diff --git a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoCrafting.java b/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoCrafting.java index 7ebde49..273f683 100644 --- a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoCrafting.java +++ b/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoCrafting.java @@ -42,17 +42,14 @@ public class ModuleAutoCrafting extends Module { @Override public void run(Hopper hopper, StorageContainerCache.Cache hopperCache) { final ItemStack toCraft; - if (hopper == null - || (toCraft = getAutoCrafting(hopper)) == null - || cachedRecipes.get(toCraft) == null - /*|| !canMove(hopperInventory, toCraft)*/) + if (hopper == null || (toCraft = getAutoCrafting(hopper)) == null || toCraft.getType() == Material.AIR) return; top: - for (List recipe : cachedRecipes.get(toCraft).getRecipes()) { + for (SimpleRecipe recipe : getRecipes(toCraft).recipes) { // Do we have enough to craft this recipe? - for(ItemStack item : recipe) { + for(ItemStack item : recipe.recipe) { int amountHave = 0; for (ItemStack hopperItem : hopperCache.cachedInventory) { if (hopperItem != null && Methods.isSimilar(hopperItem, item)) @@ -66,24 +63,12 @@ public class ModuleAutoCrafting extends Module { // If we've gotten this far, then we have items to craft! // first: can we push this crafted item down the line? - if (!hopperCache.addItem(toCraft)) + if (!hopperCache.addItem(recipe.result)) return; // We're good! Remove the items used to craft! - for(ItemStack item : recipe) { - int amountToRemove = item.getAmount(); - for (int i = 0; amountToRemove > 0 && i < hopperCache.cachedInventory.length; i++) { - final ItemStack hopperItem = hopperCache.cachedInventory[i]; - if(hopperItem != null && Methods.isSimilar(hopperItem, item)) { - if(amountToRemove >= hopperItem.getAmount()) { - amountToRemove -= hopperItem.getAmount(); - hopperCache.removeItem(i); - } else { - hopperItem.setAmount(hopperItem.getAmount() - amountToRemove); - break; - } - } - } + for(ItemStack item : recipe.recipe) { + hopperCache.removeItems(item); } } } @@ -114,14 +99,7 @@ public class ModuleAutoCrafting extends Module { public List getBlockedItems(Hopper hopper) { ItemStack itemStack = getAutoCrafting(hopper); if (itemStack != null && itemStack.getType() != Material.AIR) { - - Recipes recipes = cachedRecipes.get(itemStack); - if (recipes == null) { - recipes = new Recipes(Bukkit.getServer().getRecipesFor(itemStack)); - cachedRecipes.put(itemStack, recipes); - } - - return recipes.getAllMaterials(); + return getRecipes(itemStack).getAllMaterials(); } return Collections.EMPTY_LIST; } @@ -138,6 +116,32 @@ public class ModuleAutoCrafting extends Module { cachedCrafting.remove(hopper); } + Recipes getRecipes(ItemStack toCraft) { + Recipes recipes = cachedRecipes.get(toCraft); + if (recipes == null) { + recipes = new Recipes(Bukkit.getServer().getRecipesFor(toCraft)); + + // adding broken recipe for wood planks + final String toType = toCraft.getType().name(); + if (toType.endsWith("_PLANKS")) { + boolean fromLog = false; + for (SimpleRecipe recipe : recipes.recipes) { + if (recipe.recipe.length == 1 && recipe.recipe[0].getType().name().endsWith("_LOG")) { + fromLog = true; + break; + } + } + if (!fromLog) { + Material log = Material.getMaterial(toType.substring(0, toType.length() - 6) + "LOG"); + if(log != null) recipes.addRecipe(Collections.singletonList(new ItemStack(log)), new ItemStack(toCraft.getType(), 4)); + } + } + + cachedRecipes.put(toCraft, recipes); + } + return recipes; + } + public ItemStack getAutoCrafting(Hopper hopper) { if (cachedCrafting.containsKey(hopper)) return cachedCrafting.get(hopper); @@ -173,10 +177,10 @@ public class ModuleAutoCrafting extends Module { 1, Short.parseShort(autoCraftingParts.length == 2 ? autoCraftingParts[1] : "0")); } - final class Recipes { + final static class Recipes { // we don't actually care about the shape, just the materials used - private final List> recipes = new ArrayList<>(); + private final List recipes = new ArrayList<>(); private final List allTypes = new ArrayList<>(); public Recipes() { @@ -186,7 +190,7 @@ public class ModuleAutoCrafting extends Module { addRecipes(recipes); } - public List> getRecipes() { + public List getRecipes() { return Collections.unmodifiableList(recipes); } @@ -201,6 +205,10 @@ public class ModuleAutoCrafting extends Module { } else { ingredientMap = new ArrayList<>(((ShapedRecipe) recipe).getIngredientMap().values()); } + addRecipe(ingredientMap, recipe.getResult()); + } + + public void addRecipe(Collection ingredientMap, ItemStack result) { // consense the recipe into a list of materials and how many of each Map mergedRecipe = new HashMap<>(); ingredientMap.stream() @@ -213,7 +221,7 @@ public class ModuleAutoCrafting extends Module { mergedItem.setAmount(mergedItem.getAmount() + 1); } }); - this.recipes.add(new ArrayList<>(mergedRecipe.values())); + this.recipes.add(new SimpleRecipe(mergedRecipe.values(), result)); // Also keep a tally of what materials are possible for this craftable mergedRecipe.keySet().stream() .filter(itemType -> itemType != null && !allTypes.contains(itemType)) @@ -234,4 +242,14 @@ public class ModuleAutoCrafting extends Module { recipes.clear(); } } + + final static class SimpleRecipe { + final ItemStack result; + final ItemStack[] recipe; + + public SimpleRecipe(Collection recipe, ItemStack result) { + this.result = result; + this.recipe = recipe.toArray(new ItemStack[0]); + } + } } diff --git a/src/main/java/com/songoda/epichoppers/tasks/HopTask.java b/src/main/java/com/songoda/epichoppers/tasks/HopTask.java index cb26969..851dd33 100644 --- a/src/main/java/com/songoda/epichoppers/tasks/HopTask.java +++ b/src/main/java/com/songoda/epichoppers/tasks/HopTask.java @@ -102,18 +102,17 @@ public class HopTask extends BukkitRunnable { List blockedMaterials = new ArrayList<>(); // Cycle through modules. - for (Module module : hopper.getLevel().getRegisteredModules()) { + hopper.getLevel().getRegisteredModules().stream() + .filter(module -> module != null) + .forEach(module -> { + // Run Module + module.run(hopper, hopperCache); - // Run Module - module.run(hopper, hopperCache); - - // Add banned materials to list. - List materials = module.getBlockedItems(hopper); - if (materials == null || materials.isEmpty()) - continue; - - blockedMaterials.addAll(materials); - } + // Add banned materials to list. + List materials = module.getBlockedItems(hopper); + if (materials != null && !materials.isEmpty()) + blockedMaterials.addAll(materials); + }); // Process extra hopper pull pullItemsFromContainers(hopper, hopperCache, maxToMove); @@ -124,12 +123,12 @@ public class HopTask extends BukkitRunnable { // don't proccess any further if the hopper is empty or if all items are blocked boolean doProcess = false; for (int i = 0; i < hopperCache.cachedInventory.length; i++) { - // Don't try to move items that we've added this round - if (hopperCache.cacheChanged[i]) - continue; - final ItemStack item = hopperCache.cachedInventory[i]; + // Don't try to move items that we've added this round + if (hopperCache.cacheChanged[i] && item.getAmount() - hopperCache.cacheAdded[i] < maxToMove) + continue; + // Skip if slot empty, blocked, or voidlisted if (item == null || item.getAmount() == 0 || blockedMaterials.contains(item.getType()) @@ -398,15 +397,15 @@ public class HopTask extends BukkitRunnable { // Loop through all of our hopper's item slots. for (int i = 0; i < 5; i++) { - // Don't try to move items that we've added this round - if (hopperCache.cacheChanged[i]) - continue; - // Get potential item to move. ItemStack item = hopperCache.cachedInventory[i]; - // Skip if slot empty, blocked, or voidlisted - if (item == null + // Can we check this item? + if ( // Ignore this one if the slot is empty + item == null + // Don't try to move items that we've added this round + || (hopperCache.cacheChanged[i] && item.getAmount() - hopperCache.cacheAdded[i] < maxToMove) + // skip if blocked or voidlisted || blockedMaterials.contains(item.getType()) || hopper.getFilter().getVoidList().stream().anyMatch(itemStack -> Methods.isSimilar(itemStack, item))) continue; diff --git a/src/main/java/com/songoda/epichoppers/utils/StorageContainerCache.java b/src/main/java/com/songoda/epichoppers/utils/StorageContainerCache.java index 3bb04be..a85103e 100644 --- a/src/main/java/com/songoda/epichoppers/utils/StorageContainerCache.java +++ b/src/main/java/com/songoda/epichoppers/utils/StorageContainerCache.java @@ -55,6 +55,7 @@ public class StorageContainerCache { public final Block block; public ItemStack[] cachedInventory; public boolean[] cacheChanged; + public int[] cacheAdded; public boolean dirty; public Cache(Material type, ItemStack[] cachedInventory) { @@ -68,6 +69,7 @@ public class StorageContainerCache { this.type = b.getType(); this.cachedInventory = cachedInventory; this.cacheChanged = new boolean[cachedInventory.length]; + this.cacheAdded = new int[cachedInventory.length]; } public void setDirty(boolean dirty) { @@ -139,7 +141,7 @@ public class StorageContainerCache { if (type.name().contains("SHULKER_BOX") && item.getType().name().contains("SHULKER_BOX")) return 0; - int added = 0; + int totalAdded = 0; if (cachedInventory != null && item != null) { final int maxStack = item.getMaxStackSize(); for (int i = 0; amountToAdd > 0 && i < cachedInventory.length; i++) { @@ -150,28 +152,24 @@ public class StorageContainerCache { cachedInventory[i] = item.clone(); cachedInventory[i].setAmount(toAdd); cacheChanged[i] = true; - added += toAdd; + cacheAdded[i] = toAdd; + totalAdded += toAdd; amountToAdd -= toAdd; } else if (maxStack > cacheItem.getAmount() && Methods.isSimilar(item, cacheItem)) { // free space! int toAdd = Math.min(maxStack - cacheItem.getAmount(), amountToAdd); - added += toAdd; - if (toAdd == amountToAdd) { - cachedInventory[i].setAmount(toAdd + cacheItem.getAmount()); - cacheChanged[i] = true; - break; - } else { - cachedInventory[i].setAmount(maxStack); - cacheChanged[i] = true; - amountToAdd -= toAdd; - } + cachedInventory[i].setAmount(toAdd + cacheItem.getAmount()); + cacheChanged[i] = true; + cacheAdded[i] += toAdd; + totalAdded += toAdd; + amountToAdd -= toAdd; } } - if (added != 0) { + if (totalAdded != 0) { dirty = true; } } - return added; + return totalAdded; } /** @@ -264,20 +262,16 @@ public class StorageContainerCache { cachedInventory[i] = item.clone(); cachedInventory[i].setAmount(adding); cacheChanged[i] = true; + cacheAdded[i] = adding; toAdd -= adding; } else if (maxStack > cacheItem.getAmount()) { // free space! // (no need to check item.isSimilar(cacheItem), since we have that cached in check[]) int adding = Math.min(maxStack - cacheItem.getAmount(), toAdd); - if (adding == toAdd) { - cachedInventory[i].setAmount(adding + cacheItem.getAmount()); - cacheChanged[i] = true; - break; - } else { - cachedInventory[i].setAmount(maxStack); - cacheChanged[i] = true; - toAdd -= adding; - } + cachedInventory[i].setAmount(adding + cacheItem.getAmount()); + cacheChanged[i] = true; + cacheAdded[i] += adding; + toAdd -= adding; } } dirty = true;