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?
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.
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
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()); } }
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.
Listen on event, put removed blocks into map <Block, Location>, then do scheduled runnable and use iterate through map
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)); } }
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
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
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.
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); } }
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.