Solved Get block at Cursor Location

Discussion in 'Plugin Development' started by JavaNoob, Oct 22, 2020.

  1. Offline

    JavaNoob

    Hi! I wanted to start trying again to make a plugin that involves changing the blocks that a player looks at. But I don't know how to get that block. It doesn't matter how far or close the block is, how would i get the block that the cursor is currently on? I already tried the getEyeLocation(), but that just spawns it on top of my head. (Unless I am doing something wrong.) Thanks!

    Edit: I just thought of something. If I set the block to bedrock at the getEyeLocation(), does it include air blocks? Because that might have been why it spawned on my head. Because I forgot to exclude air blocks.
     
    Last edited: Oct 22, 2020
  2. Offline

    spuddy

    I think it's Player.getTargetBlock(Set<Material> filter, int rangeLimit);

    filter can be null, which will ignore only Air blocks.
     
    Last edited: Oct 22, 2020
  3. Offline

    Strahan

    I found this code over at SpigotMC, it's what I use for that purpose:
    Code:
    public final Block getTargetBlock(Player player, int range) {
      BlockIterator iter = new BlockIterator(player, range);
      Block lastBlock = iter.next();
      while (iter.hasNext()) {
        lastBlock = iter.next();
        if (lastBlock.getType() == Material.AIR) continue;
        break;
      }
      return lastBlock;
    }
     
  4. Offline

    JavaNoob

    Thank you, I will try it!

    Edit: It worked, and I tested it before. But I think I created an infinite loop and it crashed the server. I can't see anything, I thought I had closed all the holes.

    Code:
     
    @Override
    
        public void onEnable(){
    
            Bukkit.getPluginManager().registerEvents(this, this);
    
        }
    
       
    
    
    
        public final Block getTargetBlock(Player player, int range){
    
        Block Iterator iter = newBlockIterator(player, range);
    
          Block lastBlock=iter.next();
    
          while(iter.hasNext()){
    
          lastBlock=iter.next();
    
            if(lastBlock.getType() == Material.AIR) continue;
    
            break;
    
              }
    
          return last Block;
    
        }
    
        boolean a = true;
    
        @Override
    
        public boolean onCommand(CommandSender sender, Command cmd, String lable, String[] args) {
    
            if (sender instanceof Player){
    
                if (cmd.getName().equals("start")){
    
                    Player player = (Player) sender;
    
                    while (player.isOnline() & a == true) {
    
                        Block b = (Block) getTargetBlock(player, 10000);
    
                        if (!(b.getType() == Material.BEDROCK)) {
    
                            b.setType(Material.BEDROCK);
    
                        }
    
                    }
    
                }
    
                if (cmd.getName().equals("stop")){
    
                    a = false;
    
                }
    
               
    
            }
    
           
    
            return false;
    
        }
    
    
     
    Last edited: Oct 22, 2020
  5. Offline

    PureAspiration

    You can use:
    Code:
    Player player = event.getPlayer();
    Block block = player.getTargetBlock(null, 50);
    You can change the 50 to whatever range you need.
     
  6. Offline

    Strahan

    Ah, yea, you can't do it that way. Minecraft has multiple threads, but the core of the work runs on a single thread so your command will block that thread and everything will freeze. First thought would be a runnable, but performing block changes async is not recommended.

    One option would be to use the PlayerMoveEvent to check when they move their head. However that will be ran a lot and I've personally never did any lag testing on the get block method I posted as I have never used it continuously so just be careful of that.
     
  7. Offline

    JavaNoob

    Ok, thank you. I will change it up, and will try again.

    Thank you

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Oct 23, 2020
  8. Offline

    davidclue

    Use a repeating task to check every tick or so if the player is looking at the specific block and cancel the task when you want it to stop. That is the best way as with PlayerMoveEvent it will only update when the player moves and if someone lets say is standing still and not moving and a block is placed in front of where their cursor is pointed then until they move their mouse or touch their keyboard the method won't run.
     
  9. Offline

    JavaNoob

    I got it to work, but I want it so that whenever they look at a block, it won't change until they look away from it. I have tried a bunch of different things, bit everything I try either lags out the server, or won't work. Here is what I have currently, if you could figure it out.

    Code:
    @Override
    
        public void onEnable() {
    
            Bukkit.getPluginManager().registerEvents(this, this);
    
        }
    
        Location a = null;
    
        public final Block getTargetBlock(Player player, int range) {
    
        BlockIterator iter = newBlockIterator(player, range);
    
          Block lastBlock = iter.next();
    
          while(iter.hasNext()){
    
          lastBlock = iter.next();
    
            if(lastBlock.getType() == Material.AIR) continue;
    
            break;
    
              }
    
          return lastBlock;
    
        }
    
    
    
        @EventHandler
    
        public void  onMove(PlayerMoveEvent event){
    
            Player player = (Player) event.getPlayer();
    
            if(getTargetBlock(player, 100).getLocation() != a){
    
                getTargetBlock(player,100).setType(Material.BEDROCK);
                a=getTargetBlock(player,100).getLocation();
    
            }
    
        }
    
    I realized as I am posting this that it would just change the block that I immediately look at to bedrock, but I can't think of anything because I am really tired.

    (White space may be missing because of formatting)
     
  10. Offline

    davidclue

    Coding in bukkit you can't use while loops because that breaks the server, instead use a repeating task and the best way to do that at least for me is with an abstract class
    Code:
    import org.bukkit.Bukkit;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public abstract class RepeatingTask implements Runnable {
    
        private int taskId;
    
        public RepeatingTask(JavaPlugin plugin, int arg1, int arg2) {
            taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, this, arg1, arg2);
        }
        public void cancel() {
            Bukkit.getScheduler().cancelTask(taskId);
        }
    }
    And then to use this for repeating tasks like this
    Code:
    RepeatingTask repeatingTask = new RepeatingTask(plugin, 0, 20) { //0 is for the initial delay and 20 is for the amount of ticks till it repeats, both are in ticks: 20 ticks = 1s
            @Override
            public void run() {
                //run code here to be repeated
               
                //use "cancel();" to end the task when you are done with it
            }
        };
    This is a good way and just have it repeat every tick a loop through the players and check using
    Code:
    Block block = player.getTargetBlock(null, 50);
    to get the block they are looking at, then just simply
    Code:
    if (b.getType() == Material.Bedrock) {
            //run this if player is looking at bedrock
        }
    And don't forget to call "cancel()" inside the task when you are done with it.
     
  11. Offline

    JavaNoob

    Okay, thank you!
     

Share This Page