Events/BlockEvent

Revision as of 18:46, 20 April 2021 by EERussianguy (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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)
    {
        IWorld world = event.getWorld();
        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.getMainHandItem().getItem().equals(Items.DIAMOND_SHOVEL)) // check what we're holding
            {
                ItemHandlerHelper.giveItemToPlayer(player, new ItemStack(Items.BONE)); // give a bone
            }
        }
    }

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)
    {
        IWorld world = event.getWorld();
        if (!world.isClientSide() && event.getEntity() instanceof EndermanEntity)
        {
            event.setCanceled(true); // prevent enderman placement
        }
    }

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)
    {
        IWorld world = event.getWorld();
        if (world.isClientSide()) return;
        BlockPos eventPos = event.getPos();
        if (event.getState().is(Blocks.REDSTONE_WIRE)) // only do it for redstone
        {
            for (Direction direction : event.getNotifiedSides()) // cycle through notified directions
            {
                BlockPos pos = eventPos.relative(direction); // move to that spot
                if (world.isEmptyBlock(pos))
                {
                    world.setBlock(pos, Blocks.GLOWSTONE.defaultBlockState(), 3); // place glowstone
                }
            }
        }
    }

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 onFluidSourceCreate(final BlockEvent.CreateFluidSourceEvent event)
    {
        IWorldReader world = event.getWorld();
        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)
    {
        IWorld world = event.getWorld();
        if (world.isClientSide()) return;
        BlockState newState = event.getNewState();
        if (newState.is(Blocks.COBBLESTONE) && world.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)
    {
        IWorld world = event.getWorld();
        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 (world.getRandom().nextFloat() > 0.2F) // take a 4/5 chance
            {
                event.setResult(Event.Result.DENY); // make bamboo grow less often
            }
        }
    }

public void onCropsGrowPost(final BlockEvent.CropGrowEvent.Post event)
    {
        IWorld world = event.getWorld();
        if (!world.isClientSide() && event.getState().is(Blocks.WHEAT)) // check wheat
        {
            BlockState newState = event.getState();
            if (newState.is(Blocks.WHEAT)) // defensive check to make sure we can do this
            {
                world.setBlock(event.getPos(), newState.setValue(CropsBlock.AGE, 7), 3); // set max growth wheat
            }
        }
    }

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)
    {
        IWorld world = event.getWorld();
        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).

Example usage:

public void onPortalLight(final BlockEvent.PortalSpawnEvent event)
    {
        event.setCanceled(true);
    }

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. This will normally just return whatever the original block is unless you or another modder has set it. It can't check, for example, if something *will* turn into farmland in the future.

Example usage:

public void onToolInteract(final BlockEvent.BlockToolInteractEvent event)
    {
        IWorld world = event.getWorld();
        if (!world.isClientSide() && event.getHeldItemStack().getItem() == Items.NETHERITE_HOE)
        {
            event.setFinalState(Blocks.NETHERRACK.defaultBlockState()); // set the block to netherrack
            // note that this happens for any right click on a block, not just dirt
        }
    }

Some ideas for using this:

  • Setting your custom farmland block during tilling
  • Adding stripped wood behavior for other blocks
  • Disable path creation