TNT Regen Exploded Blocks

Discussion in 'Spigot Plugin Development' started by bmac20, Apr 30, 2017.

  1. How would I go about getting the blocks destroyed by the TNT explosion and then generate them back?

    Would I store the location and the block in some list and then just loop through it, setting the block each time?
     
  2. https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/block/BlockExplodeEvent.html

    Yes, something like that. You should start working on this since you have an initial idea and you will figure the remaining parts out on the way. I believe this is the optimal method to learn.
     
  3. Store the block after it gets destroyed by TNT, in the aforementioned event, then use Block#setType to add the 'regenerating' effect

    Edit: also probably worth mentioning that you should remove it from your storage if you're not using it, clears up memory a bit

    Sent from my iPhone using Tapatalk
     
  4. This is what I have so far, and it is still not generating the blocks when exploded. There are also no errors in the console.
    Code (Text):
    package me.textrus.tntregen;

    import org.bukkit.block.Block;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.block.BlockExplodeEvent;
    import org.bukkit.plugin.java.JavaPlugin;

    public class TNTRegen extends JavaPlugin implements Listener {

        public void onEnable() {
            this.getServer().getPluginManager().registerEvents(this, this);
        }


        @EventHandler
        public void onBlockExplode(BlockExplodeEvent e) {
           
            for(Block b : e.blockList()){
                regenBlocks(b);
            }
           
        }

        public void regenBlocks(Block b) {
            b.setType(b.getType());
        }

    }
     
     
  5. You need to add a delay using a BukkitRunnable and then iterate through the block list one by one using an index. That way they don't all generate at once.
    Your on the right track though.
     
  6. Listen on event, put removed blocks into map <Block, Location>, then do scheduled runnable and use iterate through map
     
  7. This is a somewhat old code, hopefully it will still work :)

    Code (Text):
    package me;

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;

    import org.bukkit.Bukkit;
    import org.bukkit.Effect;
    import org.bukkit.Location;
    import org.bukkit.Material;
    import org.bukkit.Sound;
    import org.bukkit.block.Block;
    import org.bukkit.entity.Entity;
    import org.bukkit.entity.Item;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.entity.EntityExplodeEvent;

    public class Regen implements Listener {

        @EventHandler
        public void onExplode(EntityExplodeEvent e){
            final HashMap<Location, Material> blocks = new HashMap<Location, Material>();
            final HashMap<Location, Byte> dats = new HashMap<Location, Byte>();
            final Entity entity = e.getEntity();
            for (Block b : e.blockList()){
                blocks.put(b.getLocation(), b.getType());
                dats.put(b.getLocation(), Byte.valueOf(b.getData()));
            }
            //Main.getPlugin() Returns where Java Plugin is extending.
            Bukkit.getScheduler().scheduleSyncDelayedTask(Main.getPlugin(), new Runnable() {
                @Override
                public void run() {
                    for (Entity ent : entity.getWorld().getNearbyEntities(entity.getLocation(), 10.0D, 10.0D, 10.0D)) {
                        if ((ent instanceof Item)) {
                            ent.remove();
                        }
                    }
                }
            }, 1L);
            Bukkit.getScheduler().scheduleSyncDelayedTask(Main.getPlugin(), new Runnable() {
                @Override
                public void run() {
                    blockRegen(blocks, dats);
                }
            }, 40L);
        }
       
        public void blockRegen(final HashMap<Location, Material> blocks, final HashMap<Location, Byte> dats){
            Bukkit.getScheduler().scheduleSyncDelayedTask(Main.getPlugin(), new Runnable() {
                @Override
                public void run() {
                    if (!blocks.isEmpty()){
                        HashMap<Double, Location> hashList = new HashMap<Double, Location>();
                        for (Location loc : blocks.keySet()) {
                            hashList.put(Double.valueOf(loc.getY()), loc);
                        }
                        List<Double> doubles = new ArrayList<Double>();
                        for (Iterator localIterator2 = hashList.keySet().iterator(); localIterator2.hasNext();){
                            double d = ((Double)localIterator2.next()).doubleValue();
                            doubles.add(Double.valueOf(d));
                        }
                        Location loc = (Location)hashList.get(doubles.get(Regen.minIndex(doubles)));
                        Material b = (Material)blocks.get(loc);
                        loc.getWorld().getBlockAt(loc).setType(b);
                        loc.getWorld().getBlockAt(loc).setData(((Byte)dats.get(loc)).byteValue());
                        for (Entity ent : loc.getWorld().getNearbyEntities(loc, 15.0D, 15.0D, 15.0D)) {
                            if ((ent instanceof Player)){
                                Player p = (Player)ent;
                                p.playSound(loc, Sound.CHICKEN_EGG_POP, 1.0F, 1.0F);
                                p.playEffect(loc, Effect.STEP_SOUND, loc.getWorld().getBlockAt(loc).getType());
                            }
                        }
                        blocks.remove(loc);
                        blockRegen(blocks, dats);
                    }
                }
            }, 3L);
        }
       
        public static int minIndex(List<Double> list){
            return list.indexOf(Collections.min(list));
        }
       
    }
     
     
  8. Personally, I would store blocks instead of locations. But yeah, have 2 hashmaps, one to store the original material, and another to store the original data value. After blocks explode, call a method which schedules a task for later and regenerates the block by getting the values from the 2 hashmaps
     
    • Agree Agree x 1
  9. WAS

    WAS

    Can you explain what you are actually trying to do specifically step by step?

    Like, yes you want to regen blocks exploded. But what you are doing now is irrelevant as you can just run EnttiyExplodeEvent#blockList().clear() will remove any blocks going to be removed. You can even clone/copy this exact list anywhere you'd like (store it in config/memory with a hash for the event, loop all stored hashed. Once executed remove set)

    Code (Java):
    List<Block> myRegenList = new ArrayList<Block>();
    myRegenList.addAll(e.blockList());
    Code (Java):
    e.blockList().clear() // No damage/blocks removed
     
  10. Or you can simply remove block you don't want to blow up from the Event#blocklist.
     
    • Agree Agree x 1
  11. Code (Text):
    @EventHandler
        public void onEntityExplode(EntityExplodeEvent e) {

            for (Block b : e.blockList()) {
                BlockState state = b.getState();
               
                List<Block> blocks = e.blockList();

                b.setType(Material.AIR);

                int delay = 20;

                if ((b.getType() == Material.SAND) || (b.getType() == Material.GRAVEL)) {
                    delay += 1;
                }

                Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {

                    int i = 0;
                   
                    public void run() {

                        blocks.get(i).getState().update(true,false);
                        i += 1;

                    }

                }, 0, 20);
            }

        }
    This is what I have so far trying to regenerate the blocks by the second. It's not working for some reason and no error in console.
     
  12. Next time watch the video i send

    Code (Text):
    @EventHandler
            public void onEntityExplode(EntityExplodeEvent e) {
                    for (Block b : e.blockList()) {
                            final BlockState state = b.getState();
                           
                            b.setType(Material.AIR); // Stop item drops from spawning.
                           
                            int delay = 20;
                           
                            if ((b.getType() == Material.SAND) || (b.getType() == Material.GRAVEL)) {
                                    delay += 1;
                            }
                           
                            Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
                                    public void run() {
                                            state.update(true, false);
                                    }
                            }, delay);
                    }
            }
     
  13. I did watch it... I want to make the blocks regen every second...
     
  14. Then make a for loop, so for every block you will create a one second delay
     
  15. Shouldn't that already be happening because its inside the for(Block b : e.blockList)
     
  16. What do you need the integer delay for?

    Anyway, just loop through the block list, if its not sand or gravel continue, if it is sand or gravel schedule a sync task later (with a 1 second delay) that will 'regen' the block, and then remove the value from the storage to save on memory.

    EDIT: Keep in mind that the delay is in ticks, 20 ticks is a second. So make the delay 20 if you want it to be regen each second.