Help with Falling Blocks bug

Discussion in 'Spigot Plugin Development' started by Twintyk, Jan 4, 2019.

  1. Hello there ! Im asking for some assistance on a block explosion util class im making. The thing is what when the code triggers this small kind of explosion happends and blocks fly a little bit, after a X amount of time a BukkitRunnable timer regenerates the destroyed terrain and deletes the blocks created by the flying blocks. Now the issue is what when the terrain is generated again when you try to break it the block gets spawned again, no idea why it does that, if i break the block it just spawns again, making impossible to destroy it. Have to say what this is fixed in a server reload or restart, must probably is something to do with FallingBlock entity but tried everything with no luck.

    Here is my current code, i hope some can help me, thanks !

    Code (Java):
    public class FallingBlocksManager implements Listener {

        private JavaPlugin pluginInstance;
        private static FallingBlocksManager instance;

        private ArrayList<FallingBlockSet> fallingBlockSets = new ArrayList<>();

        public FallingBlocksManager(JavaPlugin pluginInstance) {
            if (instance != null) return;
            instance = this;
            this.pluginInstance = pluginInstance;
            pluginInstance.getServer().getPluginManager().registerEvents(this, pluginInstance);
            initRegenerateBlocksTask();
        }

        private void initRegenerateBlocksTask() {
            new BukkitRunnable() {
                @Override
                public void run() {
                    ArrayList<FallingBlockSet> setsToRemove = new ArrayList<>();
                    for (FallingBlockSet fallingBlockSet : fallingBlockSets) {
                        if (fallingBlockSet.getDurationRemaining() <= 0) {
                            setsToRemove.add(fallingBlockSet);
                            continue;
                        }
                        fallingBlockSet.setDurationRemaining(fallingBlockSet.getDurationRemaining() - 0.25D);
                    }
                    for (FallingBlockSet fallingBlockSet : setsToRemove)
                        regenerateFallingBlockSet(fallingBlockSet);
                }
            }.runTaskTimer(pluginInstance, 5, 5);
        }

        public void regenerateFallingBlockSet(FallingBlockSet fallingBlockSet) {
            for (Entity entity : fallingBlockSet.getFallingBlocks())
                entity.remove();
            for (Location location : fallingBlockSet.getFallingBlocksLand())
                location.getBlock().setType(Material.AIR);
            for (Location location : fallingBlockSet.getInitialBlocksData().keySet()) {
                Block block = location.getBlock();
                if (block == null) continue;
                ItemStack blockItem = fallingBlockSet.getInitialBlocksData().get(location);
                block.setType(blockItem.getType());
                block.setData(blockItem.getData().getData());          
            }
        }

        public FallingBlockSet createFallingBlockSet(ArrayList<Location> blocks, double blocksDuration, Vector velocity) {
            final HashMap<Location, ItemStack> initialBlocksData = new HashMap<>();
            final ArrayList<Entity> fallingBlocks = new ArrayList<>();
            for (Location location : blocks) {
                Block block = location.getBlock();
                if (block == null) continue;

                if (block.getType() != Material.AIR) {
                    ItemStack blockItem = new ItemStack(block.getType(), 1, (short) block.getState().getData().getData());
                    initialBlocksData.put(location, blockItem);
                } else
                    continue;
                if (!block.getType().isSolid()) {
                    block.setType(Material.AIR);
                    continue;
                }
                FallingBlock fallingBlock = block.getWorld().spawnFallingBlock(block.getLocation().add(0, 1, 0), block.getState().getData());
                fallingBlock.setDropItem(false);
                block.setType(Material.AIR);

                fallingBlock.setVelocity(velocity);
                fallingBlocks.add(fallingBlock);
            }

            FallingBlockSet fallingBlockSet = new FallingBlockSet(initialBlocksData, fallingBlocks, blocksDuration);
            for (Entity entity : fallingBlockSet.getFallingBlocks())
                entity.setMetadata("FallingBlockMeta", getNewFallingBlockSetMetadata(fallingBlockSet));
            fallingBlockSets.add(fallingBlockSet);
            return fallingBlockSet;
        }

        public ArrayList<Location> createSphereShape(Location center, int radius) {
            final double finalRadius = radius + 0.5;
            final double blockX = center.getBlockX() + 0.5;
            final double blockY = center.getBlockY() + 0.5;
            final double blockZ = center.getBlockZ() + 0.5;

            ArrayList<Location> sphereBlocks = new ArrayList<>();
            for (double x = blockX - finalRadius; x <= blockX + finalRadius; x++)
                for (double y = blockY - finalRadius; y <= blockY + finalRadius; ++y)
                    for (double z = blockZ - finalRadius; z <= blockZ + finalRadius; ++z) {
                        final double distanceSq = lengthSq(blockX - x, blockY - y, blockZ - z);
                        if (!(distanceSq < finalRadius * finalRadius)) continue;
                        sphereBlocks.add(new Location(center.getWorld(), x, y, z));
                    }
            return sphereBlocks;
        }


        @EventHandler(priority = EventPriority.HIGHEST)
        public void onEntityChangeBlock(EntityChangeBlockEvent event) {
            Entity entity = event.getEntity();
            if (!(entity instanceof FallingBlock)) return;
            if (!entity.hasMetadata("FallingBlockMeta")) return;
            MetadataValue metadataValue = entity.getMetadata("FallingBlockMeta").get(0);
            entity.remove();
            if (!(metadataValue.value() instanceof FallingBlockSet)) {
                if (metadataValue.getOwningPlugin().getName().equals(pluginInstance.getName()))
                    event.setCancelled(true);
                return;
            }
            FallingBlockSet fallingBlockSet = (FallingBlockSet) metadataValue.value();
            for (FallingBlockSet otherFallingBlockSet : fallingBlockSets)
                if (otherFallingBlockSet.equals(fallingBlockSet)) {
                    otherFallingBlockSet.getFallingBlocksLand().add(event.getBlock().getLocation());
                    return;
                }
            event.setCancelled(true);
        }

        @EventHandler(priority = EventPriority.LOWEST)
        public void onPluginDisable(PluginDisableEvent event) {
            if (!event.getPlugin().getName().equals(pluginInstance.getName()))
                return;
            for (FallingBlockSet fallingBlockSet : fallingBlockSets)
                regenerateFallingBlockSet(fallingBlockSet);
        }

        private double lengthSq(double x, double y, double z) {
            return (x * x) + (y * y) + (z * z);
        }

        private MetadataValue getNewFallingBlockSetMetadata(FallingBlockSet fallingBlockSet) {
            return new MetadataValue() {
                @Override
                public Object value() {
                    return fallingBlockSet;
                }

                @Override
                public int asInt() {
                    return 0;
                }

                @Override
                public float asFloat() {
                    return 0;
                }

                @Override
                public double asDouble() {
                    return 0;
                }

                @Override
                public long asLong() {
                    return 0;
                }

                @Override
                public short asShort() {
                    return 0;
                }

                @Override
                public byte asByte() {
                    return 0;
                }

                @Override
                public boolean asBoolean() {
                    return false;
                }

                @Override
                public String asString() {
                    return null;
                }

                @Override
                public Plugin getOwningPlugin() {
                    return pluginInstance;
                }

                @Override
                public void invalidate() {

                }
            };
        }

        public static FallingBlocksManager getInstance() {
            return instance;
        }

    }

    Code (Java):
    public class FallingBlockSet {

        private HashMap<Location, ItemStack> initialBlocksData = new HashMap<>();
        private ArrayList<Entity> fallingBlocks = new ArrayList<>();
        private ArrayList<Location> fallingBlocksLand = new ArrayList<>();
        private double durationRemaining;

        FallingBlockSet(HashMap<Location, ItemStack> initialBlocksData, ArrayList<Entity> fallingBlocks, double initialDuration) {
            this.initialBlocksData = initialBlocksData;
            this.fallingBlocks = fallingBlocks;
            this.durationRemaining = initialDuration;
        }

        public double getDurationRemaining() {
            return durationRemaining;
        }

        public void setDurationRemaining(double durationRemaining) {
            this.durationRemaining = durationRemaining;
        }

        public ArrayList<Entity> getFallingBlocks() {
            return fallingBlocks;
        }

        ArrayList<Location> getFallingBlocksLand() {
            return fallingBlocksLand;
        }

        public HashMap<Location, ItemStack> getInitialBlocksData() {
            return initialBlocksData;
        }
    }
    The trigger method is "createFallingBlockSet()" in FallingBlocksManager class
     
  2. Bump, im still needing a fix for this.