2

I'm making a Bukkit plugin that will change the block underneath any player to glowstone.

The scheduler isn't working. The ground will change to glowstone but the glowstone block won't revert back to what it originally was.

@EventHandler
public void onStep(PlayerMoveEvent pme) {
    Player player = pme.getPlayer();
    Location locUnderPlayer = player.getLocation();
    locUnderPlayer.setY(locUnderPlayer.getY() - 1);
    Location locForScheduler = player.getLocation();
    locForScheduler.setY(locForScheduler.getY() + 1);
    final Material materialForScheduler = locForScheduler.getBlock().getType();
    Block block = locUnderPlayer.getBlock();
    Material m = player.getItemInHand().getType();
    if (m == Material.GLOWSTONE) {
        if (block.getType() != Material.AIR && block.getType() != Material.WATER && block.getType() != Material.STATIONARY_WATER && block.getType() != Material.LAVA && block.getType() != Material.STATIONARY_LAVA && block.getType() != Material.REDSTONE_WIRE && block.getType() != Material.REDSTONE_COMPARATOR && block.getType() != Material.REDSTONE_TORCH_ON && block.getType() != Material.REDSTONE_TORCH_OFF) {
            block.setType(Material.GLOWSTONE);
            Bukkit.getScheduler().scheduleSyncDelayedTask(Magic.getInstance(), new Runnable() {
                public void run() {
                    block.setType(materialForScheduler);
                }
            }, 1 * 10);
        }
    }
}
spongebob
  • 8,370
  • 15
  • 50
  • 83
user3397648
  • 39
  • 1
  • 5
  • Is the block supposed to change back 10 ticks after the players ENTERS the block, or 10 ticks after he LEAVES it? – Dorus Feb 03 '15 at 18:06

4 Answers4

8

To get the block underneath a player, you could use:

Block block = player.getLocation().subtract(0, 1, 0).getBlock();

Which gets the player's location, subtracts 1 from the Y-axis, and then gets the block (hence getting the block under the player).

Then to get the type, you could use block.getType():

Material type = block.getType();

To set the block to glowstone, you could use block.setType(Material):

block.setType(Material.GLOWSTONE);

So, if you wanted to set the block under a player to glowstone, then immediately turn it back to the original block, you could use:

Block block = player.getLocation().subtract(0, 1, 0).getBlock(); //get the block
Material type = block.getType(); //get the block's type
block.setType(Material.GLOWSTONE); //set the block's material to glowstone
block.setType(type); //set the block's material back to the original material

But to have a delay between setting the block to glowstone then setting it back to the original block (in your case, the delay is 10 ticks) you could use a Runnable task:

final Block block = player.getLocation().subtract(0, 1, 0).getBlock(); //get the block
final Material type = block.getType(); //get the block's type

block.setType(Material.GLOWSTONE); //set the block's material to glowstone

Bukkit.getScheduler().runTaskLater(Magic.getInstance(), new Runnable(){
  public void run(){
    block.setType(type); //set the block back to the original block
  }
},10L);

We would want to make sure that the block beneath the player is not already glowstone, to insure that the block change does not become permanent. This could be done using simply:

if(!type.equals(Material.GLOWSTONE))

If we did not check for this, then a player could move with glowstone in their hand, hence setting the block underneath them to glowstone, and then starting a timer to set it back to the original block. But, if the player moves while the timer is in session (for example, 5 ticks after they last moved), the block underneath them would permanently change to glowstone.

So, your code could look something like this:

@EventHandler
public void onStep(PlayerMoveEvent pme) {
  Player player = pme.getPlayer(); //get the player in the event
  final Block block = player.getLocation().subtract(0, 1, 0).getBlock(); //get the block
  final Material type = block.getState().getType(); //get the block's material
  if(!type.equals(Material.GLOWSTONE)){//don't change the block if it's already glowstone
    if(player.getItemInHand() != null){//make sure the item in the player's hand is not null, to avoid a null pointer
      Material m = player.getItemInHand().getType(); //get the item in the player's hand
      if(m == Material.GLOWSTONE){ //check if the item in the player's hand is glowstone
        if(type != Material.AIR && type != Material.WATER && type != Material.STATIONARY_WATER && type != Material.LAVA && type != Material.STATIONARY_LAVA && type != Material.REDSTONE_WIRE && type != Material.REDSTONE_COMPARATOR && type != Material.REDSTONE_TORCH_ON && type != Material.REDSTONE_TORCH_OFF){
          block.setType(Material.GLOWSTONE);//set the block type to glowstone
          Bukkit.getScheduler().runTaskLater(Magic.getInstance(), new Runnable() {
            public void run(){
              block.setType(type); //set the block type back to the original type
            }
          },10L);
        }
      }
    }
  }
}

