diff --git a/pom.xml b/pom.xml index 0687f68..fe126c8 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ de.jeffclan JeffChestSort - 4.2 + 4.3.1-dev jar JeffChestSort diff --git a/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortCategory.java b/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortCategory.java index 1fcdf3e..e6fc810 100644 --- a/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortCategory.java +++ b/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortCategory.java @@ -1,5 +1,7 @@ package de.jeffclan.JeffChestSort; +import de.jeffclan.utils.TypeMatchPositionPair; + public class JeffChestSortCategory { // Represents a sorting category @@ -11,21 +13,22 @@ public class JeffChestSortCategory { // "COARSE_DIRT" will match the typeMatch "*dirt" String name; - String[] typeMatches; + TypeMatchPositionPair[] typeMatches; - JeffChestSortCategory(String name, String[] typeMatches) { + JeffChestSortCategory(String name, TypeMatchPositionPair[] typeMatchPositionPairs) { this.name = name; - this.typeMatches = typeMatches; + this.typeMatches = typeMatchPositionPairs; } - // Checks whether a the given itemname fits into this category - boolean matches(String itemname) { + // Checks whether a the given itemname fits into this category and returns the line number. 0 means not found + short matches(String itemname) { boolean asteriskBefore = false; boolean asteriskAfter = false; // Very, very simple wildcard checks - for (String typeMatch : typeMatches) { + for (TypeMatchPositionPair typeMatchPositionPair : typeMatches) { + String typeMatch = typeMatchPositionPair.getTypeMatch(); if (typeMatch.startsWith("*")) { asteriskBefore = true; typeMatch = typeMatch.substring(1); @@ -37,24 +40,24 @@ public class JeffChestSortCategory { if (asteriskBefore == false && asteriskAfter == false) { if (itemname.equalsIgnoreCase(typeMatch)) { - return true; + return typeMatchPositionPair.getPosition(); } } else if (asteriskBefore == true && asteriskAfter == true) { if (itemname.contains(typeMatch)) { - return true; + return typeMatchPositionPair.getPosition(); } } else if (asteriskBefore == true && asteriskAfter == false) { if (itemname.endsWith(typeMatch)) { - return true; + return typeMatchPositionPair.getPosition(); } } else { if (itemname.startsWith(typeMatch)) { - return true; + return typeMatchPositionPair.getPosition(); } } } - return false; + return 0; } } diff --git a/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortOrganizer.java b/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortOrganizer.java index 12082e0..4a01c48 100644 --- a/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortOrganizer.java +++ b/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortOrganizer.java @@ -2,6 +2,7 @@ package de.jeffclan.JeffChestSort; import java.io.File; import java.io.FileNotFoundException; +import java.io.FilenameFilter; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -12,6 +13,9 @@ import org.bukkit.Bukkit; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import de.jeffclan.utils.CategoryLinePair; +import de.jeffclan.utils.TypeMatchPositionPair; + public class JeffChestSortOrganizer { // This is the heart of ChestSort! @@ -34,6 +38,8 @@ public class JeffChestSortOrganizer { // The same applies for wood. We strip the wood name from the item name and keep it in the above mentioned color variable static final String[] woodNames = { "acacia", "birch", "jungle", "oak", "spruce", "dark_oak" }; + private static final String emptyPlaceholderString= "~"; + // We store a list of all Category objects ArrayList categories = new ArrayList(); @@ -42,13 +48,24 @@ public class JeffChestSortOrganizer { // Load Categories File categoriesFolder = new File(plugin.getDataFolder().getAbsolutePath() + File.separator + "categories" + File.separator); - File[] listOfCategoryFiles = categoriesFolder.listFiles(); + File[] listOfCategoryFiles = categoriesFolder.listFiles(new FilenameFilter() { + public boolean accept(File directory, String fileName) { + if (!fileName.endsWith(".txt")) { + return false; + } + if (fileName.matches("(?i)^\\d\\d\\d.*\\.txt$")) // Category between 900 and 999-... are default categories + { + return true; + } + return false; + } + }); for (File file : listOfCategoryFiles) { if (file.isFile()) { // Category name is the filename without .txt String categoryName = file.getName().replaceFirst(".txt", ""); try { - categories.add(new JeffChestSortCategory(categoryName,getArrayFromCategoryFile(file))); + categories.add(new JeffChestSortCategory(categoryName,loadCategoryFile(file))); if(plugin.verbose) { plugin.getLogger().info("Loaded category file "+file.getName()); } @@ -62,17 +79,17 @@ public class JeffChestSortOrganizer { } // Returns an array with all typematches listed in the category file - String[] getArrayFromCategoryFile(File file) throws FileNotFoundException { + TypeMatchPositionPair[] loadCategoryFile(File file) throws FileNotFoundException { Scanner sc = new Scanner(file); - List lines = new ArrayList(); + List lines = new ArrayList(); + short currentLine=1; while (sc.hasNextLine()) { - //if(!sc.nextLine().startsWith("#")) { - lines.add(sc.nextLine()); - //} + lines.add(new TypeMatchPositionPair(sc.nextLine(),currentLine)); + currentLine++; } - String[] arr = lines.toArray(new String[0]); + TypeMatchPositionPair[] result = lines.toArray(new TypeMatchPositionPair[0]); sc.close(); - return arr; + return result; } @@ -85,7 +102,7 @@ public class JeffChestSortOrganizer { // [0] = Sortable Item name // [1] = Color/Wood - String myColor = ""; + String myColor = (plugin.debug) ? "~color~" : emptyPlaceholderString; // Only work with lowercase typeName = typeName.toLowerCase(); @@ -168,16 +185,18 @@ public class JeffChestSortOrganizer { // This method takes a sortable item name and checks all categories for a match // If none, matches, return "" (it will be put behind all categorized items when sorting by category) - String getCategory(String typeName) { + CategoryLinePair getCategoryLinePair(String typeName) { typeName = typeName.toLowerCase(); for (JeffChestSortCategory cat : categories) { - if (cat.matches(typeName)) { - return cat.name; + short matchingLineNumber = cat.matches(typeName); + if (matchingLineNumber!=0) { + return new CategoryLinePair(cat.name,matchingLineNumber); } } - return ""; + return new CategoryLinePair((plugin.debug) ? "~category~" : emptyPlaceholderString,(short) 0); } + // This puts together the sortable item name, the category, the color, and whether the item is a block or a "regular item" String getSortableString(ItemStack item) { char blocksFirst; @@ -193,24 +212,36 @@ public class JeffChestSortOrganizer { String[] typeAndColor = getTypeAndColor(item.getType().name()); String typeName = typeAndColor[0]; String color = typeAndColor[1]; - String category = getCategory(item.getType().name()); + String category = getCategoryLinePair(item.getType().name()).getCategoryName(); + String customName = (plugin.debug) ? "~customName~" : emptyPlaceholderString; + if(item.getItemMeta().hasDisplayName() && item.getItemMeta().getDisplayName()!=null) { + customName=item.getItemMeta().getDisplayName(); + } + String lore =(plugin.debug)? "~lore~" : emptyPlaceholderString; + if(item.getItemMeta().hasLore() && item.getItemMeta().getLore() != null && item.getItemMeta().getLore().size()!=0) { + String[] loreArray=item.getItemMeta().getLore().toArray(new String[0]); + lore = String.join(",", loreArray); + } + String lineNumber = getCategoryLinePair(item.getType().name()).getFormattedPosition(); - // The hashcode actually not needed anymore, but I kept it for debugging purposes - String hashCode = String.valueOf(getBetterHash(item)); // Generate the strings that finally are used for sorting. // They are generated according to the config.yml's sorting-method option - String sortableString = plugin.sortingMethod.replaceAll("\\{itemsFirst\\}", String.valueOf(itemsFirst)); + String sortableString = plugin.sortingMethod.replaceAll(",", "|"); + sortableString = sortableString.replaceAll("\\{itemsFirst\\}", String.valueOf(itemsFirst)); sortableString = sortableString.replaceAll("\\{blocksFirst\\}", String.valueOf(blocksFirst)); sortableString = sortableString.replaceAll("\\{name\\}", typeName); sortableString = sortableString.replaceAll("\\{color\\}", color); sortableString = sortableString.replaceAll("\\{category\\}", category); - sortableString = sortableString + "," + hashCode; + sortableString = sortableString.replaceAll("\\{line\\}", lineNumber); + sortableString = sortableString.replaceAll("\\{customName\\}", customName); + sortableString = sortableString.replaceAll("\\{lore\\}", lore); return sortableString; } + // Sort a complete inventory void sortInventory(Inventory inv) { sortInventory(inv,0,inv.getSize()-1); @@ -296,13 +327,5 @@ public class JeffChestSortOrganizer { } } - // I wanted to fix the skull problems here. Instead, I ended up not using the hashCode at all. - // I still left this here for nostalgic reasons. Also it is nice to see the hashcodes when debug is enabled - // TODO: feel free to remove this and all references, it is really not needed anymore. - private static int getBetterHash(ItemStack item) { - // I used to add some metadata here, but it has been removed since a long time - // as I said: feel free to remove this completely - return item.hashCode(); - } } diff --git a/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortPlugin.java b/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortPlugin.java index 3197e9a..e86a638 100644 --- a/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortPlugin.java +++ b/src/main/java/de/jeffclan/JeffChestSort/JeffChestSortPlugin.java @@ -32,6 +32,7 @@ package de.jeffclan.JeffChestSort; import java.io.File; import java.io.FileOutputStream; +import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -59,7 +60,7 @@ public class JeffChestSortPlugin extends JavaPlugin { JeffChestSortListener listener; String sortingMethod; ArrayList disabledWorlds; - int currentConfigVersion = 9; + int currentConfigVersion = 10; boolean usingMatchingConfig = true; boolean debug = false; boolean verbose = true; @@ -198,6 +199,8 @@ public class JeffChestSortPlugin extends JavaPlugin { // the default values for unset options createConfig(); + debug = getConfig().getBoolean("debug"); + // Save default sorting category files when enabled in the config (default=true) saveDefaultCategories(); @@ -261,12 +264,11 @@ public class JeffChestSortPlugin extends JavaPlugin { } registerMetrics(); - } private void registerMetrics() { - // Metrics will need json-simple with 1.14 API. + // Metrics will need json-simple with 1.14 API. Metrics metrics = new Metrics(this); metrics.addCustomChart(new Metrics.SimplePie("sorting_method", () -> sortingMethod)); metrics.addCustomChart(new Metrics.SimplePie("config_version", @@ -284,6 +286,8 @@ public class JeffChestSortPlugin extends JavaPlugin { metrics.addCustomChart( new Metrics.SimplePie("using_matching_config_version", () -> Boolean.toString(usingMatchingConfig))); metrics.addCustomChart(new Metrics.SimplePie("sort_time", () -> getConfig().getString("sort-time"))); + metrics.addCustomChart(new Metrics.SimplePie("auto_generate_category_files", + () -> Boolean.toString(getConfig().getBoolean("auto-generate-category-files")))); } // Saves default category files, when enabled in the config @@ -296,7 +300,39 @@ public class JeffChestSortPlugin extends JavaPlugin { // Isn't there a smarter way to find all the 9** files in the .jar? String[] defaultCategories = { "900-tools", "910-valuables", "920-combat", "930-brewing", "940-food", - "950-redstone", "960-wood", "970-stone", "980-plants", "981-corals" }; + "950-redstone", "960-wood", "970-stone", "980-plants", "981-corals","_ReadMe - Category files" }; + + // Delete all files starting with 9.. + for (File file : new File(getDataFolder().getAbsolutePath() + File.separator + "categories" + File.separator) + .listFiles(new FilenameFilter() { + public boolean accept(File directory, String fileName) { + if (!fileName.endsWith(".txt")) { + return false; + } + if (fileName.matches("(?i)9\\d\\d.*\\.txt$")) // Category between 900 and 999-... are default + // categories + { + return true; + } + return false; + } + })) { + + boolean delete = true; + + for (String name : defaultCategories) { + name=name+".txt"; + if (name.equalsIgnoreCase(file.getName())) { + delete = false; + break; + } + } + if (delete) { + file.delete(); + getLogger().warning("Deleting deprecated default category file " + file.getName()); + } + + } for (String category : defaultCategories) { diff --git a/src/main/java/de/jeffclan/utils/CategoryLinePair.java b/src/main/java/de/jeffclan/utils/CategoryLinePair.java new file mode 100644 index 0000000..3c3c62f --- /dev/null +++ b/src/main/java/de/jeffclan/utils/CategoryLinePair.java @@ -0,0 +1,26 @@ +package de.jeffclan.utils; + + +public class CategoryLinePair { + String categoryName; + String formattedPosition; + short position; + + public CategoryLinePair(String categoryName,short position) { + this.categoryName=categoryName; + this.formattedPosition=Utils.shortToStringWithLeadingZeroes(position); + this.position=position; + } + + public String getCategoryName() { + return categoryName; + } + + public String getFormattedPosition() { + return formattedPosition; + } + + public int getPosition() { + return position; + } +} diff --git a/src/main/java/de/jeffclan/utils/TypeMatchPositionPair.java b/src/main/java/de/jeffclan/utils/TypeMatchPositionPair.java new file mode 100644 index 0000000..afc9feb --- /dev/null +++ b/src/main/java/de/jeffclan/utils/TypeMatchPositionPair.java @@ -0,0 +1,27 @@ +package de.jeffclan.utils; + +public class TypeMatchPositionPair { + + String typeMatch; + String formattedPosition; + public String getTypeMatch() { + return typeMatch; + } + + public short getPosition() { + return position; + } + + public String getFormattedPosition() { + return formattedPosition; + } + + short position; + + public TypeMatchPositionPair(String typeMatch,short position) { + this.typeMatch=typeMatch; + this.position=position; + this.formattedPosition=Utils.shortToStringWithLeadingZeroes(position); + } + +} diff --git a/src/main/java/de/jeffclan/utils/Utils.java b/src/main/java/de/jeffclan/utils/Utils.java index dfdf98f..ec9b17e 100644 --- a/src/main/java/de/jeffclan/utils/Utils.java +++ b/src/main/java/de/jeffclan/utils/Utils.java @@ -28,4 +28,8 @@ public class Utils { } return buf; } + + public static String shortToStringWithLeadingZeroes(short number) { + return String.format("%05d", number); + } } diff --git a/src/main/resources/categories/900-tools.default.txt b/src/main/resources/categories/900-tools.default.txt index 316334d..b04511f 100644 --- a/src/main/resources/categories/900-tools.default.txt +++ b/src/main/resources/categories/900-tools.default.txt @@ -1,3 +1,11 @@ +# +# ChestSort Default Category File +# +# If you want to change this file, rename it. +# Please do NOT use file prefixed between 900 and 999 for +# your custom files because ChestSort will overwrite them +# + *_pickaxe *_shovel *_hoe diff --git a/src/main/resources/categories/910-valuables.default.txt b/src/main/resources/categories/910-valuables.default.txt index d8f3d52..bc69ebc 100644 --- a/src/main/resources/categories/910-valuables.default.txt +++ b/src/main/resources/categories/910-valuables.default.txt @@ -1,3 +1,11 @@ +# +# ChestSort Default Category File +# +# If you want to change this file, rename it. +# Please do NOT use file prefixed between 900 and 999 for +# your custom files because ChestSort will overwrite them +# + diamond emerald diamond_ore diff --git a/src/main/resources/categories/920-combat.default.txt b/src/main/resources/categories/920-combat.default.txt index ac853ca..59d2894 100644 --- a/src/main/resources/categories/920-combat.default.txt +++ b/src/main/resources/categories/920-combat.default.txt @@ -1,3 +1,11 @@ +# +# ChestSort Default Category File +# +# If you want to change this file, rename it. +# Please do NOT use file prefixed between 900 and 999 for +# your custom files because ChestSort will overwrite them +# + turtle_helmet bow arrow diff --git a/src/main/resources/categories/930-brewing.default.txt b/src/main/resources/categories/930-brewing.default.txt index 9b7370c..5285ad6 100644 --- a/src/main/resources/categories/930-brewing.default.txt +++ b/src/main/resources/categories/930-brewing.default.txt @@ -1,3 +1,11 @@ +# +# ChestSort Default Category File +# +# If you want to change this file, rename it. +# Please do NOT use file prefixed between 900 and 999 for +# your custom files because ChestSort will overwrite them +# + ghast_tear potion glass_bottle diff --git a/src/main/resources/categories/940-food.default.txt b/src/main/resources/categories/940-food.default.txt index eccfedb..f4632fb 100644 --- a/src/main/resources/categories/940-food.default.txt +++ b/src/main/resources/categories/940-food.default.txt @@ -1,3 +1,11 @@ +# +# ChestSort Default Category File +# +# If you want to change this file, rename it. +# Please do NOT use file prefixed between 900 and 999 for +# your custom files because ChestSort will overwrite them +# + apple baked_potato beef diff --git a/src/main/resources/categories/950-redstone.default.txt b/src/main/resources/categories/950-redstone.default.txt index ff37152..3820f5a 100644 --- a/src/main/resources/categories/950-redstone.default.txt +++ b/src/main/resources/categories/950-redstone.default.txt @@ -1,3 +1,11 @@ +# +# ChestSort Default Category File +# +# If you want to change this file, rename it. +# Please do NOT use file prefixed between 900 and 999 for +# your custom files because ChestSort will overwrite them +# + dispenser note_block sticky_piston diff --git a/src/main/resources/categories/960-wood.default.txt b/src/main/resources/categories/960-wood.default.txt index bb078da..5d8f0f8 100644 --- a/src/main/resources/categories/960-wood.default.txt +++ b/src/main/resources/categories/960-wood.default.txt @@ -1,3 +1,11 @@ +# +# ChestSort Default Category File +# +# If you want to change this file, rename it. +# Please do NOT use file prefixed between 900 and 999 for +# your custom files because ChestSort will overwrite them +# + *_planks *_sapling *_log diff --git a/src/main/resources/categories/970-stone.default.txt b/src/main/resources/categories/970-stone.default.txt index cdfd40b..9d170a2 100644 --- a/src/main/resources/categories/970-stone.default.txt +++ b/src/main/resources/categories/970-stone.default.txt @@ -1,3 +1,11 @@ +# +# ChestSort Default Category File +# +# If you want to change this file, rename it. +# Please do NOT use file prefixed between 900 and 999 for +# your custom files because ChestSort will overwrite them +# + stone cobblestone granite diff --git a/src/main/resources/categories/980-plants.default.txt b/src/main/resources/categories/980-plants.default.txt index b93a03a..cd4db7f 100644 --- a/src/main/resources/categories/980-plants.default.txt +++ b/src/main/resources/categories/980-plants.default.txt @@ -1,3 +1,11 @@ +# +# ChestSort Default Category File +# +# If you want to change this file, rename it. +# Please do NOT use file prefixed between 900 and 999 for +# your custom files because ChestSort will overwrite them +# + grass fern dead_bush diff --git a/src/main/resources/categories/981-corals.default.txt b/src/main/resources/categories/981-corals.default.txt index ad31817..34b1ef4 100644 --- a/src/main/resources/categories/981-corals.default.txt +++ b/src/main/resources/categories/981-corals.default.txt @@ -1 +1,9 @@ +# +# ChestSort Default Category File +# +# If you want to change this file, rename it. +# Please do NOT use file prefixed between 900 and 999 for +# your custom files because ChestSort will overwrite them +# + *_coral* \ No newline at end of file diff --git a/src/main/resources/categories/_ReadMe - Category files.default.txt b/src/main/resources/categories/_ReadMe - Category files.default.txt new file mode 100644 index 0000000..3448dc5 --- /dev/null +++ b/src/main/resources/categories/_ReadMe - Category files.default.txt @@ -0,0 +1,23 @@ +############# +# ChestSort # +############# + +You can define custom category files for ChestSort using simple .txt files. + +If you have {category} in your sorting-method, it will get replaced with the category name. + +Category names are determined by the file names. The name must start with a number ranging +from 000 to 899 and end with .txt + +Default categories are prefixed with 900 to 999. Please do not edit the default categories. +You can instead copy or rename the default files and edit those instead. +WARNING: All files with names starting between 900 and 999 will be deleted on start. + +If you put {keepCategoryOrder} behind {category} in the sorting-method, the items will be +ordered exactly as listed in the category files. Otherwise, they will be grouped by category +and then sorted according to the remaining variables in your sorting-method. + +Category files can contain asterisks (*) as wildcard character at the beginning and/or end +of an expression, but not in the middle. + +Category files can also contain comments using the hashtag (#) symbol \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 348662f..3f5c9db 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -39,6 +39,8 @@ show-message-again-after-logout: true # If you wish to edit those, you can disable the generation of these # files, because otherwise all your changes in the pregenerated # files will be overwritten on each server startup. +# However, a much smarter option is to copy the default files +# and rename them to from 900... to 800... and edit those instead. auto-generate-category-files: true # you can choose when ChestSort should sort chests. @@ -90,11 +92,14 @@ disabled-worlds: # Only change this if you know what you are doing. # # Available variables: -# {category} order stuff by category as defined in plugins/ChestSort/categories/.txt -# {itemsFirst} put items before blocks -# {blocksFirst} put blocks before items -# {name} returns the name (e.g. DIRT, GRASS_BLOCK, BIRCH_LOG, DIAMOND_SWORD, ...) -# {color} returns the color, e.g. light_blue for wool. Empty if block/item is not dyeable +# {category} order stuff by category as defined in plugins/ChestSort/categories/.txt +# {keepCategoryOrder} orders stuff in the same category according to their line numbers in the category file +# {itemsFirst} put items before blocks +# {blocksFirst} put blocks before items +# {name} returns the name (e.g. DIRT, GRASS_BLOCK, BIRCH_LOG, DIAMOND_SWORD, ...) +# {color} returns the color, e.g. light_blue for wool. Empty if block/item is not dyeable +# {customName} returns the display name if set (e.g. with an anvil) +# {lore} returns the lore if set # # Warning: You must not use spaces and fields have to be separated by commas. # @@ -111,6 +116,9 @@ disabled-worlds: # sort by category, then put items before blocks and sort by name and color # '{category},{itemsFirst},{name},{color}' # +# sort by category, but keep exactly the same order as defined in each category file, then sort any undefined items by name and color +# '{category},{keepCategoryOrder},{name},{color} +# sorting-method: '{category},{itemsFirst},{name},{color}' ######################### @@ -228,4 +236,4 @@ message-error-invalid-options: "&cError: Unknown option %s. Valid options are %s ######################### # please do not change the following line manually! -config-version: 9 +config-version: 10 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 41af7ae..f920fee 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ main: de.jeffclan.JeffChestSort.JeffChestSortPlugin name: ChestSort -version: 4.2 +version: 4.3.1-dev api-version: 1.13 description: Allows automatic chest sorting author: mfnalex