Events/BlockEvent
The variations of BlockEvent
let modders intercept interactions between the player and blocks in the world. All of these events have in common the following: the World
the action was taken in, and the BlockPos
and BlockState
that's being modified.
BreakEvent
This event is fired before a block is broken by a player. Predictably, cancelling this event prevents the block from getting broken. Modders have two extra variables to play with:
getExpToDrop()
: Returns how much experience ought to drop when the block is broken. Will be zero if the event is currently canceled.
setExpToDrop()
: Sets the experience that's going to drop manually.
getPlayer()
: Gets the player that's doing the action.
Example usage:
public void onBlockBreak(final BlockEvent.BreakEvent event) { if (!world.isClientSide() && event.getState().is(Blocks.SAND)) // use the base event to get the state and see what it is { event.setExpToDrop(10); // change the amount of experience we'll be dropping PlayerEntity player = event.getPlayer(); if (player.getUseItem().getItem().is(Items.SHEARS)) // check if the player is holding shears { ItemHandlerHelper.giveItemToPlayer(player, new ItemStack(Items.BONE)); // give a bone to the player! } } }
Some ideas for using this event:
- Stopping players from breaking a block
- Changing the XP drop of a vanilla block
- Modify the behavior of a tool
EntityPlaceEvent
This event is called when a block is placed.
getEntity()
: This is the entity placing the block. Note that this might not be a player! It can be null. This means you should null check the entity. By default, Forge adds this in three places: players placing blocks, endermen placing their held block, as well as ice placed by the Frost Walker enchantment.
getBlockSnapshot()
: Gets the snapshot of what's about to be placed. A BlockSnapshot
is just an object containing the dimension, position, NBT, and state of a block, along with some other info. Typically, this isn't necessary.
getPlacedBlock()
The BlockState
to be placed.
getPlacedAgainst()
The BlockState
that was clicked in order to place the block. Imagine planting a flower on some dirt. The dirt would be the state here.
Example usage:
public void onEntityPlace(final BlockEvent.EntityPlaceEvent event) { Entity entity = event.getEntity(); if (!world.isClientSide() && entity != null) // check if the entity is null { Block block = event.getState().getBlock(); // get the block that was placed if (entity instanceof PlayerEntity && block.is(Blocks.FROSTED_ICE)) { event.setCanceled(true); // cancel the placing event.getWorld().setBlock(event.getPos(), Blocks.COBBLESTONE.defaultBlockState(), 3); // set cobble instead } } }
Some ideas for using this event:
- (See above) Changing how frost walker works based on certain conditions
- Preventing a block from being placed
- Changing the player's inventory when a block is placed
- Cause another block to be placed instead of another
EntityMultiPlaceEvent
This is the same as above except it's fired when a block causes another block to be replaced. A great example is beds, where placing one half of the bed causes another half to be placed.
getReplacedBlockSnapshots()
: Everything is the same as before, except we now have a list of snapshots. How sweet.
NeighborNotifyEvent
This event is fired when a block tells its neighbors to update themselves. This happens all the time, typically with redstone blocks like tripwires or repeaters.
getNotifiedSides()
: A set of Direction
values that were updated during the event. Sometimes, blocks will choose to exclude a side from being updated, but most often this will be all six directions.
getForceRedstoneUpdate()
This is a little funky. There's an option when blocks are set to force a redstone update. If that happened, this will be true. You typically won't need this.
Example usage:
public void onNeighborNotify(final BlockEvent.NeighborNotifyEvent event) { if (world.isClientSide()) return; BlockPos eventPos = event.getPos(); for (Direction direction : event.getNotifiedSides()) // cycle through notified directions { BlockPos pos = eventPos.relative(direction); // move to the direction given double x = pos.getX() + 0.5D; // move to center of the block double y = pos.getY() + 0.5D; double z = pos.getZ() + 0.5D; // add particle event.getWorld().addParticle(ParticleTypes.CLOUD, x, y, z, 0.0D, 0.0D, 0.0D); } }
Some ideas for using this event:
- Adding blocks that interact with redstone
- Making a block update detector block
CreateFluidSourceEvent
This event controls creation of fluid sources. This is different than cancellable events, because it has a Result
. Setting it to ALLOW
causes a source block to created, even if that's not normally what would happen. Setting it to DENY
always prevents source creation.
Example usage:
public void onNeighborNotify(final BlockEvent.CreateFluidSourceEvent event) { if (!world.isClientSide() && event.getPos().getY() > 100) { event.setResult(Event.Result.DENY); // prevent source creation above y = 100 } }
FluidPlaceBlockEvent
This event fires when fluids place blocks. Examples of this happening are: basalt, stone, cobblestone, obsidian, and fire (think lava pools). You can cancel this event to prevent placement.
getLiquidPos()
This is the liquid's position. For cases like cobble generation, this is the same as the original getPos()
. But for placing fire, this won't be the same.
getNewState()
Gets the state to be placed.
setNewState()
Sets the state to be placed.
getOriginalState()
What the block was before this event.
Example usage:
public void onFluidPlace(final BlockEvent.FluidPlaceBlockEvent event) { if (world.isClientSide()) return; BlockState newState = event.getNewState(); if (newState.is(Blocks.FIRE)) { event.setCanceled(true); // prevent fire placing from lava } else if (newState.is(Blocks.COBBLESTONE) && event.getWorld().dayTime() > 14000L) { event.setNewState(Blocks.ANDESITE.defaultBlockState()); // change the block if done during nighttime. } }
Some ideas for using this event:
- Changing behavior of cobble generators
- Preventing cobble generators
- Adding more aggressive effects during fire spreading from lava
CropGrowEvent
These events are fired during crop growth. The Pre
event is fired before. It's fired when vanilla blocks try to 'grow' during random ticks (think cacti getting taller). Setting DEFAULT
as the result will cause no change. Setting ALLOW
forces growth. Setting DENY
prevents growth.
The Post
event is fired after growth.
getOriginalState()
Get the state before growth happened.
Example usage:
public void onCropGrowPre(final BlockEvent.CropGrowEvent.Pre event) { if (world.isClientSide()) return; BlockState state = event.getState(); if (state.is(Blocks.WHEAT)) { event.setResult(Event.Result.DENY); // prevent wheat from growing } else if (state.is(Blocks.BAMBOO)) { if (event.getWorld().getRandom().nextFloat() > 0.2F) // take a 4/5 chance { event.setResult(Event.Result.DENY); // make bamboo grow less often } } }
Some ideas for using this event:
- Changing growth rate of crops
- Preventing crop growth under certain conditions
- Spawning an entity when something grows
FarmlandTrampleEvent
This event is fired when farmland gets trampled. You can cancel it to prevent trampling.
getEntity()
The entity that trampled
getFallDistance()
How far that entity fell
Example usage:
public void onTrample(final BlockEvent.FarmlandTrampleEvent event) { if (!world.isClientSide() && event.getFallDistance() < 10.0F) { event.setCanceled(true); // change conditions for trampling } }
PortalSpawnEvent
This event is fired when a nether portal is created.
getPortalSize()
returns a PortalSize
object, basically only useful for determining if the portal is going to be valid or not.
This is mostly used for preventing portal spawning in certain dimensions (even the overworld).
BlockToolInteractEvent
This event is fired on right click tool events, such as path creation, wood stripping, and farmland tilling. You have access to the player, the ItemStack
they're holding, and the ToolType
they have.
setFinalState()
: Set what you want the result to be.
getFinalState()
: Returns what it will be changed to.
Example usage:
public void onToolInteract(final BlockEvent.BlockToolInteractEvent event) { if (!world.isClientSide() && event.getFinalState().is(Blocks.FARMLAND) && event.getHeldItemStack().getItem() == Items.NETHERITE_HOE) { event.setFinalState(Blocks.NETHERRACK.defaultBlockState()); // change the final state under certain conditions } }
Some ideas for using this:
- Setting your custom farmland block during tilling
- Adding stripped wood behavior for other blocks
- Disable path creation