Also, you could reduce this if statement:

if(type != Material.AIR && type != Material.WATER && type != Material.STATIONARY_WATER && type != Material.LAVA && type != Material.STATIONARY_LAVA && type != Material.REDSTONE_WIRE && type != Material.REDSTONE_COMPARATOR && type != Material.REDSTONE_TORCH_ON && type != Material.REDSTONE_TORCH_OFF)

into simply type.isSolid():

if(type.isSolid())
Jojodmo
  • 23,357
  • 13
  • 65
  • 107
  • 1
    Does this work? A couple problems come to mind when I read this code: When a player leaves the block and returns within 10 ticks, the block will be converted to glowstone permanently 10 ticks later. Also, this convert the block back to original independent of how long the player has been stationary on the block, is that intended? (Notice I did not test this code, just reading it) – Dorus Feb 03 '15 at 13:53
  • @Dorus It actually isn't dependent on where the player is (notice how the block below the player is stored). If the player moves within the 10 ticks, it will still be converted back to the original – Jojodmo Feb 03 '15 at 15:48
  • 1) I mean, the player leaves block A, leaving process 1 running, he returns to block A 5 ticks later, starting process 2, A will then be stored as a Glowstone. Another 5 ticks later it's restored to dirt by process 1, but (permanently) changed to Glowstone again by process 2 after another 5 ticks. – Dorus Feb 03 '15 at 15:54
  • 2) Players enter block A, starting process 1, and wait 5 ticks, then leaves. 5 ticks later block A convert back to dirt. However, had the player waited 8 ticks, block A returns 2 ticks later. Had the player waited 12 ticks, the block would already be converted back. – Dorus Feb 03 '15 at 15:55
  • #1 makes sense, thank you, I just updated the answer... I don't really understand why #2 is a problem though. I think the OP wants to convert it back in 10 ticks no matter what – Jojodmo Feb 03 '15 at 17:23
  • #1 is probably what the OP ran into yes. #2 could be by design, guess the OP need to answer that one. +1 cause i think this is a valid solution now. – Dorus Feb 03 '15 at 18:05
0
@EventHandler(priority = EventPriority.MONITOR)
public void onMonitor(PlayerMoveEvent event) {
    if (!event.isCancelled()) {
        Player player = event.getPlayer();
        if (player.getItemInHand().getType() == Material.GLOWSTONE) {
            Block block = event.getTo().subtract(0D, 1D, 0D).getBlock();
            Material type = block.getType();
            if (type.isSolid()) {
                if (!Restore.locked.contains(block)) {
                    Restore restore = new Restore(block, type, block.getData());
                    block.setType(Material.GLOWSTONE);
                    restore.runTaskLater(Plugin, 10L);
                }
            }
        }
    }
}

public class Restore extends BukkitRunnable {
    public static Set<Block> locked = new HashSet<Block>();
    private Block block;
    private Material type;
    private byte data;
    public Restore(Block block, Material type, byte data) {
        this.block = block;
        this.type = type;
        this.data = data;
        locked.add(block);
    }
    @Override
    public void run() {
        block.setType(type);
        block.setData(data);
        locked.remove(block);
    }
}
spongebob
  • 8,370
  • 15
  • 50
  • 83
0

The issue is because you are not checking if the block is already glowstone. So if you are running a temporary glowstone through the code, it will become permanent.

k3v
  • 119
  • 1
  • 11
0

EDIT: Late huh, my bad well I guess anyone else could use it There's another option:

1) get block under player

Block block = (player.getWorld, player.getLocation().getX(), 
    ,player.getWorld, player.getLocation().getY()-1,
    ,player.getWorld, player.getLocation().getZ());

2) get the block and save it as a block state

Blockstate bs = block.getState();

3) set the block to glowstone

block.setType(Material.GLOWSTONE);

4) this reverts it back to its last saved state

bs.update(true)

5) (if you want) create a delay

Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this new Runnable() {
          public void run() {
   //put delayed code here
   bs.update(true);

}
            }, 20 * seconds);
J22929
  • 5
  • 2