Update JeffChestSortOrganizer.java

comments
This commit is contained in:
JEFF 2019-04-29 01:26:07 +02:00 committed by GitHub
parent 93b7882bbf
commit 7b6b024d4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -13,6 +13,9 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
public class JeffChestSortOrganizer { public class JeffChestSortOrganizer {
// This is the heart of ChestSort!
// All of the sorting stuff happens here.
/* /*
* DEPRECATED: THE FOLLOWING INFOS ARE OUTDATED * DEPRECATED: THE FOLLOWING INFOS ARE OUTDATED
@ -27,24 +30,26 @@ public class JeffChestSortOrganizer {
JeffChestSortPlugin plugin; JeffChestSortPlugin plugin;
// All available colors in the game. We will strip this from the item names and keep the color in a separate variable
static final String[] colors = { "white", "orange", "magenta", "light_blue", "light_gray", "yellow", "lime", "pink", "gray", static final String[] colors = { "white", "orange", "magenta", "light_blue", "light_gray", "yellow", "lime", "pink", "gray",
"cyan", "purple", "blue", "brown", "green", "red", "black" }; "cyan", "purple", "blue", "brown", "green", "red", "black" };
// 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" }; static final String[] woodNames = { "acacia", "birch", "jungle", "oak", "spruce", "dark_oak" };
// We store a list of all Category objects
ArrayList<JeffChestSortCategory> categories = new ArrayList<JeffChestSortCategory>(); ArrayList<JeffChestSortCategory> categories = new ArrayList<JeffChestSortCategory>();
JeffChestSortOrganizer(JeffChestSortPlugin plugin) { JeffChestSortOrganizer(JeffChestSortPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
// Load Categories // Load Categories
File categoriesFolder = new File(plugin.getDataFolder().getAbsolutePath() + File.separator + "categories" + File.separator); File categoriesFolder = new File(plugin.getDataFolder().getAbsolutePath() + File.separator + "categories" + File.separator);
File[] listOfCategoryFiles = categoriesFolder.listFiles(); File[] listOfCategoryFiles = categoriesFolder.listFiles();
for (File file : listOfCategoryFiles) { for (File file : listOfCategoryFiles) {
if (file.isFile()) { if (file.isFile()) {
// Category name is the filename without .txt
String categoryName = file.getName().replaceFirst(".txt", ""); String categoryName = file.getName().replaceFirst(".txt", "");
try { try {
categories.add(new JeffChestSortCategory(categoryName,getArrayFromCategoryFile(file))); categories.add(new JeffChestSortCategory(categoryName,getArrayFromCategoryFile(file)));
if(plugin.verbose) { if(plugin.verbose) {
@ -52,13 +57,14 @@ public class JeffChestSortOrganizer {
} }
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
plugin.getLogger().warning("Could not load category file: "+file.getName()); plugin.getLogger().warning("Could not load category file: "+file.getName());
//e.printStackTrace(); e.printStackTrace();
} }
} }
} }
} }
// Returns an array with all typematches listed in the category file
String[] getArrayFromCategoryFile(File file) throws FileNotFoundException { String[] getArrayFromCategoryFile(File file) throws FileNotFoundException {
Scanner sc = new Scanner(file); Scanner sc = new Scanner(file);
List<String> lines = new ArrayList<String>(); List<String> lines = new ArrayList<String>();
@ -67,28 +73,35 @@ public class JeffChestSortOrganizer {
lines.add(sc.nextLine()); lines.add(sc.nextLine());
//} //}
} }
String[] arr = lines.toArray(new String[0]); String[] arr = lines.toArray(new String[0]);
sc.close(); sc.close();
return arr; return arr;
} }
// Convert the item name to what I call a "sortable item name".
// Sorry, the method name is a bit misleading.
// The array's [0] value contains the item name with a few fixes, see below
// The array's [1] value contains the color or wood name of the item, or "<none>"
String[] getTypeAndColor(String typeName) { String[] getTypeAndColor(String typeName) {
// [0] = TypeName // [0] = Sortable Item name
// [1] = Color // [1] = Color/Wood
String myColor = "<none>"; String myColor = "<none>";
// Only work with lowercase
typeName = typeName.toLowerCase(); typeName = typeName.toLowerCase();
// When a color occurs at the beginning (e.g. "white_wool"), we omit the color so that the color will not
// determine the beginning letters of the sortable item name
for (String color : colors) { for (String color : colors) {
if (typeName.startsWith(color)) { if (typeName.startsWith(color)) {
typeName = typeName.replaceFirst(color + "_", ""); typeName = typeName.replaceFirst(color + "_", "");
myColor = color; myColor = color;
} }
} }
// Same for wood, but the wood name can also be in the middle of the item name, e.g. "stripped_oak_log"
for(String woodName : woodNames) { for(String woodName : woodNames) {
if(typeName.equals(woodName+"_wood")) { if(typeName.equals(woodName+"_wood")) {
typeName = "log_wood"; typeName = "log_wood";
@ -108,8 +121,8 @@ public class JeffChestSortOrganizer {
} }
} }
// Egg has to be put in front to group spawn eggs // "egg" has to be put in front to group spawn eggs
// E.g. cow_spawn_egg -> egg_cow_spawn // e.g. cow_spawn_egg -> egg_cow_spawn
if(typeName.endsWith("_egg")) { if(typeName.endsWith("_egg")) {
typeName = typeName.replaceFirst("_egg", ""); typeName = typeName.replaceFirst("_egg", "");
typeName = "egg_" + typeName; typeName = "egg_" + typeName;
@ -121,16 +134,18 @@ public class JeffChestSortOrganizer {
typeName = typeName + "_polished"; typeName = typeName + "_polished";
} }
// Group wet and dry sponges
if(typeName.equalsIgnoreCase("wet_sponge")) { if(typeName.equalsIgnoreCase("wet_sponge")) {
typeName = "sponge_wet"; typeName = "sponge_wet";
} }
// Group pumpkins and jack-o-lanterns / carved pumpkins
if(typeName.equalsIgnoreCase("carved_pumpkin")) { if(typeName.equalsIgnoreCase("carved_pumpkin")) {
typeName = "pumpkin_carved"; typeName = "pumpkin_carved";
} }
// Sort armor: helmet, chestplate, leggings, boots // Sort armor: helmet, chestplate, leggings, boots
// We add a number to keep the armor in the "right" order
if(typeName.endsWith("helmet")) { if(typeName.endsWith("helmet")) {
typeName = typeName.replaceFirst("helmet", "1_helmet"); typeName = typeName.replaceFirst("helmet", "1_helmet");
} else if(typeName.endsWith("chestplate")) { } else if(typeName.endsWith("chestplate")) {
@ -154,24 +169,24 @@ public class JeffChestSortOrganizer {
return typeAndColor; return typeAndColor;
} }
// This method takes a sortable item name and checks all categories for a match
// If none, matches, return "<none>" (it will be put behind all categorized items when sorting by category)
String getCategory(String typeName) { String getCategory(String typeName) {
typeName = typeName.toLowerCase(); typeName = typeName.toLowerCase();
for (JeffChestSortCategory cat : categories) { for (JeffChestSortCategory cat : categories) {
if (cat.matches(typeName)) { if (cat.matches(typeName)) {
return cat.name; return cat.name;
} }
} }
return "<none>"; return "<none>";
} }
// 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) { String getSortableString(ItemStack item) {
char blocksFirst; char blocksFirst;
char itemsFirst; char itemsFirst;
if (item.getType().isBlock()) { if (item.getType().isBlock()) {
blocksFirst = '!'; blocksFirst = '!'; // ! is before # in ASCII
itemsFirst = '#'; itemsFirst = '#';
} else { } else {
blocksFirst = '#'; blocksFirst = '#';
@ -183,8 +198,11 @@ public class JeffChestSortOrganizer {
String color = typeAndColor[1]; String color = typeAndColor[1];
String category = getCategory(item.getType().name()); String category = getCategory(item.getType().name());
// The hashcode actually not needed anymore, but I kept it for debugging purposes
String hashCode = String.valueOf(getBetterHash(item)); 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("\\{itemsFirst\\}", String.valueOf(itemsFirst));
sortableString = sortableString.replaceAll("\\{blocksFirst\\}", String.valueOf(blocksFirst)); sortableString = sortableString.replaceAll("\\{blocksFirst\\}", String.valueOf(blocksFirst));
sortableString = sortableString.replaceAll("\\{name\\}", typeName); sortableString = sortableString.replaceAll("\\{name\\}", typeName);
@ -196,10 +214,12 @@ public class JeffChestSortOrganizer {
} }
// Sort a complete inventory
void sortInventory(Inventory inv) { void sortInventory(Inventory inv) {
sortInventory(inv,0,inv.getSize()-1); sortInventory(inv,0,inv.getSize()-1);
} }
// Sort an inventory only between startSlot and endSlot
void sortInventory(Inventory inv,int startSlot, int endSlot) { void sortInventory(Inventory inv,int startSlot, int endSlot) {
// This has been optimized as of ChestSort 3.2. // This has been optimized as of ChestSort 3.2.
@ -214,20 +234,21 @@ public class JeffChestSortOrganizer {
// We copy the complete inventory into an array // We copy the complete inventory into an array
ItemStack[] items = inv.getContents(); ItemStack[] items = inv.getContents();
// Get rid of all stuff before startSlot and after endSlot // Get rid of all stuff before startSlot...
for(int i = 0; i<startSlot;i++) { for(int i = 0; i<startSlot;i++) {
items[i] = null; items[i] = null;
} }
// ... and after endSlot
for(int i=endSlot+1;i<inv.getSize();i++) { for(int i=endSlot+1;i<inv.getSize();i++) {
items[i] = null; items[i] = null;
} }
// Remove the stuff that we took from the original inventory // Remove the stuff from the original inventory
for(int i = startSlot; i<=endSlot;i++) { for(int i = startSlot; i<=endSlot;i++) {
inv.clear(i); inv.clear(i);
} }
// We don't want to have stacks of null // We don't want to have stacks of null, so we create a new ArrayList and put in everything != null
ArrayList<ItemStack> nonNullItemsList = new ArrayList<ItemStack>(); ArrayList<ItemStack> nonNullItemsList = new ArrayList<ItemStack>();
for(ItemStack item : items) { for(ItemStack item : items) {
if(item!=null) { if(item!=null) {
@ -235,38 +256,54 @@ public class JeffChestSortOrganizer {
} }
} }
// We don't need the copied inventory anymore // We no longer need the original array that includes all the null-stacks
items=null; items=null;
// We need the list as array // We need the new list as array. So why did'nt we take an array from the beginning?
// Because I did not bother to count the number of non-null items beforehand.
// TODO: Feel free to make a Pull request if you want to save your server a few nanoseconds :)
ItemStack[] nonNullItems = nonNullItemsList.toArray(new ItemStack[nonNullItemsList.size()]); ItemStack[] nonNullItems = nonNullItemsList.toArray(new ItemStack[nonNullItemsList.size()]);
// Sort the array with ItemStacks according to our sortable String // Sort the array with ItemStacks according to each ItemStacks' sortable String
Arrays.sort(nonNullItems,new Comparator<ItemStack>(){ Arrays.sort(nonNullItems,new Comparator<ItemStack>(){
public int compare(ItemStack s1,ItemStack s2){ public int compare(ItemStack s1,ItemStack s2){
return(getSortableString(s1).compareTo(getSortableString(s2))); return(getSortableString(s1).compareTo(getSortableString(s2)));
}}); }});
// put everything back in a temporary inventory to combine ItemStacks even when using strict slot sorting // Now, we put everything back in a temporary inventory to combine ItemStacks even when using strict slot sorting
// Thanks to SnackMix for this idea! // Thanks to SnackMix for this idea!
// Without doing this, it would not be possible to sort an inventory with a startSlot other than 0,
// because Spigot's add(ItemStack...) method will always to store the ItemStack in the first possible slot
// Create the temporary inventory with a null holder. 54 slots is enough for every inventory
Inventory tempInventory = Bukkit.createInventory(null, 54); //cannot be bigger than 54 as of 1.14 Inventory tempInventory = Bukkit.createInventory(null, 54); //cannot be bigger than 54 as of 1.14
for(ItemStack item : nonNullItems) { for(ItemStack item : nonNullItems) {
if(plugin.debug) System.out.println(getSortableString(item)); if(plugin.debug) System.out.println(getSortableString(item));
// Add the item to the temporary inventory
tempInventory.addItem(item); tempInventory.addItem(item);
} }
// Now, we iterate through all slots between startSlot and endSlot in the original inventory
// and set those to whatever the temporary inventory contains
// Since we already deleted all those slots, there is no chance for item duplication
int currentSlot = startSlot; int currentSlot = startSlot;
for(ItemStack item : tempInventory.getContents()) { for(ItemStack item : tempInventory.getContents()) {
if(item==null) continue; // Ignore null ItemStacks. TODO: Actually, we could skip the for-loop here because
// our temporary inventory was already sorted. Feel free to make a pull request to
// save your server half a nanosecond :)
if(item==null) continue;
inv.setItem(currentSlot, item); inv.setItem(currentSlot, item);
currentSlot++; currentSlot++;
} }
} }
// 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) { private static int getBetterHash(ItemStack item) {
// I wanted to fix the skull problems here. Instead, I ended up not using the hashCode at all. // I used to add some metadata here, but it has been removed since a long time
// I still left this here because it is nice to see the hashcodes when debug is enabled // as I said: feel free to remove this completely
return item.hashCode(); return item.hashCode();
} }