Solved Regenerate exploded blocks

Discussion in 'Plugin Development' started by MiniDigger, Oct 23, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    MiniDigger

    Hey guys,
    what I am trying to do is to make an explosion and regenerate the blocks after some time.
    So I created an explosion using 'loc.getWorld().createExplosion(loc, 4, false);'. That works fine.
    Now I store the exploded blocks into a list
    Code:
    public List<Block> blocks;
    @EventHandler
    public void onEntityExplode(EntityExplodeEvent e) {
    blocks = e.blockList();
    }
    And here is my regeneration method:
    Code:
     public void regen() {
    for (Block b : blocks) {
    b.getLocation().getBlock().setTypeIdAndData(b.getTypeId(), b.getData(), false);
    }
    }
    But it don't work. The blocks explode but dont get replaced.
    Thank you for your help

    bump

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 5, 2016
  2. Offline

    The_Doctor_123

    Create a delayed task and put back all the blocks from the list.
     
  3. Offline

    MiniDigger

    The_Doctor_123 this is what I am doing but it dont work :D. I delayed regen() for 10 seconds using the BukkitScheduler.
     
  4. Offline

    The_Doctor_123

    MiniDigger
    So what does it do? Throw an exception, or just not work? Show us the code you used.
     
  5. Offline

    MiniDigger

    Code:
    loc.getWorld().createExplosion(loc, 4, false);
    Bukkit.getScheduler().runTaskLater(Advent.plugin, new Runnable() {
     
    @Override
    public void run() {
    regen();
    }, 20*10);
    it dont throw an exception, it just dont replace the blocks. The just blew up.
     
  6. Offline

    The_Doctor_123

    What is the regen() method? Don't you need a List argument so it knows what blocks to regen?
     
  7. Offline

    MiniDigger

    the regen method is in the first post. It dont need the blocklist, the list is an attribute
     
  8. Offline

    The_Doctor_123

    MiniDigger
    Oh, that's troublesome the way you did that. What if there was a second explosion before the first set of blocks were restored? Create an argument for that method(or just don't have the method at all.. you don't exactly need it to be a method) for the list of blocks in the explosion.

    Also, check if the event is even getting executed. Did you register events?
     
    1Rogue likes this.
  9. Offline

    MiniDigger

    the event is getting executed. it checked it with a log msg. I think somethink in the regen() method is wrong.
     
  10. Offline

    Goblom

    with your EntityExplodeEvent add all blocks exploded to map with Block & location.

    Then do what The_Doctor_123 said and set a runnable to get all blocks in that map and place them.
     
  11. Offline

    The_Doctor_123

    MiniDigger
    Let me ask you, does regeneration apply to all explosions or just ones generated by your plugin?
     
  12. Offline

    MiniDigger

    The_Doctor_123 just ones

    Goblom isnt this what I am doing? :D

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 5, 2016
  13. Offline

    Goblom

    MiniDigger yes, but it looks like every time a new explosion happens then the previous blocks in the list get overwritten
     
  14. Offline

    MiniDigger

    Goblom yeah it does but I know that this is the only explosion on the server. Its the lobby server of a network.
     
  15. Offline

    Goblom

    MiniDigger instead of doing blocks = e.getBlocks();

    try doing blocks.add(e.getBlocks());
     
  16. Offline

    MiniDigger

    there is not method add(List<Block>) in type list. I used addAll(List<Block>) but it still dont works
     
  17. Offline

    Garris0n

    You can't actually save blocks...
     
  18. Offline

    desht

    This.

    All the original method is doing is saving the Block objects, which can be considered a "pointer" to the place in the world. A Block does not store what's actually there, just where it is. (You can check this yourself by looking at CraftBlock.java). So when it attempts to restore the blocks, it's simply setting the block to what it currently is, i.e. doing nothing.

    MiniDigger what you want to store is the block's state - and there happens to be a Bukkit class to do exactly that: BlockState. In the initial event handler, add block.getState() for each affected block to a List<BlockState> object. In your deferred task, call state.update(true) for each member of the list.

    I do something similar in my PortableHole plugin (not explosion repairing in this case, but closing temporary tunnels through solid blocks).

    A couple of other points:
    • You will need to track the block states from multiple explosions. One way to do this is create a new class (let's call it Explosion) which stores the List<BlockState> from an explosion. This class could inherit BukkitRunnable, so your event handler can just create one (passing the list of affected blocks to the constructor) and call .runTaskLater() on it. Once the task is run, the object goes out of scope.
    • You need to think about what happens if the server is shut down when there is one or more repair operations pending. You can either persist all of the block states that need restoring, or (much easier) do all the repairing from the plugin's onDisable() method (you'll need to keep track of all the pending tasks so you can run them early).
     
    MiniDigger and Garris0n like this.
  19. Offline

    MiniDigger

    desht thank you realy much. Got it working know. Never looked into the differets of Block and BlockState ;D
     
  20. Offline

    scarabcoder

    This is probably outdated, but I would LOVE to know how you did this. Can you give me the complete code please MiniDigger?
     
  21. Offline

    MiniDigger

    scarabcoder I'll try to send you the code when I am at home.
     
  22. Offline

    scarabcoder

  23. Offline

    blablubbabc

    desht
    Though BlockState is (currently) bugged.. sadly :(

    Example (I tested this with your PortableHole plugin to make sure you run into the same issue): If there is a sign with text in the way of the "portable hole", then, after restoring that sign from air back to sign material, the tile data (sign text) will be lost..forever (no reconnect can fix this).

    See this ticket about it: https://bukkit.atlassian.net/browse/BUKKIT-3522

    Same issue with all other TileEntityData (chest content etc.)

    I really hope this will be fixed soon.
     
  24. Offline

    MiniDigger

    scarabcoder there you go:
    Code:java
    1. @EventHandler
    2. public void onEntityExplode(EntityExplodeEvent e) {
    3. ArrayList<Block> blocks = new ArrayList<>();
    4. ArrayList<Block> dontexplode = new ArrayList<>();
    5. for (Block b : e.blockList()) {
    6. if (b.getType() == Material.WOOL || b.getType() == Material.TORCH) {
    7. blocks.add(b);
    8. } else {
    9. dontexplode.add(b);
    10. }
    11. }
    12. for(Block b : dontexplode){
    13. e.blockList().remove(b);
    14. b.getState().update(true);
    15. }e.setYield(0);
    16. GeschenkExplosion ge = new GeschenkExplosion(blocks);
    17. Bukkit.getScheduler().runTaskLater(Advent.plugin, ge, 20 * 20);
    18. }


    Code:java
    1. package eu.zonegames.Advent;
    2.  
    3. import java.util.ArrayList;
    4. import java.util.List;
    5. import java.util.Random;
    6.  
    7. import org.bukkit.Bukkit;
    8. import org.bukkit.block.Block;
    9. import org.bukkit.block.BlockState;
    10. import org.bukkit.scheduler.BukkitRunnable;
    11.  
    12. public class GeschenkExplosion extends BukkitRunnable{
    13.  
    14. List<BlockState> states;
    15.  
    16. public GeschenkExplosion(ArrayList<BlockState> blocks){
    17. states = blocks;
    18. }
    19.  
    20. public GeschenkExplosion(List<Block> blocks){
    21. states = new ArrayList<>();
    22. for(Block b : blocks){
    23. states.add(b.getState());
    24. }
    25. }
    26.  
    27. @Override
    28. public void run() {
    29. regen();
    30. }
    31.  
    32. public void regen(){
    33. for(final BlockState state : states){
    34. Bukkit.getScheduler().runTaskLater(Advent.plugin, new Runnable() {
    35.  
    36. @Override
    37. public void run() {
    38. state.update(true);
    39. }
    40. }, new Random().nextInt(10*20) + 20);
    41. }
    42. }
    43.  
    44. }
     
  25. Offline

    scarabcoder

    Thanks a lot MiniDigger!

    MiniDigger For some reason, this doesn't work for me. Where do I put the code?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 5, 2016
  26. Offline

    MiniDigger

    scarabcoder the first snippet is a event listener. Put it into your Listener. The second one is a class.
     
  27. Offline

    scarabcoder

    Okay, thanks!
     
Thread Status:
Not open for further replies.

Share This Page