ChangeBlockEvent only for Blocks changed by a player

Hey,
I noticed, that there is a problem with the ChangeBlockEvent and my plugin…
it’s not a bug, it’s just something I want to avoid.

@Listener
public void onBlockChange(ChangeBlockEvent event) {

Optional<Player> optPlayer = event.getCause().first(Player.class);
if (optPlayer.isPresent()) {
	if (event instanceof ChangeBlockEvent.Place || event instanceof ChangeBlockEvent.Break) {
		logger.info("only if player really places / breaks a block")
	}
}

Problem: logger.info("only if player really places / breaks a block") gets not only called, when a player really places / breaks a block with a mouse-click.
I think, this gets called also, if new chunks get generated and the given player is the cause for it…

I don’t know, if this is the exact cause, but I know, that it gets called, even if the player doesn’t place or break blocks. (this spams a player without any sense, because my plugin would say “You are not permitted to build here!”)

So how can I avoid this? I need something like a “mouse click checker” like I can use it when I work with InteractBlockEvent, but I don’t want to use InteractBlockEvent.

Greets :slightly_smiling:

You can do the following:

@Listener
@IsCancelled(Tristate.FALSE)
public void onBlock(@Include({ChangeBlockEvent.Place.class, ChangeBlockEvent.Break.class}) ChangeBlockEvent event, @Root Player player) {
  logger.info("Only filtering when the root is a player and the event is a Place or Break!");
  // do stuff
}

This is a little bit of what you are doing but event filtering does this all for you without needing to check optionals and such. The root cause would be the Player object included, but in the case of chunk generation, the root wouldn’t (should be afaik, unless @Deamon or @Zidane can correct me on this) be the Player object, but rather it could be the Chunk, World or Server. The filter @Root enforces the check that the root of the Cause is actually a type of that class (in this case a Player object), and if that check succeeds, then this event listener is actually called.

2 Likes

Thanks :slightly_smiling:
There is a little problem with your code (?), because I get '@Include' not applicable to parameter , when I try to use it.
How can I fix this issue? (not important for me, because I have to check anyway, if it’s a break / place, but maybe, other folks want to use it like this…)
Greets :slight_smile:

1 Like

If you have to check that anyway if its place/break you actually should make 2 Listener methods, i think: :wink:

@Listener
@IsCancelled(Tristate.FALSE)
public void onBlock(ChangeBlockEvent.Place event, @Root Player player) {
  logger.info("Only filtering when the root is a player and the event is a Place!");
  // do stuff
}

@Listener
@IsCancelled(Tristate.FALSE)
public void onBlock(ChangeBlockEvent.Break event, @Root Player player) {
  logger.info("Only filtering when the root is a player and the event is a Break!");
  // do stuff
}

Yeah I know, but I also can check it by using if(event instanceof ChangeBlock.Break) and if(event instanceof ChangeBlock.Place) in one listener :slightly_smiling:

Yep, but the 2 Listener method should be faster (and is more organized but that’s personal preference ^^) :stuck_out_tongue:

Atm I can’t decide, which one looks better, but I think, I will use your format, like I did it before :smiley:

1 Like