Replacing blocks

Discussion in 'Plugin Development' started by MordorKing78, Dec 29, 2014.

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

    MordorKing78

    So what I want is to place blocks and after 20 seconds they get removed and the blocks who were there before will get replaced. (Sorry for bad english)

    Example, This will get placed on grass,

    Code:
    p.getLocation().add(0, -1, 0).getBlock().setType(Material.GOLD_BLOCK);
         
            p.getLocation().add(1, -1, 0).getBlock().setType(Material.STONE);
            p.getLocation().add(2, -1, 0).getBlock().setType(Material.STONE);
            p.getLocation().add(3, -1, 0).getBlock().setType(Material.STONE);
    
            p.getLocation().add(-1, -1, 0).getBlock().setType(Material.STONE);
            p.getLocation().add(-2, -1, 0).getBlock().setType(Material.STONE);
            p.getLocation().add(-3, -1, 0).getBlock().setType(Material.STONE);
    
            p.getLocation().add(0, -1, 1).getBlock().setType(Material.STONE);
            p.getLocation().add(0, -1, 2).getBlock().setType(Material.STONE);
            p.getLocation().add(0, -1, 3).getBlock().setType(Material.STONE);
    
            p.getLocation().add(0, -1, -1).getBlock().setType(Material.STONE);
            p.getLocation().add(0, -1, -2).getBlock().setType(Material.STONE);
            p.getLocation().add(0, -1, -3).getBlock().setType(Material.STONE);
         
            p.getLocation().add(2, -1, -2).getBlock().setType(Material.STONE);
            p.getLocation().add(-2, -1, 2).getBlock().setType(Material.STONE);
            p.getLocation().add(2, -1, 2).getBlock().setType(Material.STONE);
            p.getLocation().add(-2, -1, -2).getBlock().setType(Material.STONE);
         
            p.getLocation().add(0, 0, 3).getBlock().setType(Material.WOOD);
            p.getLocation().add(0, 0, -3).getBlock().setType(Material.WOOD);
            p.getLocation().add(3, 0, 0).getBlock().setType(Material.WOOD);
            p.getLocation().add(-3, 0, 0).getBlock().setType(Material.WOOD);
         
            p.getLocation().add(0, 1, 3).getBlock().setType(Material.BEACON);
            p.getLocation().add(0, 1, -3).getBlock().setType(Material.BEACON);
            p.getLocation().add(3, 1, 0).getBlock().setType(Material.BEACON);
            p.getLocation().add(-3, 1, 0).getBlock().setType(Material.BEACON);
         
            p.getLocation().add(2, 0, -2).getBlock().setType(Material.FENCE);
            p.getLocation().add(-2, 0, 2).getBlock().setType(Material.FENCE);
            p.getLocation().add(2, 0, 2).getBlock().setType(Material.FENCE);
            p.getLocation().add(-2, 0, -2).getBlock().setType(Material.FENCE);
         
            p.getLocation().add(1, 0, -2).getBlock().setType(Material.FENCE);
            p.getLocation().add(-1, 0, 2).getBlock().setType(Material.FENCE);
            p.getLocation().add(1, 0, 2).getBlock().setType(Material.FENCE);
            p.getLocation().add(-1, 0, -2).getBlock().setType(Material.FENCE);
    
            p.getLocation().add(2, 0, -1).getBlock().setType(Material.FENCE);
            p.getLocation().add(-2, 0, 1).getBlock().setType(Material.FENCE);
            p.getLocation().add(2, 0, 1).getBlock().setType(Material.FENCE);
            p.getLocation().add(-2, 0, -1).getBlock().setType(Material.FENCE);
    
    after 20 seconds it will be turned it to grass and air.

    EDIT: I have to get the blocks who are there before the new blocks get placed. I have to store them somewere. And after 20 seconds I have to remove everything and get these blocks back?

    Something like this?? How would I do this?? Thanks!

    I have to get the blocks who are there before the new blocks get placed. I have to store them somewere. And after 20 seconds I have to remove everything and get these blocks back?

    Something like this?? How would I do this?? Thanks!

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Oct 31, 2016
  2. Use a hashmap like this

    HashMap<Location, Material> materialByLocation = new HashMap<Location, Material>();
    then you can use
    materialByLocation.put(some_location, some_block_material);
    and to get from it use
    some_block.setType(materialByLocation.get(location_goes_here));

    Also remove it from the hashmap when you're done

    You may have to make another hashmap for saving the blocks data (for wool with colors and such)
    like HashMap<Location, Integer>
     
  3. Offline

    MordorKing78

  4. What do you mean?
    You just get the location you want, set the location with the current block type in the hashmap, change the block type and then whenever you want to later on grab the type from the hashmap and reset it.
     
  5. Offline

    MordorKing78

    @WD_MUFFINFLUFFER Do I have to make a new hashmap for everyblock? And how do I place the blocks back with the hashmpa?
     
  6. No you make one hashmap.
    With the hashmap you can use Bukkit.getWorld("WorldName").getBlockAt(some_location).setType(type_from_the_hashmap));
    I would google how hashmaps work if you dont already know

    Edit: Also you can just do Bukkit.getWorlds().get(0) to get the default world
     
  7. Offline

    WarmakerT

    Since you don't know how HashMaps works, you should learn about them. You will definitely need them sometime.
    I think making an ArrayList of BlockStates(block.getState()) would be the way to go. A BlockState is a clone of a block; it doesn't change when the block does.

    Code:
    ArrayList<BlockState> oldBlocks = new ArrayList<>();
    So you'd add every single one of those blocks with oldBlocks.add(block.getState()) .

    I'd look into using the WorldEdit API, since it's a lot easier and you don't need to have 20 lines of .setBlock().
    You can learn about it here.
     
  8. Offline

    MordorKing78

    Last edited: Dec 30, 2014
  9. Offline

    xize

    @MordorKing78

    my advise is just create a hashmap with the following types: Location, MaterialData as a final field.

    if you want to work with and data values and sub data values MaterialData is a good wrapper however if you work only with Materials use the Material class instead.

    now you can place all your contents inside with the put method.

    now to get the locations what you could do is using a Iterator from HashMap#entrySet().Iterator().
    an EntrySet gives you a fixed key and value back in return while you iterate over it.

    I hope it helps a bit or atleast points you to a direction ;-)
     
  10. Offline

    MordorKing78

    @xize I didn't know how to put in MaterialData? So I did Material.. Also I don't understand how I would place a block using your method? As far as I know you can get the Hashmap using the location..?
     
  11. Offline

    xize

    @MordorKing78

    I show you a semi psuodo example I hope you understand how generics work in a HashMap if not, its like a ArrayList everything inside the <> is the type, a HashMap has a key and a value so that means you could do <Location, SomethingElse> the something else could be a Material enum or a MaterialData for example thats the value and the location is a key, its always very important if you dont use it anymore to remove the key from the HashMap either through a Iterator or via a key.

    In this case the key is kinda harder to find so we use a Iterator instead.

    now my psuodo example:

    Code:
    Iterator<Entry<Location, Material>> it = hash.entrySet().iterator(); //if you cant import the Entry type for some reason use Map.Entry instead.
    
    while(it.hasNext()) {
           Entry<Location, Material> entry = it.next();
           entry.getK??.getBlock().setType(entry.getV???);
           it.remove(); // removes the key and value from the HashMap because the block was set.
    }
    
    its maybe also important to read the javadocs on oracle sadly my iphone refuses to paste the links as it just going to cancel it by spelling control D:
     
  12. Offline

    MordorKing78

    @xize Why is my key harder to find? because in this case players stay on the location.
     
  13. Offline

    xize

    @MordorKing78

    well it depends how you use it, if the player moves his yaw and you try to remove the key from the HashMap with that location it may doesn't detect because the location you use is slightly different/modified, it doesn't need to happen though but that is a possibility what could happen.

    however if you ignore the yaw and pitch in a location object by just using the block location (int x int y int z) where yaw is 0 and pitch is 0 you got a better chance of getting the keys correct, you can easily do that with p.getLocation().getBlock().getLocation().

    but since you also want to have it running in a scheduler perhaps is a Iterator a better choose?

    in a scheduler you can do something like:
    Code:
    if(it.hasNext()) {
        Entry<Location, Material> a = it.next(); //hops to next element.
        it.remove();
    }
    
    so with every scheduler tick it goes to a other element with a other location as key, however if you want to reuse it rather than removing it from the HashMap you can do:

    Code:
    if(it.hasNext()) {
        Entry<Location, Material> a = it.next(); //hops to next element.
       // it.remove();
    } else {
       it = hash.entrySet().iterator(); //instance the iterator again from start index.
    }
    
     
  14. Offline

    MordorKing78

    @xize I don't understand the Iterator at all. And I tried
    Code:
                                        p.getLocation().add(0, -1, 0).getBlock().setType(oldBlocks.get(p.getLocation().add(0, -1, 0)));
    
    and that didn't work at all..
     
  15. Offline

    xize

    @MordorKing78

    try:

    when placing in the HashMap:
    Code:
    Location loc = p.getLocation().getBlock().getRelative(BlockFace.DOWN).getLocation(); //does the same as -1 in your code but this uses the blocks coordinates not yaw and pitch
    hash.put(loc, Material.WOOL);
    
    now to get it from your code:
    Code:
    Location loc = p.getLocation().getBlock().getRelative(BlockFace.DOWN).getLocation(); //use block coords not the yaw and pitch from player
    if(hash.containsKey(loc)) {
          Block block = loc.getBlock();
          Material mat = hash.get(loc);
          block.setType(mat);
    }
    
    this should work ;-)

    -edit-
    edited the locations
     
    MordorKing78 likes this.
  16. Offline

    MordorKing78

    @xize Yes this works perfectly! Thanks bro! Also I have another question. Could I ask you another?
     
  17. Offline

    xize

  18. Offline

    MordorKing78

    @xize What I want to do is like when a player types a command he cant move anymore so I wanted to teleport him to a certain location. I will need to use a hashmap I think. How would I do that.

    COMMAND:
    Code:
    public class crate implements CommandExecutor{
        public Main plugin;
       
        public crate(Main plugin)
        {
            this.plugin = plugin;
        }
        HashMap<Location, Material> oldBlocks = new HashMap<Location, Material>();
     
        public int count = 0;
    
        public int i = 5;
    
        public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args){
            final Player p = (Player)sender;          
        
                                    // BLOCKS REMOVED
            p.sendMessage("§e§lCrates> §a§lYou placed an Crate! You have §c§l20§a§l seconds to open the Beacons before your crate explodes!");
    
            
         
            plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
                  public void run() {
                        Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, new BukkitRunnable () {
                            public void run(){
                                if(i!=-1){
                                    if( i != 0){
                                        p.sendMessage("§e§l" + i + "§c§l seconds left until the Crate explodes!");
                                        i--;
                                    }else{
                                    // BLOCKS REMOVED
                                     
                                        p.getWorld().playEffect(p.getLocation(), Effect.EXPLOSION_HUGE, 0);
    
                                        p.sendMessage("§c§lCrate has been Exploded!");
                                        i--;
                                    }
                                }
                            }
                        }, 0L, 20L);
                  }
            }, 20 * 15);
                 
            Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, new BukkitRunnable () {
                public void run() {
                      if(count > 40) {
                        this.cancel();
                        return;
                      }
                      else {
                          p.getWorld().playEffect(p.getLocation().add(0, 1, 3), Effect.MOBSPAWNER_FLAMES, 0);
                          p.getWorld().playEffect(p.getLocation().add(0, 1, -3), Effect.MOBSPAWNER_FLAMES, 0);
                          p.getWorld().playEffect(p.getLocation().add(3, 1, 0), Effect.MOBSPAWNER_FLAMES, 0);
                          p.getWorld().playEffect(p.getLocation().add(-3, 1, 0), Effect.MOBSPAWNER_FLAMES, 0);
                          count++;
                      }
                }
          }, 0, 10);
            return true;
        }
    }
    
     
  19. Offline

    xize

    @MordorKing78

    hmm that depends should the location be different for each player firing that command or is it the same location over all players firing that command?

    if its the same location for all players you could use a HashSet<String> its almost the same as a ArrayList however a HashSet doesn't allow duplicates which is very handy, or you could add metadata to the player object (if you are lazy) and check in the PlayerMoveEvent if the player has that metadata attached/or you can lookup in the HashSet it self.

    if you plan to store players with different teleport locations then it may is suiteable to use a HashMap like HashMap<String, Location> however in that case you may need to make some factory design or a getter in your listener note the same way should be done with a HashSet to.

    either way I dont recommend to use HashMap or HashSet used being static as in a field term.

    //TL;TR
    its better to make the whole class static as in a manager way and only return it once (so not that it is being double instanced), what I always use is this in my main class since I think its one of the better solutions if your aren't able to use a setter or a constructor for like in a event without causing static fields, or you want to reuse the same data everytime again without causing to much performance in events such like PlayerMoveEvent a manager system with setters and getters work in my opinion better.

    but now why are static fields or to much usage of static bad?, I generaly think (from my own opinion) from each class you would process a static call that class stores a copy of each static object which is actually not good because they are anonymous and cannot be connected to any class you called it from that also could mean that one copy differs with a other static copy of a other call meaning that perhaps one HashSet says that the object is removed whilst the other says it exists, I never got this experienced myself but ive readed these subjects alot on other sites, maybe Im completely wrong or partialy wrong atleast its important to know to try to avoid static as most of possible it causes bad coding habbits.

    //end TL;TR

    I think in theory its more effective to e.g instance the class once as in a static way which maintain your HashSet or HashMap or maybe a wrapper as in a manager context, else try to avoid static as much as possible, if it is possible to use setters or constructors you should use those, yet I cant find a otherway for command->events without causing static fields.

    this is for example (I think a good way):

    Code:
    public class Yourplugin extends JavaPlugin {
    
        private final HashSet<String> explosions = new HashSet<String>();
    
        public void onEnable() {
    
        }
    
        public void onDisable() {
    
        }
    
        public HashSet<String> getExplosionData() {
                 return explosions;
        }
    
        public static Yourplugin getPlugin() {
               return Yourplugin.getPlugin(Yourplugin.class);
        }
    
    }
    
    which mean that you can access the HashSet from every outside class by just using:
    Code:
    Yourplugin.getPlugin().getExplosionData();
    
    however Im not sure if the static way of getPlugin(class clazz) returns everytime a new singleton else you may want to cache it.

    sorry for the long responds:p
     
Thread Status:
Not open for further replies.

Share This Page