From 8e07ada3211920f4f628b956dd1c0454fc05ed0a Mon Sep 17 00:00:00 2001 From: TheBusyBiscuit Date: Sun, 21 Jun 2020 10:26:54 +0200 Subject: [PATCH] Reduced technical debt / Refactoring --- CHANGELOG.md | 1 + .../slimefun4/api/geo/ResourceManager.java | 5 +- .../implementation/SlimefunItems.java | 19 +- .../listeners/AncientAltarListener.java | 137 +++++---- .../listeners/BlockListener.java | 51 ++-- .../listeners/DebugFishListener.java | 11 +- .../listeners/ExplosionsListener.java | 3 +- .../listeners/GrapplingHookListener.java | 4 +- .../listeners/MobDropListener.java | 31 +- .../listeners/SlimefunBowListener.java | 29 +- .../listeners/TalismanListener.java | 38 ++- .../implementation/tasks/TickerTask.java | 281 ++++++++---------- .../slimefun4/utils/NumberUtils.java | 27 +- .../Slimefun/SlimefunPlugin.java | 14 +- .../Slimefun/api/BlockStorage.java | 87 ++++-- 15 files changed, 430 insertions(+), 308 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43c4c83a6..d21fde737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ #### Changes * Coolant Cells now last twice as long +* Ticking blocks will now catch more errors caused by addons * Massive performance improvements #### Fixes diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/geo/ResourceManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/geo/ResourceManager.java index 289130f18..ec67c3af5 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/geo/ResourceManager.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/geo/ResourceManager.java @@ -18,6 +18,7 @@ import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.config.Config; import io.github.thebusybiscuit.cscorelib2.item.CustomItem; +import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.api.events.GEOResourceGenerationEvent; import io.github.thebusybiscuit.slimefun4.implementation.items.geo.GEOMiner; import io.github.thebusybiscuit.slimefun4.implementation.items.geo.GEOScanner; @@ -71,7 +72,9 @@ public class ResourceManager { SlimefunPlugin.getRegistry().getGEOResources().add(resource); } - config.save(); + if (SlimefunPlugin.getMinecraftVersion() != MinecraftVersion.UNIT_TEST) { + config.save(); + } } public OptionalInt getSupplies(GEOResource resource, World world, int x, int z) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java index a159d7e68..a298bded8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java @@ -64,15 +64,16 @@ public final class SlimefunItems { public static final SlimefunItemStack FILLED_FLASK_OF_KNOWLEDGE = new SlimefunItemStack("FILLED_FLASK_OF_KNOWLEDGE", Material.EXPERIENCE_BOTTLE, "&aFlask of Knowledge"); /* Backpacks */ - public static final SlimefunItemStack BACKPACK_SMALL = new SlimefunItemStack("SMALL_BACKPACK", HeadTexture.BACKPACK, "&eSmall Backpack", "", "&7Size: &e9", "&7ID: ", "", LoreBuilder.RIGHT_CLICK_TO_OPEN); - public static final SlimefunItemStack BACKPACK_MEDIUM = new SlimefunItemStack("MEDIUM_BACKPACK", HeadTexture.BACKPACK, "&eBackpack", "", "&7Size: &e18", "&7ID: ", "", LoreBuilder.RIGHT_CLICK_TO_OPEN); - public static final SlimefunItemStack BACKPACK_LARGE = new SlimefunItemStack("LARGE_BACKPACK", HeadTexture.BACKPACK, "&eLarge Backpack", "", "&7Size: &e27", "&7ID: ", "", LoreBuilder.RIGHT_CLICK_TO_OPEN); - public static final SlimefunItemStack WOVEN_BACKPACK = new SlimefunItemStack("WOVEN_BACKPACK", HeadTexture.BACKPACK, "&eWoven Backpack", "", "&7Size: &e36", "&7ID: ", "", LoreBuilder.RIGHT_CLICK_TO_OPEN); - public static final SlimefunItemStack GILDED_BACKPACK = new SlimefunItemStack("GILDED_BACKPACK", HeadTexture.BACKPACK, "&eGilded Backpack", "", "&7Size: &e45", "&7ID: ", "", LoreBuilder.RIGHT_CLICK_TO_OPEN); - public static final SlimefunItemStack RADIANT_BACKPACK = new SlimefunItemStack("RADIANT_BACKPACK", HeadTexture.BACKPACK, "&eRadiant Backpack", "", "&7Size: &e54 (Double chest)", "&7ID: ", "", LoreBuilder.RIGHT_CLICK_TO_OPEN); - public static final SlimefunItemStack BOUND_BACKPACK = new SlimefunItemStack("BOUND_BACKPACK", HeadTexture.ENDER_BACKPACK, "&cSoulbound Backpack", "", "&7Size: &e36", "&7ID: ", "", LoreBuilder.RIGHT_CLICK_TO_OPEN); - public static final SlimefunItemStack COOLER = new SlimefunItemStack("COOLER", HeadTexture.COOLER, "&bCooler", "&rAllows you to store Juices/Smoothies", "&rand automatically consumes them when you are hungry", "&rand you have this in your Inventory", "", "&7Size: &e27", "&7ID: ", "", LoreBuilder.RIGHT_CLICK_TO_OPEN); - public static final SlimefunItemStack RESTORED_BACKPACK = new SlimefunItemStack("RESTORED_BACKPACK", HeadTexture.RESTORED_BACKPACK, "&eRestored Backpack", "", "&7Retrieve your lost items", "&7ID: ", "", LoreBuilder.RIGHT_CLICK_TO_OPEN); + private static final String BACKPACK_ID = "&7ID: "; + public static final SlimefunItemStack BACKPACK_SMALL = new SlimefunItemStack("SMALL_BACKPACK", HeadTexture.BACKPACK, "&eSmall Backpack", "", "&7Size: &e9", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN); + public static final SlimefunItemStack BACKPACK_MEDIUM = new SlimefunItemStack("MEDIUM_BACKPACK", HeadTexture.BACKPACK, "&eBackpack", "", "&7Size: &e18", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN); + public static final SlimefunItemStack BACKPACK_LARGE = new SlimefunItemStack("LARGE_BACKPACK", HeadTexture.BACKPACK, "&eLarge Backpack", "", "&7Size: &e27", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN); + public static final SlimefunItemStack WOVEN_BACKPACK = new SlimefunItemStack("WOVEN_BACKPACK", HeadTexture.BACKPACK, "&eWoven Backpack", "", "&7Size: &e36", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN); + public static final SlimefunItemStack GILDED_BACKPACK = new SlimefunItemStack("GILDED_BACKPACK", HeadTexture.BACKPACK, "&eGilded Backpack", "", "&7Size: &e45", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN); + public static final SlimefunItemStack RADIANT_BACKPACK = new SlimefunItemStack("RADIANT_BACKPACK", HeadTexture.BACKPACK, "&eRadiant Backpack", "", "&7Size: &e54 (Double chest)", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN); + public static final SlimefunItemStack BOUND_BACKPACK = new SlimefunItemStack("BOUND_BACKPACK", HeadTexture.ENDER_BACKPACK, "&cSoulbound Backpack", "", "&7Size: &e36", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN); + public static final SlimefunItemStack COOLER = new SlimefunItemStack("COOLER", HeadTexture.COOLER, "&bCooler", "&rAllows you to store Juices/Smoothies", "&rand automatically consumes them when you are hungry", "&rand you have this in your Inventory", "", "&7Size: &e27", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN); + public static final SlimefunItemStack RESTORED_BACKPACK = new SlimefunItemStack("RESTORED_BACKPACK", HeadTexture.RESTORED_BACKPACK, "&eRestored Backpack", "", "&7Retrieve your lost items", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN); /* Jetpacks */ public static final SlimefunItemStack DURALUMIN_JETPACK = new SlimefunItemStack("DURALUMIN_JETPACK", Material.LEATHER_CHESTPLATE, Color.SILVER, "&9Electric Jetpack &7- &eI", "", LoreBuilder.material("Duralumin"), LoreBuilder.powerCharged(0, 20), "&8\u21E8 &7Thrust: &c0.35", "", LoreBuilder.CROUCH_TO_USE); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java index 06a5f1f6d..8feb73a5a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java @@ -156,64 +156,21 @@ public class AncientAltarListener implements Listener { } } - private void useAltar(Block b, Player p) { + private void useAltar(Block altar, Player p) { ItemStack catalyst = new CustomItem(p.getInventory().getItemInMainHand(), 1); - List pedestals = getPedestals(b); + List pedestals = getPedestals(altar); - if (!altars.contains(b)) { - altars.add(b); + if (!altars.contains(altar)) { + altars.add(altar); if (pedestals.size() == 8) { pedestals.forEach(block -> altarsInUse.add(block.getLocation())); if (catalyst.getType() != Material.AIR) { - List input = new ArrayList<>(); - for (Block pedestal : pedestals) { - Item stack = findItem(pedestal); - - if (stack != null) { - input.add(fixItemStack(stack.getItemStack(), stack.getCustomName())); - } - } - - Optional result = getRecipeOutput(catalyst, input); - if (result.isPresent()) { - if (Slimefun.hasUnlocked(p, result.get(), true)) { - List consumed = new ArrayList<>(); - consumed.add(catalyst); - - if (p.getGameMode() != GameMode.CREATIVE) { - ItemUtils.consumeItem(p.getInventory().getItemInMainHand(), false); - } - - b.getWorld().playSound(b.getLocation(), Sound.ENTITY_ILLUSIONER_PREPARE_MIRROR, 1, 1); - Slimefun.runSync(new AncientAltarTask(b, altar.getSpeed(), result.get(), pedestals, consumed, p), 10L); - } - else { - altars.remove(b); - - for (Block block : pedestals) { - altarsInUse.remove(block.getLocation()); - } - - // Item not unlocked, no longer in use. - altarsInUse.remove(b.getLocation()); - } - } - else { - altars.remove(b); - SlimefunPlugin.getLocal().sendMessage(p, "machines.ANCIENT_ALTAR.unknown-recipe", true); - - for (Block block : pedestals) { - altarsInUse.remove(block.getLocation()); - } - - // Bad recipe, no longer in use. - altarsInUse.remove(b.getLocation()); - } + startRitual(p, altar, pedestals, catalyst); } else { - altars.remove(b); + altars.remove(altar); SlimefunPlugin.getLocal().sendMessage(p, "machines.ANCIENT_ALTAR.unknown-catalyst", true); for (Block block : pedestals) { @@ -221,17 +178,65 @@ public class AncientAltarListener implements Listener { } // Unknown catalyst, no longer in use - altarsInUse.remove(b.getLocation()); + altarsInUse.remove(altar.getLocation()); } } else { - altars.remove(b); + altars.remove(altar); SlimefunPlugin.getLocal().sendMessage(p, "machines.ANCIENT_ALTAR.not-enough-pedestals", true, msg -> msg.replace("%pedestals%", String.valueOf(pedestals.size()))); // Not a valid altar so remove from inuse + altarsInUse.remove(altar.getLocation()); + } + } + } + + private void startRitual(Player p, Block b, List pedestals, ItemStack catalyst) { + List input = new ArrayList<>(); + + for (Block pedestal : pedestals) { + Item stack = findItem(pedestal); + + if (stack != null) { + input.add(fixItemStack(stack.getItemStack(), stack.getCustomName())); + } + } + + Optional result = getRecipeOutput(catalyst, input); + if (result.isPresent()) { + if (Slimefun.hasUnlocked(p, result.get(), true)) { + List consumed = new ArrayList<>(); + consumed.add(catalyst); + + if (p.getGameMode() != GameMode.CREATIVE) { + ItemUtils.consumeItem(p.getInventory().getItemInMainHand(), false); + } + + b.getWorld().playSound(b.getLocation(), Sound.ENTITY_ILLUSIONER_PREPARE_MIRROR, 1, 1); + Slimefun.runSync(new AncientAltarTask(b, altar.getSpeed(), result.get(), pedestals, consumed, p), 10L); + } + else { + altars.remove(b); + + for (Block block : pedestals) { + altarsInUse.remove(block.getLocation()); + } + + // Item not unlocked, no longer in use. altarsInUse.remove(b.getLocation()); } } + else { + altars.remove(b); + SlimefunPlugin.getLocal().sendMessage(p, "machines.ANCIENT_ALTAR.unknown-recipe", true); + + for (Block block : pedestals) { + altarsInUse.remove(block.getLocation()); + } + + // Bad recipe, no longer in use. + altarsInUse.remove(b.getLocation()); + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -353,16 +358,26 @@ public class AncientAltarListener implements Listener { private Optional checkRecipe(ItemStack catalyst, List items) { for (AltarRecipe recipe : altarRecipes) { if (SlimefunUtils.isItemSimilar(catalyst, recipe.getCatalyst(), true)) { - for (int i = 0; i < 8; i++) { - if (SlimefunUtils.isItemSimilar(items.get(i), recipe.getInput().get(0), true)) { - for (int j = 1; j < 8; j++) { - if (!SlimefunUtils.isItemSimilar(items.get((i + j) % items.size()), recipe.getInput().get(j), true)) { - break; - } - else if (j == 7) { - return Optional.of(recipe.getOutput()); - } - } + Optional optional = checkPedestals(items, recipe); + + if (optional.isPresent()) { + return optional; + } + } + } + + return Optional.empty(); + } + + private Optional checkPedestals(List items, AltarRecipe recipe) { + for (int i = 0; i < 8; i++) { + if (SlimefunUtils.isItemSimilar(items.get(i), recipe.getInput().get(0), true)) { + for (int j = 1; j < 8; j++) { + if (!SlimefunUtils.isItemSimilar(items.get((i + j) % items.size()), recipe.getInput().get(j), true)) { + break; + } + else if (j == 7) { + return Optional.of(recipe.getOutput()); } } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java index 05f7d6dd0..1ef53575a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java @@ -13,6 +13,7 @@ import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -88,25 +89,9 @@ public class BlockListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockUnregister(BlockBreakEvent e) { - Block blockAbove = e.getBlock().getRelative(BlockFace.UP); - - if (sensitiveMaterials.contains(blockAbove.getType())) { - SlimefunItem sfItem = BlockStorage.check(blockAbove); - - if (sfItem != null && !sfItem.useVanillaBlockBreaking()) { - SlimefunBlockHandler blockHandler = SlimefunPlugin.getRegistry().getBlockHandlers().get(sfItem.getID()); - - if (blockHandler != null) { - if (blockHandler.onBreak(e.getPlayer(), blockAbove, sfItem, UnregisterReason.PLAYER_BREAK)) { - blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), BlockStorage.retrieve(blockAbove)); - blockAbove.setType(Material.AIR); - } - else { - e.setCancelled(true); - return; - } - } - } + if (hasSensitiveBlockAbove(e.getPlayer(), e.getBlock())) { + e.setCancelled(true); + return; } SlimefunItem sfItem = BlockStorage.check(e.getBlock()); @@ -147,6 +132,10 @@ public class BlockListener implements Listener { } } + dropItems(e, drops); + } + + private void dropItems(BlockBreakEvent e, List drops) { if (!drops.isEmpty()) { e.getBlock().setType(Material.AIR); @@ -160,6 +149,30 @@ public class BlockListener implements Listener { } } + private boolean hasSensitiveBlockAbove(Player p, Block b) { + Block blockAbove = b.getRelative(BlockFace.UP); + + if (sensitiveMaterials.contains(blockAbove.getType())) { + SlimefunItem sfItem = BlockStorage.check(blockAbove); + + if (sfItem != null && !sfItem.useVanillaBlockBreaking()) { + SlimefunBlockHandler blockHandler = SlimefunPlugin.getRegistry().getBlockHandlers().get(sfItem.getID()); + + if (blockHandler != null) { + if (blockHandler.onBreak(p, blockAbove, sfItem, UnregisterReason.PLAYER_BREAK)) { + blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), BlockStorage.retrieve(blockAbove)); + blockAbove.setType(Material.AIR); + } + else { + return true; + } + } + } + } + + return false; + } + private int getBonusDropsWithFortune(ItemStack item, Block b) { int fortune = 1; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/DebugFishListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/DebugFishListener.java index 832f6cce4..63f8ad91d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/DebugFishListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/DebugFishListener.java @@ -19,6 +19,7 @@ import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.tasks.TickerTask; import io.github.thebusybiscuit.slimefun4.utils.HeadTexture; +import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; @@ -103,14 +104,14 @@ public class DebugFishListener implements Listener { if (item.isTicking()) { p.sendMessage(ChatColors.color("&dTicker: " + enabledTooltip)); p.sendMessage(ChatColors.color(" &dAsync: &e" + (BlockStorage.check(b).getBlockTicker().isSynchronized() ? disabledTooltip : enabledTooltip))); - p.sendMessage(ChatColors.color(" &dTimings: &e" + ticker.toMillis(ticker.getTimings(b), true))); - p.sendMessage(ChatColors.color(" &dTotal Timings: &e" + ticker.toMillis(ticker.getTimings(BlockStorage.checkID(b)), true))); - p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + ticker.toMillis(ticker.getTimings(b.getChunk()), true))); + p.sendMessage(ChatColors.color(" &dTimings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b)))); + p.sendMessage(ChatColors.color(" &dTotal Timings: &e" + NumberUtils.getAsMillis(ticker.getTimings(BlockStorage.checkID(b))))); + p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b.getChunk())))); } else if (item.getEnergyTicker() != null) { p.sendMessage(ChatColors.color("&dTicking: " + "&3Indirect")); - p.sendMessage(ChatColors.color(" &dTimings: &e" + ticker.toMillis(ticker.getTimings(b), true))); - p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + ticker.toMillis(ticker.getTimings(b.getChunk()), true))); + p.sendMessage(ChatColors.color(" &dTimings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b)))); + p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b.getChunk())))); } else { p.sendMessage(ChatColors.color("&dTicker: " + disabledTooltip)); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java index e47de3035..d2f27e255 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java @@ -9,6 +9,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityExplodeEvent; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; @@ -33,7 +34,7 @@ public class ExplosionsListener implements Listener { blocks.remove(); // Hardened Glass and WitherProof blocks cannot be destroyed by explosions - if (!id.equalsIgnoreCase("HARDENED_GLASS") && !SlimefunPlugin.getRegistry().getWitherProofBlocks().containsKey(id)) { + if (!id.equals(SlimefunItems.HARDENED_GLASS.getItemId()) && !SlimefunPlugin.getRegistry().getWitherProofBlocks().containsKey(id)) { boolean success = true; SlimefunItem sfItem = SlimefunItem.getByID(id); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GrapplingHookListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GrapplingHookListener.java index 67ac5bb7e..5bbdc21c5 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GrapplingHookListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GrapplingHookListener.java @@ -80,7 +80,7 @@ public class GrapplingHookListener implements Listener { Player p = (Player) arrow.getShooter(); if (p.getGameMode() != GameMode.CREATIVE && (boolean) grappleState.get(p.getUniqueId())) { - arrow.getWorld().dropItem(arrow.getLocation(), SlimefunItems.GRAPPLING_HOOK); + arrow.getWorld().dropItem(arrow.getLocation(), SlimefunItems.GRAPPLING_HOOK.clone()); } Vector velocity = new Vector(0.0, 0.2, 0.0); @@ -135,7 +135,7 @@ public class GrapplingHookListener implements Listener { // To fix issue #253 Slimefun.runSync(() -> { if (grappleState.containsKey(uuid)) { - SlimefunPlugin.getBowListener().getBows().remove(uuid); + SlimefunPlugin.getBowListener().getProjectileData().remove(uuid); for (Entity n : temporaryEntities.get(uuid)) { if (n.isValid()) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MobDropListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MobDropListener.java index ec18bdb26..248713276 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MobDropListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MobDropListener.java @@ -1,5 +1,6 @@ package io.github.thebusybiscuit.slimefun4.implementation.listeners; +import java.util.List; import java.util.Set; import org.bukkit.Material; @@ -9,9 +10,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.inventory.ItemStack; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.BasicCircuitBoard; -import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.handlers.EntityKillHandler; @@ -19,8 +18,12 @@ import me.mrCookieSlime.Slimefun.api.Slimefun; public class MobDropListener implements Listener { - public MobDropListener(SlimefunPlugin plugin) { + private final BasicCircuitBoard circuitBoard; + + public MobDropListener(SlimefunPlugin plugin, BasicCircuitBoard circuitBoard) { plugin.getServer().getPluginManager().registerEvents(this, plugin); + + this.circuitBoard = circuitBoard; } @EventHandler @@ -31,15 +34,7 @@ public class MobDropListener implements Listener { Set customDrops = SlimefunPlugin.getRegistry().getMobDrops(e.getEntityType()); if (customDrops != null && !customDrops.isEmpty()) { - for (ItemStack drop : customDrops) { - if (Slimefun.hasUnlocked(p, drop, true)) { - if (SlimefunUtils.isItemSimilar(drop, SlimefunItems.BASIC_CIRCUIT_BOARD, true) && !((BasicCircuitBoard) SlimefunItems.BASIC_CIRCUIT_BOARD.getItem()).isDroppedFromGolems()) { - continue; - } - - e.getDrops().add(drop.clone()); - } - } + addDrops(p, customDrops, e.getDrops()); } if (item.getType() != Material.AIR) { @@ -51,4 +46,16 @@ public class MobDropListener implements Listener { } } } + + private void addDrops(Player p, Set customDrops, List drops) { + for (ItemStack drop : customDrops) { + if (Slimefun.hasUnlocked(p, drop, true)) { + if (circuitBoard != null && circuitBoard.isItem(drop) && !circuitBoard.isDroppedFromGolems()) { + continue; + } + + drops.add(drop.clone()); + } + } + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBowListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBowListener.java index 0c34199c2..b20e8c54f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBowListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBowListener.java @@ -19,16 +19,31 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.handlers.BowShootHandler; import me.mrCookieSlime.Slimefun.api.Slimefun; +/** + * This {@link Listener} is responsible for tracking {@link Arrow Arrows} fired from a + * {@link SlimefunBow}. + * + * @author TheBusyBiscuit + * + * @see SlimefunBow + * + */ public class SlimefunBowListener implements Listener { - private final Map bows = new HashMap<>(); + private final Map projectiles = new HashMap<>(); public void register(SlimefunPlugin plugin) { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - public Map getBows() { - return bows; + /** + * This returns a {@link HashMap} holding the {@link UUID} of a {@link Arrow} and the + * associated {@link SlimefunBow} with which this {@link Arrow} was fired from. + * + * @return A {@link HashMap} with all actively tracked {@link Arrow Arrows} + */ + public Map getProjectileData() { + return projectiles; } @EventHandler @@ -37,7 +52,7 @@ public class SlimefunBowListener implements Listener { SlimefunItem bow = SlimefunItem.getByItem(e.getBow()); if (bow instanceof SlimefunBow) { - bows.put(e.getProjectile().getUniqueId(), (SlimefunBow) bow); + projectiles.put(e.getProjectile().getUniqueId(), (SlimefunBow) bow); } } } @@ -46,7 +61,7 @@ public class SlimefunBowListener implements Listener { public void onArrowHit(ProjectileHitEvent e) { Slimefun.runSync(() -> { if (e.getEntity().isValid() && e.getEntity() instanceof Arrow) { - bows.remove(e.getEntity().getUniqueId()); + projectiles.remove(e.getEntity().getUniqueId()); } }, 4L); } @@ -54,13 +69,13 @@ public class SlimefunBowListener implements Listener { @EventHandler public void onArrowSuccessfulHit(EntityDamageByEntityEvent e) { if (e.getDamager() instanceof Arrow && e.getEntity() instanceof LivingEntity) { - SlimefunBow bow = bows.get(e.getDamager().getUniqueId()); + SlimefunBow bow = projectiles.get(e.getDamager().getUniqueId()); if (bow != null) { bow.callItemHandler(BowShootHandler.class, handler -> handler.onHit(e, (LivingEntity) e.getEntity())); } - bows.remove(e.getDamager().getUniqueId()); + projectiles.remove(e.getDamager().getUniqueId()); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java index ee6c0b06b..a238d7dd8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java @@ -10,6 +10,7 @@ import java.util.concurrent.ThreadLocalRandom; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.AbstractArrow; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.ChestedHorse; import org.bukkit.entity.LivingEntity; @@ -78,18 +79,41 @@ public class TalismanListener implements Listener { Projectile projectile = (Projectile) ((EntityDamageByEntityEvent) e).getDamager(); if (Talisman.checkFor(e, SlimefunItems.TALISMAN_WHIRLWIND)) { - Player p = (Player) e.getEntity(); - Vector direction = p.getEyeLocation().getDirection().multiply(2.0); - Location loc = p.getEyeLocation().add(direction.getX(), direction.getY(), direction.getZ()); - Projectile clone = (Projectile) e.getEntity().getWorld().spawnEntity(loc, projectile.getType()); - clone.setShooter(projectile.getShooter()); - clone.setVelocity(direction); - projectile.remove(); + returnProjectile((Player) e.getEntity(), projectile); } } } } + /** + * This method is used for the {@link Talisman} of the whirlwind, it returns a copy + * of a {@link Projectile} that was fired at a {@link Player}. + * + * @param p + * The {@link Player} who was hit + * @param projectile + * The {@link Projectile} that hit this {@link Player} + */ + private void returnProjectile(Player p, Projectile projectile) { + Vector direction = p.getEyeLocation().getDirection().multiply(2.0); + Location loc = p.getEyeLocation().add(direction.getX(), direction.getY(), direction.getZ()); + + Projectile returnedProjectile = (Projectile) p.getWorld().spawnEntity(loc, projectile.getType()); + returnedProjectile.setShooter(projectile.getShooter()); + returnedProjectile.setVelocity(direction); + + if (projectile instanceof AbstractArrow) { + AbstractArrow firedArrow = (AbstractArrow) projectile; + AbstractArrow returnedArrow = (AbstractArrow) returnedProjectile; + + returnedArrow.setDamage(firedArrow.getDamage()); + returnedArrow.setPickupStatus(firedArrow.getPickupStatus()); + returnedArrow.setPierceLevel(firedArrow.getPierceLevel()); + } + + projectile.remove(); + } + @EventHandler(ignoreCancelled = true) public void onKill(EntityDeathEvent e) { if (e.getDrops().isEmpty() || e.getEntity().getKiller() == null) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java index e72e3faad..8d6dad860 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java @@ -1,6 +1,5 @@ package io.github.thebusybiscuit.slimefun4.implementation.tasks; -import java.text.DecimalFormat; import java.util.AbstractMap; import java.util.Comparator; import java.util.HashMap; @@ -9,11 +8,14 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; import java.util.logging.Level; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -28,6 +30,7 @@ import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; import io.github.thebusybiscuit.cscorelib2.chat.json.ChatComponent; import io.github.thebusybiscuit.cscorelib2.chat.json.HoverEvent; import io.github.thebusybiscuit.slimefun4.api.ErrorReport; +import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; import io.github.thebusybiscuit.slimefun4.utils.PatternUtils; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; @@ -37,24 +40,29 @@ import me.mrCookieSlime.Slimefun.api.Slimefun; public class TickerTask implements Runnable { - private final DecimalFormat decimalFormat = new DecimalFormat("#.##"); - private final ConcurrentMap move = new ConcurrentHashMap<>(); - private final ConcurrentMap delete = new ConcurrentHashMap<>(); - private final ConcurrentMap blockTimings = new ConcurrentHashMap<>(); - private final ConcurrentMap chunkItemCount = new ConcurrentHashMap<>(); - private final ConcurrentMap machineCount = new ConcurrentHashMap<>(); - private final ConcurrentMap machineTimings = new ConcurrentHashMap<>(); - private final ConcurrentMap chunkTimings = new ConcurrentHashMap<>(); - private final ConcurrentMap buggedBlocks = new ConcurrentHashMap<>(); - private final Set chunksSkipped = new HashSet<>(); + private static final int VISIBILITY_THRESHOLD = 200_000; private final Set tickers = new HashSet<>(); + // These are "Queues" of blocks that need to be removed or moved + private final ConcurrentMap movingQueue = new ConcurrentHashMap<>(); + private final ConcurrentMap deletionQueue = new ConcurrentHashMap<>(); + + private final ConcurrentMap buggedBlocks = new ConcurrentHashMap<>(); + + private final ConcurrentMap blockTimings = new ConcurrentHashMap<>(); + private final ConcurrentMap machineCount = new ConcurrentHashMap<>(); + private final ConcurrentMap machineTimings = new ConcurrentHashMap<>(); + + private final ConcurrentMap chunkTimings = new ConcurrentHashMap<>(); + private final ConcurrentMap chunkItemCount = new ConcurrentHashMap<>(); + private final Set skippedChunks = new HashSet<>(); + private boolean halted = false; - private int skipped = 0; + private int skippedBlocks = 0; private int chunks = 0; - private int machines = 0; + private int blocks = 0; private long time = 0; private boolean running = false; @@ -65,104 +73,60 @@ public class TickerTask implements Runnable { @Override public void run() { - if (running) return; + if (running) { + return; + } running = true; long timestamp = System.nanoTime(); - skipped = 0; + skippedBlocks = 0; chunks = 0; - machines = 0; + blocks = 0; chunkItemCount.clear(); machineCount.clear(); time = 0; chunkTimings.clear(); - chunksSkipped.clear(); + skippedChunks.clear(); machineTimings.clear(); blockTimings.clear(); - Map bugged = new HashMap<>(buggedBlocks); + Map bugs = new HashMap<>(buggedBlocks); buggedBlocks.clear(); - Map remove = new HashMap<>(delete); + Map removals = new HashMap<>(deletionQueue); - for (Map.Entry entry : remove.entrySet()) { + for (Map.Entry entry : removals.entrySet()) { BlockStorage._integrated_removeBlockInfo(entry.getKey(), entry.getValue()); - delete.remove(entry.getKey()); + deletionQueue.remove(entry.getKey()); } if (!halted) { - for (String tickedChunk : BlockStorage.getTickingChunks()) { - long timestamp2 = System.nanoTime(); + for (String chunk : BlockStorage.getTickingChunks()) { + long chunkTimestamp = System.nanoTime(); chunks++; - for (Location l : BlockStorage.getTickingLocations(tickedChunk)) { + for (Location l : BlockStorage.getTickingLocations(chunk)) { if (l.getWorld().isChunkLoaded(l.getBlockX() >> 4, l.getBlockZ() >> 4)) { - Block b = l.getBlock(); - SlimefunItem item = BlockStorage.check(l); - - if (item != null && item.getBlockTicker() != null) { - machines++; - - try { - item.getBlockTicker().update(); - - if (item.getBlockTicker().isSynchronized()) { - Slimefun.runSync(() -> { - try { - long timestamp3 = System.nanoTime(); - item.getBlockTicker().tick(b, item, BlockStorage.getLocationInfo(l)); - - Long machinetime = machineTimings.get(item.getID()); - Integer chunk = chunkItemCount.get(tickedChunk); - Integer machine = machineCount.get(item.getID()); - - machineTimings.put(item.getID(), (machinetime != null ? machinetime : 0) + (System.nanoTime() - timestamp3)); - chunkItemCount.put(tickedChunk, (chunk != null ? chunk : 0) + 1); - machineCount.put(item.getID(), (machine != null ? machine : 0) + 1); - blockTimings.put(l, System.nanoTime() - timestamp3); - } - catch (Exception x) { - int errors = bugged.getOrDefault(l, 0); - reportErrors(l, item, x, errors); - } - }); - } - else { - long timestamp3 = System.nanoTime(); - item.getBlockTicker().tick(b, item, BlockStorage.getLocationInfo(l)); - - machineTimings.merge(item.getID(), (System.nanoTime() - timestamp3), Long::sum); - chunkItemCount.merge(tickedChunk, 1, Integer::sum); - machineCount.merge(item.getID(), 1, Integer::sum); - blockTimings.put(l, System.nanoTime() - timestamp3); - } - - tickers.add(item.getBlockTicker()); - } - catch (Exception x) { - int errors = bugged.getOrDefault(l, 0); - reportErrors(l, item, x, errors); - } - } - else skipped++; + tick(l, chunk, bugs); } else { - skipped += BlockStorage.getTickingLocations(tickedChunk).size(); - chunksSkipped.add(tickedChunk); + skippedBlocks += BlockStorage.getTickingLocations(chunk).size(); + skippedChunks.add(chunk); chunks--; break; } } - chunkTimings.put(tickedChunk, System.nanoTime() - timestamp2); + chunkTimings.put(chunk, System.nanoTime() - chunkTimestamp); } } - for (Map.Entry entry : move.entrySet()) { + for (Map.Entry entry : movingQueue.entrySet()) { BlockStorage._integrated_moveLocationInfo(entry.getKey(), entry.getValue()); } - move.clear(); + + movingQueue.clear(); Iterator iterator = tickers.iterator(); while (iterator.hasNext()) { @@ -174,23 +138,74 @@ public class TickerTask implements Runnable { running = false; } - private void reportErrors(Location l, SlimefunItem item, Exception x, int errors) { + private void tick(Location l, String tickedChunk, Map bugs) { + Block b = l.getBlock(); + SlimefunItem item = BlockStorage.check(l); + + if (item != null && item.getBlockTicker() != null) { + blocks++; + + try { + item.getBlockTicker().update(); + + if (item.getBlockTicker().isSynchronized()) { + Slimefun.runSync(() -> { + try { + long timestamp = System.nanoTime(); + item.getBlockTicker().tick(b, item, BlockStorage.getLocationInfo(l)); + + long machinetime = NumberUtils.getLong(machineTimings.get(item.getID()), 0); + int chunk = NumberUtils.getInt(chunkItemCount.get(tickedChunk), 0); + int machine = NumberUtils.getInt(machineCount.get(item.getID()), 0); + + machineTimings.put(item.getID(), machinetime + (System.nanoTime() - timestamp)); + chunkItemCount.put(tickedChunk, chunk + 1); + machineCount.put(item.getID(), machine + 1); + blockTimings.put(l, System.nanoTime() - timestamp); + } + catch (Exception | LinkageError x) { + int errors = bugs.getOrDefault(l, 0); + reportErrors(l, item, x, errors); + } + }); + } + else { + long timestamp = System.nanoTime(); + item.getBlockTicker().tick(b, item, BlockStorage.getLocationInfo(l)); + + machineTimings.merge(item.getID(), (System.nanoTime() - timestamp), Long::sum); + chunkItemCount.merge(tickedChunk, 1, Integer::sum); + machineCount.merge(item.getID(), 1, Integer::sum); + blockTimings.put(l, System.nanoTime() - timestamp); + } + + tickers.add(item.getBlockTicker()); + } + catch (Exception x) { + int errors = bugs.getOrDefault(l, 0); + reportErrors(l, item, x, errors); + } + } + else { + skippedBlocks++; + } + } + + private void reportErrors(Location l, SlimefunItem item, Throwable x, int errors) { errors++; if (errors == 1) { // Generate a new Error-Report new ErrorReport(x, l, item); - buggedBlocks.put(l, errors); } else if (errors == 4) { Slimefun.getLogger().log(Level.SEVERE, "X: {0} Y: {1} Z: {2} ({3})", new Object[] { l.getBlockX(), l.getBlockY(), l.getBlockZ(), item.getID() }); - Slimefun.getLogger().log(Level.SEVERE, "has thrown 4 Exceptions in the last 4 Ticks, the Block has been terminated."); + Slimefun.getLogger().log(Level.SEVERE, "has thrown 4 error messages in the last 4 Ticks, the Block has been terminated."); Slimefun.getLogger().log(Level.SEVERE, "Check your /plugins/Slimefun/error-reports/ folder for details."); Slimefun.getLogger().log(Level.SEVERE, " "); BlockStorage._integrated_removeBlockInfo(l, true); - Bukkit.getScheduler().scheduleSyncDelayedTask(SlimefunPlugin.instance, () -> l.getBlock().setType(Material.AIR)); } else { @@ -199,59 +214,41 @@ public class TickerTask implements Runnable { } public String getTime() { - return toMillis(time, false); + return NumberUtils.getAsMillis(time); } public void info(CommandSender sender) { sender.sendMessage(ChatColors.color("&2== &aSlimefun Diagnostic Tool &2==")); sender.sendMessage(ChatColors.color("&6Halted: &e&l" + String.valueOf(halted).toUpperCase(Locale.ROOT))); sender.sendMessage(""); - sender.sendMessage(ChatColors.color("&6Impact: &e" + toMillis(time, true))); + sender.sendMessage(ChatColors.color("&6Impact: &e" + NumberUtils.getAsMillis(time))); sender.sendMessage(ChatColors.color("&6Ticked Chunks: &e" + chunks)); - sender.sendMessage(ChatColors.color("&6Ticked Machines: &e" + machines)); - sender.sendMessage(ChatColors.color("&6Skipped Machines: &e" + skipped)); + sender.sendMessage(ChatColors.color("&6Ticked Machines: &e" + blocks)); + sender.sendMessage(ChatColors.color("&6Skipped Machines: &e" + skippedBlocks)); sender.sendMessage(""); sender.sendMessage(ChatColors.color("&6Ticking Machines:")); - List> timings = machineCount.keySet().stream().map(key -> new AbstractMap.SimpleEntry<>(key, machineTimings.getOrDefault(key, 0L))).sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue())).collect(Collectors.toList()); + summarizeTimings(sender, entry -> { + int count = machineCount.get(entry.getKey()); + String timings = NumberUtils.getAsMillis(entry.getValue()); + String average = NumberUtils.getAsMillis(entry.getValue() / count); - if (sender instanceof Player) { - ChatComponent component = new ChatComponent(ChatColors.color(" &7&oHover for more Info")); - StringBuilder builder = new StringBuilder(); - int hidden = 0; - - for (Map.Entry entry : timings) { - int count = machineCount.get(entry.getKey()); - - if (entry.getValue() > 300_000) { - builder.append("\n&c").append(entry.getKey()).append(" - ").append(count).append("x &7(").append(toMillis(entry.getValue(), true)).append(", ").append(toMillis(entry.getValue() / count, true)).append(" avg/machine)"); - } - else hidden++; - } - - builder.append("\n\n&c+ &4").append(hidden).append(" Hidden"); - component.setHoverEvent(new HoverEvent(ChatColors.color(builder.toString()))); - - component.sendMessage((Player) sender); - } - else { - int hidden = 0; - - for (Map.Entry entry : timings) { - int count = machineCount.get(entry.getKey()); - if (entry.getValue() > 300_000) { - sender.sendMessage(" " + entry.getKey() + " - " + count + "x (" + toMillis(entry.getValue(), false) + ", " + toMillis(entry.getValue() / count, false) + " avg/machine)"); - } - else hidden++; - } - - sender.sendMessage("+ " + hidden + " Hidden"); - } + return entry.getKey() + " - " + count + "x (" + timings + ", " + average + " avg/machine)"; + }, machineCount.keySet().stream().map(key -> new AbstractMap.SimpleEntry<>(key, machineTimings.getOrDefault(key, 0L)))); sender.sendMessage(""); sender.sendMessage(ChatColors.color("&6Ticking Chunks:")); - timings = chunkTimings.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList()); + summarizeTimings(sender, entry -> { + int count = chunkItemCount.getOrDefault(entry.getKey(), 0); + String timings = NumberUtils.getAsMillis(entry.getValue()); + + return formatChunk(entry.getKey()) + " - " + count + "x (" + timings + ")"; + }, chunkTimings.entrySet().stream().filter(entry -> !skippedChunks.contains(entry.getKey()))); + } + + private void summarizeTimings(CommandSender sender, Function, String> formatter, Stream> stream) { + List> timings = stream.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList()); if (sender instanceof Player) { ChatComponent component = new ChatComponent(ChatColors.color(" &7&oHover for more Info")); @@ -259,11 +256,11 @@ public class TickerTask implements Runnable { int hidden = 0; for (Map.Entry entry : timings) { - if (!chunksSkipped.contains(entry.getKey())) { - if (entry.getValue() > 0) { - builder.append("\n&c").append(formatChunk(entry.getKey())).append(" - ").append(chunkItemCount.getOrDefault(entry.getKey(), 0)).append("x &7(").append(toMillis(entry.getValue(), true)).append(')'); - } - else hidden++; + if (entry.getValue() > VISIBILITY_THRESHOLD) { + builder.append("\n&c").append(formatter.apply(entry)); + } + else { + hidden++; } } @@ -276,15 +273,15 @@ public class TickerTask implements Runnable { int hidden = 0; for (Map.Entry entry : timings) { - if (!chunksSkipped.contains(entry.getKey())) { - if (entry.getValue() > 0) { - sender.sendMessage(" " + formatChunk(entry.getKey()) + " - " + (chunkItemCount.getOrDefault(entry.getKey(), 0)) + "x (" + toMillis(entry.getValue(), false) + ")"); - } - else hidden++; + if (entry.getValue() > VISIBILITY_THRESHOLD) { + sender.sendMessage(" " + ChatColor.stripColor(formatter.apply(entry))); + } + else { + hidden++; } } - sender.sendMessage(ChatColors.color("&c+ &4" + hidden + " Hidden")); + sender.sendMessage("+ " + hidden + " Hidden"); } } @@ -318,35 +315,17 @@ public class TickerTask implements Runnable { halted = true; } - public String toMillis(long nanoseconds, boolean colors) { - String number = decimalFormat.format(nanoseconds / 1000000.0); - - if (!colors) { - return number; - } - else { - String[] parts = PatternUtils.NUMBER_SEPERATOR.split(number); - - if (parts.length == 1) { - return parts[0]; - } - else { - return parts[0] + ',' + ChatColor.GRAY + parts[1] + "ms"; - } - } - } - @Override public String toString() { - return "TickerTask {\n" + " HALTED = " + halted + "\n" + " tickers = " + tickers + "\n" + " move = " + move + "\n" + " delete = " + delete + "\n" + " chunks = " + chunkItemCount + "\n" + " machines = " + machineCount + "\n" + " machinetime = " + machineTimings + "\n" + " chunktime = " + chunkTimings + "\n" + " skipped = " + chunksSkipped + "\n" + "}"; + return "TickerTask {\n" + " HALTED = " + halted + "\n" + " tickers = " + tickers + "\n" + " move = " + movingQueue + "\n" + " delete = " + deletionQueue + "\n" + " chunks = " + chunkItemCount + "\n" + " machines = " + machineCount + "\n" + " machinetime = " + machineTimings + "\n" + " chunktime = " + chunkTimings + "\n" + " skipped = " + skippedChunks + "\n" + "}"; } public void queueMove(Location from, Location to) { - move.put(from, to); + movingQueue.put(from, to); } public void queueDelete(Location l, boolean destroy) { - delete.put(l, destroy); + deletionQueue.put(l, destroy); } public void start(SlimefunPlugin plugin) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java index 52bb18d1a..cd9fa88ba 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java @@ -1,5 +1,6 @@ package io.github.thebusybiscuit.slimefun4.utils; +import java.text.DecimalFormat; import java.text.NumberFormat; import java.time.Duration; import java.time.LocalDateTime; @@ -9,6 +10,8 @@ import org.bukkit.ChatColor; public final class NumberUtils { + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##"); + private NumberUtils() {} public static String formatBigNumber(int i) { @@ -57,11 +60,31 @@ public final class NumberUtils { return timeleft + seconds + "s"; } - public static int getInt(String str, int defaultVal) { + public static int getInt(String str, int defaultValue) { if (PatternUtils.NUMERIC.matcher(str).matches()) { return Integer.parseInt(str); } - return defaultVal; + return defaultValue; + } + + public static String getAsMillis(long nanoseconds) { + String number = DECIMAL_FORMAT.format(nanoseconds / 1000000.0); + String[] parts = PatternUtils.NUMBER_SEPERATOR.split(number); + + if (parts.length == 1) { + return parts[0]; + } + else { + return parts[0] + ',' + ChatColor.GRAY + parts[1] + "ms"; + } + } + + public static long getLong(Long value, long defaultValue) { + return value == null ? defaultValue : value; + } + + public static int getInt(Integer value, int defaultValue) { + return value == null ? defaultValue : value; } } diff --git a/src/main/java/me/mrCookieSlime/Slimefun/SlimefunPlugin.java b/src/main/java/me/mrCookieSlime/Slimefun/SlimefunPlugin.java index da66bcf79..f220ebcfe 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/SlimefunPlugin.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/SlimefunPlugin.java @@ -46,6 +46,7 @@ import io.github.thebusybiscuit.slimefun4.core.services.plugins.ThirdPartyPlugin import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAltar; import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.BasicCircuitBoard; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor; import io.github.thebusybiscuit.slimefun4.implementation.items.tools.GrapplingHook; import io.github.thebusybiscuit.slimefun4.implementation.items.weapons.SeismicAxe; @@ -225,7 +226,6 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { new MultiBlockListener(this); new GadgetsListener(this); new DispenserListener(this); - new MobDropListener(this); new BlockListener(this); new EnhancedFurnaceListener(this); new ItemPickupListener(this); @@ -237,6 +237,8 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { new WitherListener(this); new IronGolemListener(this); + new MobDropListener(this, (BasicCircuitBoard) SlimefunItems.BASIC_CIRCUIT_BOARD.getItem()); + // Item-specific Listeners new VampireBladeListener(this, (VampireBlade) SlimefunItems.BLADE_OF_VAMPIRES.getItem()); new CoolerListener(this, (Cooler) SlimefunItems.COOLER.getItem()); @@ -436,12 +438,18 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { for (String folder : storageFolders) { File file = new File("data-storage/Slimefun", folder); - if (!file.exists()) file.mkdirs(); + + if (!file.exists()) { + file.mkdirs(); + } } for (String folder : pluginFolders) { File file = new File("plugins/Slimefun", folder); - if (!file.exists()) file.mkdirs(); + + if (!file.exists()) { + file.mkdirs(); + } } } diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java index b22e7df6a..f9640cab7 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java @@ -75,10 +75,15 @@ public class BlockStorage { private static Location deserializeLocation(String l) { try { String[] components = PatternUtils.SEMICOLON.split(l); - if (components.length != 4) return null; + if (components.length != 4) { + return null; + } World w = Bukkit.getWorld(components[0]); - if (w != null) return new Location(w, Integer.parseInt(components[1]), Integer.parseInt(components[2]), Integer.parseInt(components[3])); + + if (w != null) { + return new Location(w, Integer.parseInt(components[1]), Integer.parseInt(components[2]), Integer.parseInt(components[3])); + } } catch (NumberFormatException x) { Slimefun.getLogger().log(Level.WARNING, "Could not parse Number", x); @@ -160,6 +165,7 @@ public class BlockStorage { Slimefun.getLogger().log(Level.WARNING, x, () -> "Failed to load " + file.getName() + '(' + key + ") for Slimefun " + SlimefunPlugin.getVersion()); } } + done++; } } @@ -253,7 +259,7 @@ public class BlockStorage { } public void save(boolean remove) { - this.save(true, remove); + save(true, remove); } public void save(boolean computeChanges, boolean remove) { @@ -311,27 +317,31 @@ public class BlockStorage { } if (chunkChanges > 0) { - File chunks = new File(PATH_CHUNKS + "chunks.sfc"); - Config cfg = new Config(PATH_CHUNKS + "chunks.temp"); - - for (Map.Entry entry : SlimefunPlugin.getRegistry().getChunks().entrySet()) { - // Saving empty chunk data is pointless - if (!entry.getValue().getKeys().isEmpty()) { - cfg.setValue(entry.getKey(), entry.getValue().toJSON()); - } - } - - cfg.save(chunks); - - if (remove) { - SlimefunPlugin.getRegistry().getWorlds().remove(world.getName()); - } + saveChunks(remove); } changes = 0; chunkChanges = 0; } + private void saveChunks(boolean remove) { + File chunks = new File(PATH_CHUNKS + "chunks.sfc"); + Config cfg = new Config(PATH_CHUNKS + "chunks.temp"); + + for (Map.Entry entry : SlimefunPlugin.getRegistry().getChunks().entrySet()) { + // Saving empty chunk data is pointless + if (!entry.getValue().getKeys().isEmpty()) { + cfg.setValue(entry.getKey(), entry.getValue().toJSON()); + } + } + + cfg.save(chunks); + + if (remove) { + SlimefunPlugin.getRegistry().getWorlds().remove(world.getName()); + } + } + public static void store(Block block, ItemStack item) { SlimefunItem sfitem = SlimefunItem.getByItem(item); if (sfitem != null) addBlockInfo(block, "id", sfitem.getID(), true); @@ -511,15 +521,19 @@ public class BlockStorage { } if (destroy) { - if (storage.hasInventory(l)) storage.clearInventory(l); + if (storage.hasInventory(l)) { + storage.clearInventory(l); + } UniversalBlockMenu universalInventory = getUniversalInventory(l); + if (universalInventory != null) { universalInventory.close(); universalInventory.save(); } String chunkString = locationToChunkString(l); + if (SlimefunPlugin.getRegistry().getActiveTickers().containsKey(chunkString)) { Set locations = SlimefunPlugin.getRegistry().getActiveTickers().get(chunkString); locations.remove(l); @@ -528,7 +542,9 @@ public class BlockStorage { SlimefunPlugin.getRegistry().getActiveTickers().remove(chunkString); SlimefunPlugin.getRegistry().getActiveChunks().remove(chunkString); } - else SlimefunPlugin.getRegistry().getActiveTickers().put(chunkString, locations); + else { + SlimefunPlugin.getRegistry().getActiveTickers().put(chunkString, locations); + } } } } @@ -538,7 +554,10 @@ public class BlockStorage { } public static void _integrated_moveLocationInfo(Location from, Location to) { - if (!hasBlockInfo(from)) return; + if (!hasBlockInfo(from)) { + return; + } + BlockStorage storage = getStorage(from.getWorld()); setBlockInfo(to, getLocationInfo(from), true); @@ -563,7 +582,9 @@ public class BlockStorage { SlimefunPlugin.getRegistry().getActiveTickers().remove(chunkString); SlimefunPlugin.getRegistry().getActiveChunks().remove(chunkString); } - else SlimefunPlugin.getRegistry().getActiveTickers().put(chunkString, locations); + else { + SlimefunPlugin.getRegistry().getActiveTickers().put(chunkString, locations); + } } } @@ -600,7 +621,10 @@ public class BlockStorage { } public static SlimefunItem check(Location l) { - if (!hasBlockInfo(l)) return null; + if (!hasBlockInfo(l)) { + return null; + } + return SlimefunItem.getByID(getLocationInfo(l, "id")); } @@ -608,7 +632,9 @@ public class BlockStorage { if (SlimefunPlugin.getBlockDataService().isTileEntity(b.getType())) { Optional blockData = SlimefunPlugin.getBlockDataService().getBlockData(b); - if (blockData.isPresent()) return blockData.get(); + if (blockData.isPresent()) { + return blockData.get(); + } } return checkID(b.getLocation()); @@ -692,8 +718,8 @@ public class BlockStorage { if (menu != null) { for (HumanEntity human : new ArrayList<>(menu.toInventory().getViewers())) { - // Prevents "java.lang.IllegalStateException: Asynchronous entity add!" when closing inventory while - // holding an item + // Prevents "java.lang.IllegalStateException: Asynchronous entity add!" + // when closing the inventory while holding an item Slimefun.runSync(human::closeInventory); } @@ -729,8 +755,13 @@ public class BlockStorage { public static boolean hasInventory(Block b) { BlockStorage storage = getStorage(b.getWorld()); - if (storage == null) return false; - else return storage.hasInventory(b.getLocation()); + + if (storage == null) { + return false; + } + else { + return storage.hasInventory(b.getLocation()); + } } public static BlockMenu getInventory(Location l) {