#Recursive Timber Plugin leads much to be desired performance wise

1 messages · Page 1 of 1 (latest)

gaunt hemlock
#
private void timber(Block block, int recursionDepth,  ItemStack handItem) {
        // Check if the recursion depth exceeds the limit
        if (recursionDepth >= MAX_RECURSION_DEPTH) {
            return;
        }

        // Check if the block one of the wood-types to be tree felled (All Logs/Stems and Stripped variants)
        if (!isLogMaterial(block.getType())) {
            return;
        }

        // TODO: add wood sound to block breaking
        block.breakNaturally();
        //TODO: axe durability
        //handItem.setDurability((short) (handItem.getDurability() - 1.0));

        for (int x = -1; x <= 1; x++) {
            for (int y = 0; y <= 1; y++) { // Start at base level. Tree felling upward
                for (int z = -1; z <= 1; z++) {
                    if (x == 0 && y == 0 && z == 0) { 
                        continue;
                    }

                    Block adjacentBlock = block.getRelative(x, y, z);
                    // Recursively call timber for the surrounding block with the updated recursion depth
                    // Returning handItem for calculating axe durability, not related to performance issues
                    timber(adjacentBlock, recursionDepth + 1, handItem);
                }
            }
        }
    }

Hello, currently attempting to make a timber plugin from scratch. Performance wise, the above code works well and as intended for my purposes (ignore the axe calculations). Currently the plugin will instantly feller any connected blocks up to 32 times. However I would like to put a delay (roughly a few ticks) on each individual block broken in the recursive timber method. I've attempted to use BukkitScheduler but run into performance issues with larger trees, not sure how to ask or approach optimizing the performance.

prisma moat
#

How have you attempted to use the scheduler

#

What kind of performance issues

celest axle
#

If that's sync, which it should be

gaunt hemlock
#
        Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> { 

        // TODO: add wood sound to block breaking
        block.breakNaturally();
        //TODO: axe durability
        //handItem.setDurability((short) (handItem.getDurability() - 1.0));

        for (int x = -1; x <= 1; x++) {
            for (int y = 0; y <= 1; y++) { // Start at base level. Tree felling upward
                for (int z = -1; z <= 1; z++) {
                    if (x == 0 && y == 0 && z == 0) { // Skip the center
                        continue;
                    }

                    Block adjacentBlock = block.getRelative(x, y, z);
                    // Recursively call timber for the surrounding block with the updated recursion depth
                    // Returning handItem for calculating axe durability, not related to performance issues
                    timber(adjacentBlock, recursionDepth + 1, handItem);
                    }
                }
            }
        }, 2); 
    }
}

Same code as above but added the scheduleSyncDelayedTask, sorry I should have clarified.
Tree felling cause performance issues when i implement this delay sync task

prisma moat
#

Don’t schedule the loop and recursion in the task

gaunt hemlock
#

How can I still achieve the slight delay on each recursion?

gaunt hemlock
#

i tried to wrap the task around just the block break but still see performance issues

celest axle
#

You'd need to use an async task to make it asynchronous and running parallel to the primary thread (game thread), but breaking blocks should be done synchronously

#

One thing you could do, but is probably a bad idea is to do the iterations asynchronously and schedule a task to break the blocks on the primary thread. But even the block lookup is prohibited apparently if you look at the async scheduling docs in which it is stated, that the Bukkit API should not be accessed asynchronously

gaunt hemlock
#

I am simply trying to create the effect of the logs breaking adjancently one after another, upon an intial block break event. your explanation also helped me understand why I wouldnt want to use thread.sleep to delay this.

prisma moat
gaunt hemlock
gaunt hemlock
#

Would increasing the delay with the sync delayed task help with perofmrance?

#

Yeah that just causes me to time out on a test lol

prisma moat
#

Show ur new code

#

I am assuming it’s cause the recursive functions recurves back to the wood that wasn’t removed yet

gaunt hemlock
#
    
    @EventHandler
    public void onBlockBreak(BlockBreakEvent event) {
        Player player = event.getPlayer();
        ItemStack handItem = player.getInventory().getItemInMainHand();
        
        if (isAxe(handItem)) {
            Block brokenBlock = event.getBlock();
            
            if (isLogMaterial(brokenBlock.getType())){
                // Timber using current wood, start loop and manage axe
                timber(brokenBlock, 0, handItem);

  }

    // Current value (32) will tree feller logs formation as big as the biggest tree
    private static final int MAX_RECURSION_DEPTH = 32;


    private void timber(Block block, int recursionDepth,  ItemStack handItem) {
        // Check if the recursion depth exceeds the limit
        if (recursionDepth >= MAX_RECURSION_DEPTH) {
            return;
        }

        // Check if the block one of the wood-types to be tree felled (All Logs/Stems and Stripped variants)
        if (!isLogMaterial(block.getType())) {
            return;
        }
        Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
        // Break log with 2 tick delay
        block.breakNaturally();
        }, recursionDepth * 2);
        //TODO: axe durability
        //handItem.setDurability((short) (handItem.getDurability() - 1.0));

        for (int x = -1; x <= 1; x++) {
            for (int y = 0; y <= 1; y++) { // Start at base level. Tree felling upward
                for (int z = -1; z <= 1; z++) {
                    if (x == 0 && y == 0 && z == 0) { // Skip the center
                        continue;
                    }

                    Block adjacentBlock = block.getRelative(x, y, z);
                    // Recursively call timber for the surrounding block with the updated recursion depth
                    timber(adjacentBlock, recursionDepth + 1, handItem);
                }
            }
        }
    }
}
gaunt hemlock
#

@prisma moat

#

thanks for your help so far

gaunt hemlock
#

Any luck figuring a solution I could try?

celest axle
#

I mean it's quite simple

#

You do the iteration synchronously and immediately (not within a task!) and add the blocks to destroy into a queue that gets executed after an initial task in which you poll the head of the queue each time the task updates until there's no head left

#

That way you have your effect of your adjacent blocks being destroyed one by one