diff --git a/CHANGELOG.md b/CHANGELOG.md index 6105ac3b9..fb86cf163 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ * Crafting Organic Food/Fertilizer yields more output now * Organic Food (Melon) now uses Melon Slices instead of Melon blocks * The Seismic Axe now skips the first two blocks to clear your field of view +* Auto Disenchanting is now a tiny bit faster * Small performance improvements #### Fixes diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java index f965f83f8..2c5e7b33a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java @@ -252,14 +252,14 @@ public final class PlayerProfile { * The profile can then be removed from RAM. */ public void markForDeletion() { - this.markedForDeletion = true; + markedForDeletion = true; } /** * Call this method if this Profile has unsaved changes. */ public void markDirty() { - this.dirty = true; + dirty = true; } public PlayerBackpack createBackpack(int size) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java index 1ab1dd1d3..2fedc0ff0 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java @@ -1,5 +1,6 @@ package io.github.thebusybiscuit.slimefun4.core.networks.cargo; +import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; @@ -236,25 +237,7 @@ public class CargoNet extends ChestTerminalNetwork { List outputs = outputNodes.get(frequency); if (outputs != null) { - List outputList = new LinkedList<>(outputs); - Config cfg = BlockStorage.getLocationInfo(inputNode); - boolean roundrobin = "true".equals(cfg.getString("round-robin")); - - if (roundrobin) { - roundRobinSort(inputNode, outputList); - } - - for (Location output : outputList) { - Optional target = getAttachedBlock(output.getBlock()); - - if (target.isPresent()) { - stack = CargoUtils.insert(output.getBlock(), target.get(), stack); - - if (stack == null) { - break; - } - } - } + stack = distributeItem(stack, inputNode, outputs); } DirtyChestMenu menu = CargoUtils.getChestMenu(inputTarget); @@ -272,14 +255,49 @@ public class CargoNet extends ChestTerminalNetwork { } } - private void roundRobinSort(Location input, List outputs) { - int index = roundRobin.getOrDefault(input, 0); + private ItemStack distributeItem(ItemStack stack, Location inputNode, List outputNodes) { + ItemStack item = stack; - if (index < outputs.size()) { + Deque destinations = new LinkedList<>(outputNodes); + Config cfg = BlockStorage.getLocationInfo(inputNode); + boolean roundrobin = "true".equals(cfg.getString("round-robin")); + + if (roundrobin) { + roundRobinSort(inputNode, destinations); + } + + for (Location output : destinations) { + Optional target = getAttachedBlock(output.getBlock()); + + if (target.isPresent()) { + item = CargoUtils.insert(output.getBlock(), target.get(), item); + + if (item == null) { + break; + } + } + } + + return item; + } + + /** + * This method sorts a given {@link Deque} of output node locations using a semi-accurate + * round-robin method. + * + * @param inputNode + * The {@link Location} of the input node + * @param outputNodes + * A {@link Deque} of {@link Location Locations} of the output nodes + */ + private void roundRobinSort(Location inputNode, Deque outputNodes) { + int index = roundRobin.getOrDefault(inputNode, 0); + + if (index < outputNodes.size()) { // Not ideal but actually not bad performance-wise over more elegant alternatives for (int i = 0; i < index; i++) { - Location temp = outputs.remove(0); - outputs.add(temp); + Location temp = outputNodes.removeFirst(); + outputNodes.add(temp); } index++; @@ -288,16 +306,26 @@ public class CargoNet extends ChestTerminalNetwork { index = 1; } - roundRobin.put(input, index); + roundRobin.put(inputNode, index); } - private static int getFrequency(Location l) { + /** + * This method returns the frequency a given node is set to. + * Should there be an {@link Exception} to this method it will fall back to zero in + * order to protect the integrity of the {@link CargoNet}. + * + * @param node + * The {@link Location} of our cargo node + * + * @return The frequency of the given node + */ + private static int getFrequency(Location node) { try { - String str = BlockStorage.getLocationInfo(l).getString("frequency"); + String str = BlockStorage.getLocationInfo(node).getString("frequency"); return Integer.parseInt(str); } catch (Exception x) { - Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Error occurred while parsing a Cargo Node Frequency (" + l.getWorld().getName() + " - " + l.getBlockX() + "," + l.getBlockY() + "," + +l.getBlockZ() + ")"); + Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Error occurred while parsing a Cargo Node Frequency (" + node.getWorld().getName() + " - " + node.getBlockX() + "," + node.getBlockY() + "," + +node.getBlockZ() + ")"); return 0; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PerWorldSettingsService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PerWorldSettingsService.java index 6b149b3ea..bae567485 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PerWorldSettingsService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PerWorldSettingsService.java @@ -229,24 +229,7 @@ public class PerWorldSettingsService { config.setDefaultValue("enabled", true); if (config.getBoolean("enabled")) { - for (SlimefunItem item : SlimefunPlugin.getRegistry().getEnabledSlimefunItems()) { - if (item != null && item.getID() != null) { - String addon = item.getAddon().getName().toLowerCase(Locale.ROOT); - config.setDefaultValue(addon + ".enabled", true); - config.setDefaultValue(addon + '.' + item.getID(), true); - - boolean isAddonDisabled = config.getBoolean(addon + ".enabled"); - - if (isAddonDisabled) { - Set blacklist = disabledAddons.computeIfAbsent(plugin, key -> new HashSet<>()); - blacklist.add(name); - } - - if (!isAddonDisabled || !config.getBoolean(addon + '.' + item.getID())) { - items.add(item.getID()); - } - } - } + loadItemsFromWorldConfig(name, config, items); if (SlimefunPlugin.getMinecraftVersion() != MinecraftVersion.UNIT_TEST) { config.save(); @@ -260,6 +243,27 @@ public class PerWorldSettingsService { } } + private void loadItemsFromWorldConfig(String worldName, Config config, Set items) { + for (SlimefunItem item : SlimefunPlugin.getRegistry().getEnabledSlimefunItems()) { + if (item != null && item.getID() != null) { + String addon = item.getAddon().getName().toLowerCase(Locale.ROOT); + config.setDefaultValue(addon + ".enabled", true); + config.setDefaultValue(addon + '.' + item.getID(), true); + + boolean isAddonDisabled = config.getBoolean(addon + ".enabled"); + + if (isAddonDisabled) { + Set blacklist = disabledAddons.computeIfAbsent(plugin, key -> new HashSet<>()); + blacklist.add(worldName); + } + + if (!isAddonDisabled || !config.getBoolean(addon + '.' + item.getID())) { + items.add(item.getID()); + } + } + } + } + private Config getConfig(World world) { return new Config(plugin, "world-settings/" + world.getName() + ".yml"); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java index c925f1962..1684b0a12 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java @@ -37,10 +37,13 @@ public class PermissionsService { public void register(Iterable items, boolean save) { for (SlimefunItem item : items) { - if (item != null && item.getID() != null && !migrate(item)) { - config.setDefaultValue(item.getID() + ".permission", "none"); + if (item != null && item.getID() != null) { + String path = item.getID() + ".permission"; + + config.setDefaultValue(path, "none"); config.setDefaultValue(item.getID() + ".lore", new String[] { "&rYou do not have the permission", "&rto access this item." }); - permissions.put(item.getID(), config.getString(item.getID() + ".permission")); + + permissions.put(item.getID(), config.getString(path)); } } @@ -49,23 +52,6 @@ public class PermissionsService { } } - // Temporary migration method for the old system - private boolean migrate(SlimefunItem item) { - String permission = SlimefunPlugin.getItemCfg().getString(item.getID() + ".required-permission"); - - if (permission != null) { - config.setDefaultValue(item.getID() + ".permission", permission.length() == 0 ? "none" : permission); - config.setDefaultValue(item.getID() + ".lore", SlimefunPlugin.getItemCfg().getString(item.getID() + ".no-permission-tooltip")); - permissions.put(item.getID(), config.getString(item.getID() + ".permission")); - - SlimefunPlugin.getItemCfg().setValue(item.getID() + ".required-permission", null); - SlimefunPlugin.getItemCfg().setValue(item.getID() + ".no-permission-tooltip", null); - return true; - } - - return false; - } - /** * This method checks whether the given {@link Permissible} has the {@link Permission} * to access the given {@link SlimefunItem}. diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Composter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Composter.java index 15fb95ec1..096d69b52 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Composter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Composter.java @@ -18,6 +18,7 @@ import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils; import io.github.thebusybiscuit.cscorelib2.materials.MaterialCollections; import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; +import io.github.thebusybiscuit.cscorelib2.scheduling.TaskQueue; import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import me.mrCookieSlime.Slimefun.SlimefunPlugin; @@ -26,7 +27,6 @@ import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem; import me.mrCookieSlime.Slimefun.Objects.handlers.BlockUseHandler; import me.mrCookieSlime.Slimefun.api.BlockStorage; -import me.mrCookieSlime.Slimefun.api.Slimefun; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; public class Composter extends SimpleSlimefunItem implements RecipeDisplayItem { @@ -86,19 +86,19 @@ public class Composter extends SimpleSlimefunItem implements Re ItemStack output = getOutput(p, input); if (output != null) { - for (int j = 1; j < 12; j++) { - int index = j; + TaskQueue tasks = new TaskQueue(); - Slimefun.runSync(() -> { - if (index < 11) { - b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, input.getType().isBlock() ? input.getType() : Material.HAY_BLOCK); - } - else { - p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F); - pushItem(b, output.clone()); - } - }, j * 30L); - } + tasks.thenRepeatEvery(30, 10, () -> { + Material material = input.getType().isBlock() ? input.getType() : Material.HAY_BLOCK; + b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, material); + }); + + tasks.thenRun(20, () -> { + p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F); + pushItem(b, output.clone()); + }); + + tasks.execute(SlimefunPlugin.instance); } else { SlimefunPlugin.getLocal().sendMessage(p, "machines.wrong-item", true); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoAnvil.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoAnvil.java index e0a6ba3d4..8f2d8c1b1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoAnvil.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoAnvil.java @@ -81,14 +81,10 @@ public abstract class AutoAnvil extends AContainer { if (item != null && item.getType().getMaxDurability() > 0 && ((Damageable) item.getItemMeta()).getDamage() > 0) { if (SlimefunUtils.isItemSimilar(target, SlimefunItems.DUCT_TAPE, true)) { - ItemStack newItem = item.clone(); - short durability = (short) (((Damageable) newItem.getItemMeta()).getDamage() - (item.getType().getMaxDurability() / getRepairFactor())); - if (durability < 0) durability = 0; - ItemMeta meta = newItem.getItemMeta(); - ((Damageable) meta).setDamage(durability); - newItem.setItemMeta(meta); - recipe = new MachineRecipe(30, new ItemStack[] { target, item }, new ItemStack[] { newItem }); + ItemStack repaired = repair(item); + recipe = new MachineRecipe(30, new ItemStack[] { target, item }, new ItemStack[] { repaired }); } + break; } } @@ -106,4 +102,20 @@ public abstract class AutoAnvil extends AContainer { } } + private ItemStack repair(ItemStack item) { + ItemStack repaired = item.clone(); + ItemMeta meta = repaired.getItemMeta(); + + short maxDurability = item.getType().getMaxDurability(); + short durability = (short) (((Damageable) meta).getDamage() - (maxDurability / getRepairFactor())); + + if (durability < 0) { + durability = 0; + } + + ((Damageable) meta).setDamage(durability); + repaired.setItemMeta(meta); + return repaired; + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java index 1722a9721..4333f0f30 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java @@ -31,6 +31,18 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.energy.ChargableBlock; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; +/** + * The {@link AutoDisenchanter}, in contrast to the {@link AutoEnchanter}, removes + * {@link Enchantment Enchantments} from a given {@link ItemStack} and transfers them + * to a book. + * + * @author TheBusyBiscuit + * @author Walshy + * @author poma123 + * + * @see AutoEnchanter + * + */ public class AutoDisenchanter extends AContainer { public AutoDisenchanter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { @@ -74,7 +86,7 @@ public class AutoDisenchanter extends AContainer { else progress.put(b, timeleft - 1); } else { - menu.replaceExistingItem(22, new CustomItem(new ItemStack(Material.BLACK_STAINED_GLASS_PANE), " ")); + menu.replaceExistingItem(22, new CustomItem(Material.BLACK_STAINED_GLASS_PANE, " ")); for (ItemStack item : processing.get(b).getOutput()) { menu.pushItem(item, getOutputSlots()); @@ -92,19 +104,13 @@ public class AutoDisenchanter extends AContainer { for (int slot : getInputSlots()) { ItemStack item = menu.getItemInSlot(slot); - // Check if disenchantable - SlimefunItem sfItem = null; - - // stops endless checks of getByItem for empty book stacks. - if ((item != null) && (item.getType() != Material.BOOK)) { - sfItem = SlimefunItem.getByItem(item); - } - if (sfItem != null && !sfItem.isDisenchantable()) { + if (!isDisenchantable(item)) { return; } AutoDisenchantEvent event = new AutoDisenchantEvent(item); Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { return; } @@ -128,34 +134,18 @@ public class AutoDisenchanter extends AContainer { } if (amount > 0) { - ItemStack newItem = item.clone(); - newItem.setAmount(1); - ItemStack book = target.clone(); - book.setAmount(1); - book.setType(Material.ENCHANTED_BOOK); + ItemStack disenchantedItem = item.clone(); + disenchantedItem.setAmount(1); - ItemMeta itemMeta = newItem.getItemMeta(); - ItemMeta bookMeta = book.getItemMeta(); - ((Repairable) bookMeta).setRepairCost(((Repairable) itemMeta).getRepairCost()); - ((Repairable) itemMeta).setRepairCost(0); - newItem.setItemMeta(itemMeta); - book.setItemMeta(bookMeta); - - EnchantmentStorageMeta meta = (EnchantmentStorageMeta) book.getItemMeta(); - - for (Map.Entry entry : enchantments.entrySet()) { - newItem.removeEnchantment(entry.getKey()); - meta.addStoredEnchant(entry.getKey(), entry.getValue(), true); - } - - book.setItemMeta(meta); + ItemStack book = new ItemStack(Material.ENCHANTED_BOOK); + transferEnchantments(disenchantedItem, book, enchantments); for (ItemEnchantment ench : emeraldEnchantments) { EmeraldEnchants.getInstance().getRegistry().applyEnchantment(book, ench.getEnchantment(), ench.getLevel()); - EmeraldEnchants.getInstance().getRegistry().applyEnchantment(newItem, ench.getEnchantment(), 0); + EmeraldEnchants.getInstance().getRegistry().applyEnchantment(disenchantedItem, ench.getEnchantment(), 0); } - recipe = new MachineRecipe(100 * amount, new ItemStack[] { target, item }, new ItemStack[] { newItem, book }); + recipe = new MachineRecipe(90 * amount, new ItemStack[] { target, item }, new ItemStack[] { disenchantedItem, book }); break; } } @@ -176,6 +166,35 @@ public class AutoDisenchanter extends AContainer { } } + private void transferEnchantments(ItemStack item, ItemStack book, Map enchantments) { + ItemMeta itemMeta = item.getItemMeta(); + ItemMeta bookMeta = book.getItemMeta(); + ((Repairable) bookMeta).setRepairCost(((Repairable) itemMeta).getRepairCost()); + ((Repairable) itemMeta).setRepairCost(0); + item.setItemMeta(itemMeta); + book.setItemMeta(bookMeta); + + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) book.getItemMeta(); + + for (Map.Entry entry : enchantments.entrySet()) { + item.removeEnchantment(entry.getKey()); + meta.addStoredEnchant(entry.getKey(), entry.getValue(), true); + } + + book.setItemMeta(meta); + } + + private boolean isDisenchantable(ItemStack item) { + SlimefunItem sfItem = null; + + // stops endless checks of getByItem for empty book stacks. + if (item != null && item.getType() != Material.BOOK) { + sfItem = SlimefunItem.getByItem(item); + } + + return sfItem == null || sfItem.isDisenchantable(); + } + @Override public int getSpeed() { return 1;