1.17.x Trying to break blocks in a spiral pattern with delay between each block

Discussion in 'Spigot Plugin Development' started by denNesLP, Jul 9, 2021.

Thread Status:
Not open for further replies.
  1. Hi. First of all: I'm quite new to creating plugins and this is my first try doing something. I learned Java in University and now i'd like to get some practise.

    As it's said in the title, i'm trying to create an outgoing spiral which should mine blocks within a given radius and by itself, it's already kinda working. It's just breaking all blocks in that area instantly. For that case (and for potential performance-improvement) i want to add a delay of 10 ticks (example. Value is given via
    Code (Java):
    config.getLong("TicksBetweenBrokenBlocks")
    ).

    My code, so far, looks like this:
    Code (Java):
        @EventHandler
        public void breakBlocksSpiral(BlockBreakEvent event)
        {
            Location blockPos = event.getBlock().getLocation();
            World w = blockPos.getWorld();
            Block b = w.getBlockAt(blockPos);
            for (Material material : blocks)
            {
                if(config.getBoolean("BreakBlocks"))
                {
                    int x = b.getX(), y = b.getY(), z = b.getZ(); //Coordinates of the broken block
                   
                    for(int h = 0; h < 32; h++)
                        /*I copied this part from https://stackoverflow.com/a/10607084. It creates an outgoing spiral pattern with [x, y, z] being the coordinates of the by a player broken block
                        and [x2, h, z2] being added to that.
                       
                        [X, Z] are the outer limits of the spiral, but for now they're set to 7      */

                    {
                        int X = 7, Z = 7, x2 = 0, z2 = 0, temp, dx = 0, dz = -1; //I know, it's not pretty, but i wanna make it work first
                        int t = Math.max(X,Z);
                        int maxI = t*t;

                        for (int i=0; i < maxI; i++)
                        {
                            if ((-X/2 <= x2) && (x2 <= X/2) && (-Z/2 <= z2) && (z2 <= Z/2))
                            {
                                int finalX = x2;
                                int finalH = h;
                                int finalZ = z2;
                                Bukkit.getScheduler().scheduleSyncDelayedTask(this, () -> breakBlocks(w.getBlockAt(x + finalX, y + finalH, z + finalZ)),config.getLong("TicksBetweenBrokenBlocks")); //This is the part where i'm struggling. The method works fine without the scheduler
                            }
                            if( (x2 == z2) || ((x2 < 0) && (x2 == -z2)) || ((x2 > 0) && (x2 == 1-z2)))
                            {
                                temp=dx;
                                dx=-dz;
                                dz=temp;
                            }
                            x2+=dx;
                            z2+=dz;
                        }
                    }
                }
            }
        }

        private void breakBlocks(Block block)
        {
            for (Material dBlock : blocks) //Array 'blocks' lists blocks who are supposed to be mined. It's not a parameter because i just use one class (for now)
            {
                if (config.getBoolean("DropItems") && block.getType().equals(dBlock)) //DropItems states, if broken blocks should drop items or not
                {
                    block.breakNaturally();
                    break;
                }
                else if (block.getType().equals(dBlock))
                {
                    block.setType(Material.AIR);
                    break;
                }
            }
        }
        private final Material[] blocks = //Example
        {
                        Material.STONE,
                        Material.DIRT
        };
    It would be nice if someone could help me with that
     
  2. Do you want your code to be executed x ticks later or repeat each x ticks?

    Run task later:
    Code (Java):
    Bukkit.getScheduler().runTaskLater(PLUGIN, () -> {
                // your code
            }, config.getLong("TicksBetweenBrokenBlocks"));
    To repeat task:
    Code (Java):
    Bukkit.getScheduler().runTaskTimer(PLUGIN, () -> {
                // your code
            }, 0L/* delay in ticks before first execution*/, config.getLong("TicksBetweenBrokenBlocks"));
    You can also save this in a variable in order to cancel it at some point like so:
    Code (Java):
    BukkitTask task = Bukkit.getScheduler()...
            task.cancel();
     
  3. I want breakBlocks to be repeated for a limited number of times, with a delay of x ticks after the last execution.

    And i just tried runTaskLater and runTasktimer. All blocks got destroyed at the same time, even it happend after the delay of 40 ticks
     
  4. You are not doing it right, you are just putting the for loop inside the run method, you must pass everything in the for loops to the BukkitRunnable
     
  5. Code (Java):
    new BukkitRunnable()
            {
                int count = 0;
                @Override
                public void run()
                {
                    breakBlocks(block);
                    count++;

                    if (count > /* your number of repeated times you want*/)
                        cancel();
                }
            }.runTaskTimer(PLUGIN, config.getLong("TicksBetweenBrokenBlocks"), config.getLong("TicksBetweenBrokenBlocks"));
     
    • Like Like x 1
    • Optimistic Optimistic x 1
  6. I have no idea what i'm doing. I just know that this doesn't work:
    Code (Java):

    for (int h = 0; h < 32; h++)
    {
         int X = 7, Z = 7, x2 = 0, z2 = 0, temp, dx = 0, dz = -1;
         int t = Math.max(X, Z);
         int maxI = t * t;

         for (int i = 0; i < maxI; i++)
         {
              if ((-X / 2 <= x2) && (x2 <= X / 2) && (-Z / 2 <= z2) && (z2 <= Z / 2))
              {
                   int finalX = x2;
                   int finalH = h;
                   int finalZ = z2;
                   new BukkitRunnable()
                   {
                       int count = 0;
                       @Override
                       public void run()
                       {
                            breakBlocks(w.getBlockAt(x + finalX, y + finalH, z + finalZ));
                            count++;

                            if(count > maxI)
                            {
                                 cancel();
                            }
                        }
                    }.runTaskTimer(this, config.getLong("TicksBetweenBrokenBlocks"), config.getLong("TicksBetweenBrokenBlocks"));
               }
               if ((x2 == z2) || ((x2 < 0) && (x2 == -z2)) || ((x2 > 0) && (x2 == 1 - z2)))
               {
                     temp = dx;
                     dx = -dz;
                     dz = temp;
               }
               x2 += dx;
               z2 += dz;
         }
    }
    Where do i need to create the new BukkitRunnable within my code?
     
  7. What the hell are doing? If you wanna do it that way (inside nested for loops) you’ll have to use runTaskLater buddy…
     
  8. You don't have to use for loops, instead, make your own "loop variables", in your case "i" and "h", let me show you an example of a "nested for loop using BukkitRunnable":

    Code (Java):
            new BukkitRunnable(){
                int i = 0;
                int j = 0;
                public void run() {
                    if(j > 8){
                        //Inner for loop ends
                        i++;
                        j = 0;
                        if(i > 8) {
                            //Outer for loop ends
                            cancel();
                            return;
                        }
                    }
                    //Code inside for loops here
                    j++;
                }
            }.runTaskTimer(plugin, 1, 10);
     
    • Useful Useful x 1
  9. Like I said, I have no idea what I'm doing, so I'm guessing most of the time and hope that it's working in the end. Reading the spigot-documentation isn't helping much either.

    Btw: Exchanging runTaskTimer with runTaskLater still doesn't work


    I tried your way and my method looks like this now:
    Code (Java):
    @EventHandler
        public void breakBlocks(BlockBreakEvent event)
        {
            Location blockPos = event.getBlock().getLocation();
            World w = blockPos.getWorld();
            Block b = w.getBlockAt(blockPos);
            for (Material dBlock : blocks)
            {
                if (b.getType() == dBlock)
                {
                    int x = b.getX(), y = b.getY(), z = b.getZ(); //Coordinates of broken block
                    if(config.getBoolean("BreakBlocks"))
                    {
                        new BukkitRunnable()
                        {
                            int i = 0, h = 0, X = 7, Z = 7, x2 = 0, z2 = 0, temp, dx = 0, dz = -1;
                            public void run()
                            {
                                if (h > 32) //Heightlimit for blocks
                                {
                                    i++;
                                    h = 0;
                                    if (i > ((Math.max(X, Z)) * (Math.max(X, Z))))
                                    {
                                        cancel();
                                    }
                                }

                                //This code is supposed to break blocks in form of a spiral
                                if ((-X / 2 <= x2) && (x2 <= X / 2) && (-Z / 2 <= z2) && (z2 <= Z / 2))
                                {
                                    breakBlock(w.getBlockAt(x + x2, y + h, z + z2));
                                }
                                if ((x2 == z2) || ((x2 < 0) && (x2 == -z2)) || ((x2 > 0) && (x2 == 1 - z2)))
                                {
                                    temp = dx;
                                    dx = -dz;
                                    dz = temp;
                                }
                                x2 += dx;
                                z2 += dz;
                                h++;
                            }
                        }.runTaskTimer(this, 1, config.getLong("TicksBetweenBrokenBlocks"));
                    }
                }
            }
        }
    It just broke 4 out of ~100 blocks, (so there's still stg wrong with the spiral-algorithm) but with the delay i wanted. Thank you
     
  10. Glad the delay works for you now, I hope you understand what and why is happening. Now is time to add debug messages and see why is it only breaking 4 out of 100 block. By the way, instead of
    Code (Java):
    i > ((Math.max(X,Z)) * (Math.max(X,Z)))
    you could just do
    Code (Java):
    i > Math.pow(Math.max(X,Z), 2)
     
    • Like Like x 1
    • Useful Useful x 1
  11. It's working now. Just doesn't look that pretty yet...

    Thanks to both of you
    Code (Java):
    @EventHandler
        public void breakBlocks(BlockBreakEvent event)
        {
            Location blockPos = event.getBlock().getLocation();
            World w = blockPos.getWorld();
            Block b = w.getBlockAt(blockPos);
            for (Material dBlock : blocks)
            {
                if (b.getType() == dBlock)
                {
                    int x = b.getX(), y = b.getY(), z = b.getZ(); //Coordinates of broken block
                    if(config.getBoolean("BreakBlocks"))
                    {
                        new BukkitRunnable()
                        {
                            int i = 0, j = 0, h = 0, X = 7, Z = 7, x2 = 0, z2 = 0, temp, dx = 0, dz = -1;

                            public void run()
                            {
                                if (j > (Z + 1))
                                {
                                    i++;
                                    j = 0;
                                    if (i > (X + 1))
                                    {
                                        h++;
                                        i = 0;
                                        dx = 0;
                                        dz = -1;
                                        x2 = 0;
                                        z2 = 0;
                                        if (h > 32)
                                        {
                                            cancel();
                                        }
                                    }
                                }
                                if ((-X / 2 <= x2) && (x2 <= X / 2) && (-Z / 2 <= z2) && (z2 <= Z / 2))
                                {
                                    breakBlock(w.getBlockAt(x + x2, y + h, z + z2));
                                }
                                if ((x2 == z2) || ((x2 < 0) && (x2 == -z2)) || ((x2 > 0) && (x2 == 1 - z2)))
                                {
                                    temp = dx;
                                    dx = -dz;
                                    dz = temp;
                                }
                                x2 += dx;
                                z2 += dz;
                                j++;
                            }
                        }.runTaskTimer(this, config.getLong("TicksBetweenBrokenBlocks"), config.getLong("TicksBetweenBrokenBlocks"));
                    }
                }
            }
        }
     
    • Like Like x 1
Thread Status:
Not open for further replies.