Search code examples
javabukkit

Storing Blocks for Replace Later


Here's my snippet of code. I have Lists for the blocks and player. All I need is for after the five seconds in that runnable is up, it'll replace the blocks that were previously replaced, assigning a player to get the blocks.

    @EventHandler
public void onSnowballHit(ProjectileHitEvent e) {
    // If it's a snowball...
    if (e.getEntity() instanceof Snowball) {
        Snowball snowball = (Snowball) e.getEntity();

        final Player p = (Player) snowball.getShooter();

        // ...if a player threw it...
        if (snowball.getShooter() instanceof Player) {
            // Make a Player from the Entity

                        BlockIterator iterator = new BlockIterator(e.getEntity().getWorld(),
                                e.getEntity().getLocation().toVector(), e.getEntity().getVelocity().normalize(),
                                0.0D, 4);

                        // Make a block
                        Block hitBlock = null;

                        // Loop through possible blocks
                        while (iterator.hasNext()) {
                            // Set the hitBlock to the current block we're checking
                            hitBlock = iterator.next();

                            // If it's not air, STOP!
                            if (!hitBlock.getType().equals(Material.AIR)) {
                                break;
                            }
                        }
                        int min = 1;
                        int max = 15;
                            Random r = new Random();

                            byte clayBlocks = (byte) (r.nextInt(max - min + 1) + min);

                            paintBlockList.add(hitBlock);
                            painters.add(p);
                            // Set it to stained clay
                            hitBlock.setType(Material.STAINED_CLAY);

                            // red = 14, blue = 11 (data values)
                            hitBlock.setData(clayBlocks);
                            Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
                                public void run(){
                                    if(painters.contains(p)){
                                        painters.remove(p);

                                    }
                                }
                            }, 100);

                     }
                   }    
                }

Solution

  • You could do it the same way you remove the Player from the painters list. Once you've found the first solid block (hitBlock) create a new final reference so that you can access it in the Runnable, for example like this:

    final Block solidBlock = hitBlock;
    

    To return the block to the state it was before you changed its type and data, you could keep track of those attributes:

    final byte previousData = solidBlock.getData();
    final Material previousType = solidBlock.getType();
    

    Then in your run() method you can simply change the block back if it is still at that point different like so:

    if (solidBlock.getType() != previousType) {
        solidBlock.setType(previousType);
    }
    
    if (solidBlock.getData() != previousType) {
        solidBlock.setData(previousData);
    }
    

    I'm sure there's a cleaner, nicer way to do it but this might be good enough for your purposes (I did find a glitch where if you throw two snowballs at the same block, it won't revert to the true original block but to a stained clay block because of the way the future Runnable tasks are written here, to fix this you'd need to write this completely differently and keep track of more things).