/*
* The notch client's packet sending is weird. Here's how it works: If the client is clicking a block not in range, sends a packet with x=-1,y=255,z=-1 If the client is clicking a block in
* range with an item in hand (id > 255) Sends both the normal block placement packet and a (-1,255,-1) one If the client is placing a block in range with a block in hand, only one normal
* packet is sent That is how it usually happens. Sometimes it doesn't happen like that. Therefore, a hacky workaround.
*/
final BlockFace clickedFace = message.getDirection();
Hunger hunger = player.add(Hunger.class);
if ((holdingMat instanceof Food && hunger.getHunger() != VanillaData.HUNGER.getDefaultValue()) || holdingMat instanceof Sword || (holdingMat instanceof PotionItem && !((PotionItem) holdingMat).isSplash())) {
player.get(Living.class).setEatingBlocking(true);
hunger.setEating(true, currentSlot);
return;
}
if (clickedFace == BlockFace.THIS) {
// Right clicked air with an item.
PlayerInteractBlockEvent event = Spout.getEventManager().callEvent(new PlayerInteractBlockEvent(player, null, null, clickedFace, Action.RIGHT_CLICK));
// May have been changed by the event
holding = currentSlot.get();
holdingMat = holding == null ? null : holding.getMaterial();
if (holdingMat != null) {
holdingMat.onInteract(player, Action.RIGHT_CLICK);
}
} else {
// TODO: Validate the x/y/z coordinates of the message to check if it is in range of the player
// This is an anti-hack requirement (else hackers can load far-away chunks and crash the server)
// Get clicked block and validated face against it was placed
final Block clickedBlock = world.getBlock(message.getX(), message.getY(), message.getZ());
final BlockMaterial clickedMaterial = clickedBlock.getMaterial();
// Perform interaction event
PlayerInteractBlockEvent interactEvent = Spout.getEventManager().callEvent(new PlayerInteractBlockEvent(player, clickedBlock, clickedBlock.getPosition(), clickedFace, Action.RIGHT_CLICK));
// May have been changed by the event
holding = currentSlot.get();
holdingMat = holding == null ? null : holding.getMaterial();
// check if the interaction was cancelled by the event
if (interactEvent.isCancelled()) {
refreshClient(player, clickedBlock, clickedFace, rm);
return;
}
if (holdingMat != null) {
holdingMat.onInteract(player, clickedBlock, Action.RIGHT_CLICK, clickedFace);
}
clickedMaterial.onInteract(player, clickedBlock, Action.RIGHT_CLICK, clickedFace);
// If the holding material can be placed, place it
if (holdingMat instanceof Placeable) {
Cause<?> cause = new PlayerClickBlockCause(player, clickedBlock);
short placedData = holding.getData(); // TODO: shouldn't the sub-material deal with this?
Placeable toPlace = (Placeable) holdingMat;
final Block placedBlock;
final BlockFace placedAgainst;
final boolean placedIsClicked;
// For snow, tall grass, and the like, place at the clicked block
final BlockFace clickedAgainst;
if (!clickedBlock.getMaterial().isPlacementObstacle() && BlockFaces.NESW.contains(clickedFace)) {
clickedAgainst = BlockFace.BOTTOM;
} else {
clickedAgainst = clickedFace.getOpposite();
}