499 lines
16 KiB
Java
499 lines
16 KiB
Java
/*
|
|
* Minecraft Forge
|
|
* Copyright (c) 2016-2020.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation version 2.1
|
|
* of the License.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
package net.minecraftforge.event.world;
|
|
|
|
import java.util.EnumSet;
|
|
import java.util.List;
|
|
|
|
import net.minecraft.block.NetherPortalBlock;
|
|
import net.minecraft.block.PortalSize;
|
|
import net.minecraft.block.BlockState;
|
|
import net.minecraft.enchantment.EnchantmentHelper;
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.entity.player.PlayerEntity;
|
|
import net.minecraft.enchantment.Enchantments;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.util.NonNullList;
|
|
import net.minecraft.util.math.BlockPos;
|
|
import net.minecraft.util.Direction;
|
|
import net.minecraft.world.IWorld;
|
|
import net.minecraft.world.IWorldReader;
|
|
import net.minecraft.world.World;
|
|
import net.minecraftforge.common.ForgeHooks;
|
|
import net.minecraftforge.common.ToolType;
|
|
import net.minecraftforge.common.util.BlockSnapshot;
|
|
import net.minecraftforge.eventbus.api.Cancelable;
|
|
import net.minecraftforge.eventbus.api.Event;
|
|
|
|
import com.google.common.collect.ImmutableList;
|
|
|
|
import javax.annotation.Nonnull;
|
|
import javax.annotation.Nullable;
|
|
|
|
import net.minecraftforge.eventbus.api.Event.HasResult;
|
|
|
|
public class BlockEvent extends Event
|
|
{
|
|
private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("forge.debugBlockEvent", "false"));
|
|
|
|
private final IWorld world;
|
|
private final BlockPos pos;
|
|
private final BlockState state;
|
|
public BlockEvent(IWorld world, BlockPos pos, BlockState state)
|
|
{
|
|
this.pos = pos;
|
|
this.world = world;
|
|
this.state = state;
|
|
}
|
|
|
|
public IWorld getWorld()
|
|
{
|
|
return world;
|
|
}
|
|
|
|
public BlockPos getPos()
|
|
{
|
|
return pos;
|
|
}
|
|
|
|
public BlockState getState()
|
|
{
|
|
return state;
|
|
}
|
|
|
|
/**
|
|
* Event that is fired when an Block is about to be broken by a player
|
|
* Canceling this event will prevent the Block from being broken.
|
|
*/
|
|
@Cancelable
|
|
public static class BreakEvent extends BlockEvent
|
|
{
|
|
/** Reference to the Player who broke the block. If no player is available, use a EntityFakePlayer */
|
|
private final PlayerEntity player;
|
|
private int exp;
|
|
|
|
public BreakEvent(World world, BlockPos pos, BlockState state, PlayerEntity player)
|
|
{
|
|
super(world, pos, state);
|
|
this.player = player;
|
|
|
|
if (state == null || !ForgeHooks.canHarvestBlock(state, player, world, pos)) // Handle empty block or player unable to break block scenario
|
|
{
|
|
this.exp = 0;
|
|
}
|
|
else
|
|
{
|
|
int bonusLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, player.getHeldItemMainhand());
|
|
int silklevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.SILK_TOUCH, player.getHeldItemMainhand());
|
|
this.exp = state.getExpDrop(world, pos, bonusLevel, silklevel);
|
|
}
|
|
}
|
|
|
|
public PlayerEntity getPlayer()
|
|
{
|
|
return player;
|
|
}
|
|
|
|
/**
|
|
* Get the experience dropped by the block after the event has processed
|
|
*
|
|
* @return The experience to drop or 0 if the event was canceled
|
|
*/
|
|
public int getExpToDrop()
|
|
{
|
|
return this.isCanceled() ? 0 : exp;
|
|
}
|
|
|
|
/**
|
|
* Set the amount of experience dropped by the block after the event has processed
|
|
*
|
|
* @param exp 1 or higher to drop experience, else nothing will drop
|
|
*/
|
|
public void setExpToDrop(int exp)
|
|
{
|
|
this.exp = exp;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Called when a block is placed.
|
|
*
|
|
* If a Block Place event is cancelled, the block will not be placed.
|
|
*/
|
|
@Cancelable
|
|
public static class EntityPlaceEvent extends BlockEvent
|
|
{
|
|
private final Entity entity;
|
|
private final BlockSnapshot blockSnapshot;
|
|
private final BlockState placedBlock;
|
|
private final BlockState placedAgainst;
|
|
|
|
public EntityPlaceEvent(@Nonnull BlockSnapshot blockSnapshot, @Nonnull BlockState placedAgainst, @Nullable Entity entity)
|
|
{
|
|
super(blockSnapshot.getWorld(), blockSnapshot.getPos(), !(entity instanceof PlayerEntity) ? blockSnapshot.getReplacedBlock() : blockSnapshot.getCurrentBlock());
|
|
this.entity = entity;
|
|
this.blockSnapshot = blockSnapshot;
|
|
this.placedBlock = !(entity instanceof PlayerEntity) ? blockSnapshot.getReplacedBlock() : blockSnapshot.getCurrentBlock();
|
|
this.placedAgainst = placedAgainst;
|
|
|
|
if (DEBUG)
|
|
{
|
|
System.out.printf("Created EntityPlaceEvent - [PlacedBlock: %s ][PlacedAgainst: %s ][Entity: %s ]\n", getPlacedBlock(), placedAgainst, entity);
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
public Entity getEntity() { return entity; }
|
|
public BlockSnapshot getBlockSnapshot() { return blockSnapshot; }
|
|
public BlockState getPlacedBlock() { return placedBlock; }
|
|
public BlockState getPlacedAgainst() { return placedAgainst; }
|
|
}
|
|
|
|
/**
|
|
* Fired when a single block placement triggers the
|
|
* creation of multiple blocks(e.g. placing a bed block). The block returned
|
|
* by {@link #state} and its related methods is the block where
|
|
* the placed block would exist if the placement only affected a single
|
|
* block.
|
|
*/
|
|
@Cancelable
|
|
public static class EntityMultiPlaceEvent extends EntityPlaceEvent
|
|
{
|
|
private final List<BlockSnapshot> blockSnapshots;
|
|
|
|
public EntityMultiPlaceEvent(@Nonnull List<BlockSnapshot> blockSnapshots, @Nonnull BlockState placedAgainst, @Nullable Entity entity) {
|
|
super(blockSnapshots.get(0), placedAgainst, entity);
|
|
this.blockSnapshots = ImmutableList.copyOf(blockSnapshots);
|
|
if (DEBUG)
|
|
{
|
|
System.out.printf("Created EntityMultiPlaceEvent - [PlacedAgainst: %s ][Entity: %s ]\n", placedAgainst, entity);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets a list of BlockSnapshots for all blocks which were replaced by the
|
|
* placement of the new blocks. Most of these blocks will just be of type AIR.
|
|
*
|
|
* @return immutable list of replaced BlockSnapshots
|
|
*/
|
|
public List<BlockSnapshot> getReplacedBlockSnapshots()
|
|
{
|
|
return blockSnapshots;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fired when a physics update occurs on a block. This event acts as
|
|
* a way for mods to detect physics updates, in the same way a BUD switch
|
|
* does. This event is only called on the server.
|
|
*/
|
|
@Cancelable
|
|
public static class NeighborNotifyEvent extends BlockEvent
|
|
{
|
|
private final EnumSet<Direction> notifiedSides;
|
|
private final boolean forceRedstoneUpdate;
|
|
|
|
public NeighborNotifyEvent(World world, BlockPos pos, BlockState state, EnumSet<Direction> notifiedSides, boolean forceRedstoneUpdate)
|
|
{
|
|
super(world, pos, state);
|
|
this.notifiedSides = notifiedSides;
|
|
this.forceRedstoneUpdate = forceRedstoneUpdate;
|
|
}
|
|
|
|
/**
|
|
* Gets a list of directions from the base block that updates will occur upon.
|
|
*
|
|
* @return list of notified directions
|
|
*/
|
|
public EnumSet<Direction> getNotifiedSides()
|
|
{
|
|
return notifiedSides;
|
|
}
|
|
|
|
/**
|
|
* Get if redstone update was forced during setBlock call (0x16 to flags)
|
|
* @return if the flag was set
|
|
*/
|
|
public boolean getForceRedstoneUpdate()
|
|
{
|
|
return forceRedstoneUpdate;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fired to check whether a non-source block can turn into a source block.
|
|
* A result of ALLOW causes a source block to be created even if the liquid
|
|
* usually doesn't do that (like lava), and a result of DENY prevents creation
|
|
* even if the liquid usually does do that (like water).
|
|
*/
|
|
@HasResult
|
|
public static class CreateFluidSourceEvent extends Event
|
|
{
|
|
private final IWorldReader world;
|
|
private final BlockPos pos;
|
|
private final BlockState state;
|
|
|
|
public CreateFluidSourceEvent(IWorldReader world, BlockPos pos, BlockState state)
|
|
{
|
|
this.world = world;
|
|
this.pos = pos;
|
|
this.state = state;
|
|
}
|
|
|
|
public IWorldReader getWorld()
|
|
{
|
|
return world;
|
|
}
|
|
|
|
public BlockPos getPos()
|
|
{
|
|
return pos;
|
|
}
|
|
|
|
public BlockState getState()
|
|
{
|
|
return state;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fired when a liquid places a block. Use {@link #setNewState(IBlockState)} to change the result of
|
|
* a cobblestone generator or add variants of obsidian. Alternatively, you could execute
|
|
* arbitrary code when lava sets blocks on fire, even preventing it.
|
|
*
|
|
* {@link #getState()} will return the block that was originally going to be placed.
|
|
* {@link #getPos()} will return the position of the block to be changed.
|
|
*/
|
|
@Cancelable
|
|
public static class FluidPlaceBlockEvent extends BlockEvent
|
|
{
|
|
private final BlockPos liquidPos;
|
|
private BlockState newState;
|
|
private BlockState origState;
|
|
|
|
public FluidPlaceBlockEvent(IWorld world, BlockPos pos, BlockPos liquidPos, BlockState state)
|
|
{
|
|
super(world, pos, state);
|
|
this.liquidPos = liquidPos;
|
|
this.newState = state;
|
|
this.origState = world.getBlockState(pos);
|
|
}
|
|
|
|
/**
|
|
* @return The position of the liquid this event originated from. This may be the same as {@link #getPos()}.
|
|
*/
|
|
public BlockPos getLiquidPos()
|
|
{
|
|
return liquidPos;
|
|
}
|
|
|
|
/**
|
|
* @return The block state that will be placed after this event resolves.
|
|
*/
|
|
public BlockState getNewState()
|
|
{
|
|
return newState;
|
|
}
|
|
|
|
public void setNewState(BlockState state)
|
|
{
|
|
this.newState = state;
|
|
}
|
|
|
|
/**
|
|
* @return The state of the block to be changed before the event was fired.
|
|
*/
|
|
public BlockState getOriginalState()
|
|
{
|
|
return origState;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fired when a crop block grows. See subevents.
|
|
*
|
|
*/
|
|
public static class CropGrowEvent extends BlockEvent
|
|
{
|
|
public CropGrowEvent(World world, BlockPos pos, BlockState state)
|
|
{
|
|
super(world, pos, state);
|
|
}
|
|
|
|
/**
|
|
* Fired when any "growing age" blocks (for example cacti, chorus plants, or crops
|
|
* in vanilla) attempt to advance to the next growth age state during a random tick.<br>
|
|
* <br>
|
|
* {@link Result#DEFAULT} will pass on to the vanilla growth mechanics.<br>
|
|
* {@link Result#ALLOW} will force the plant to advance a growth stage.<br>
|
|
* {@link Result#DENY} will prevent the plant from advancing a growth stage.<br>
|
|
* <br>
|
|
* This event is not {@link Cancelable}.<br>
|
|
* <br>
|
|
*/
|
|
@HasResult
|
|
public static class Pre extends CropGrowEvent
|
|
{
|
|
public Pre(World world, BlockPos pos, BlockState state)
|
|
{
|
|
super(world, pos, state);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fired when "growing age" blocks (for example cacti, chorus plants, or crops
|
|
* in vanilla) have successfully grown. The block's original state is available,
|
|
* in addition to its new state.<br>
|
|
* <br>
|
|
* This event is not {@link Cancelable}.<br>
|
|
* <br>
|
|
* This event does not have a result. {@link HasResult}<br>
|
|
*/
|
|
public static class Post extends CropGrowEvent
|
|
{
|
|
private final BlockState originalState;
|
|
public Post(World world, BlockPos pos, BlockState original, BlockState state)
|
|
{
|
|
super(world, pos, state);
|
|
originalState = original;
|
|
}
|
|
|
|
public BlockState getOriginalState()
|
|
{
|
|
return originalState;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fired when when farmland gets trampled
|
|
* This event is {@link Cancelable}
|
|
*/
|
|
@Cancelable
|
|
public static class FarmlandTrampleEvent extends BlockEvent
|
|
{
|
|
|
|
private final Entity entity;
|
|
private final float fallDistance;
|
|
|
|
public FarmlandTrampleEvent(World world, BlockPos pos, BlockState state, float fallDistance, Entity entity)
|
|
{
|
|
super(world, pos, state);
|
|
this.entity = entity;
|
|
this.fallDistance = fallDistance;
|
|
}
|
|
|
|
public Entity getEntity() {
|
|
return entity;
|
|
}
|
|
|
|
public float getFallDistance() {
|
|
return fallDistance;
|
|
}
|
|
|
|
}
|
|
|
|
/* Fired when an attempt is made to spawn a nether portal from
|
|
* {@link net.minecraft.block.BlockPortal#trySpawnPortal(World, BlockPos)}.
|
|
*
|
|
* If cancelled, the portal will not be spawned.
|
|
*/
|
|
@Cancelable
|
|
public static class PortalSpawnEvent extends BlockEvent
|
|
{
|
|
private final PortalSize size;
|
|
|
|
public PortalSpawnEvent(IWorld world, BlockPos pos, BlockState state, PortalSize size)
|
|
{
|
|
super(world, pos, state);
|
|
this.size = size;
|
|
}
|
|
|
|
public PortalSize getPortalSize()
|
|
{
|
|
return size;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fired when when this block is right clicked by a tool to change its state.
|
|
* For example: Used to determine if an axe can strip, a shovel can path, or a hoe can till.
|
|
*
|
|
* This event is {@link Cancelable}. If canceled, this will prevent the tool
|
|
* from changing the block's state.
|
|
*/
|
|
@Cancelable
|
|
public static class BlockToolInteractEvent extends BlockEvent
|
|
{
|
|
|
|
private final PlayerEntity player;
|
|
private final ItemStack stack;
|
|
private final ToolType toolType;
|
|
private BlockState state;
|
|
|
|
public BlockToolInteractEvent(IWorld world, BlockPos pos, BlockState originalState, PlayerEntity player, ItemStack stack, ToolType toolType)
|
|
{
|
|
super(world, pos, originalState);
|
|
this.player = player;
|
|
this.stack = stack;
|
|
this.state = originalState;
|
|
this.toolType = toolType;
|
|
}
|
|
|
|
/**Gets the player using the tool.*/
|
|
public PlayerEntity getPlayer()
|
|
{
|
|
return player;
|
|
}
|
|
|
|
/**Gets the tool being used.*/
|
|
public ItemStack getHeldItemStack()
|
|
{
|
|
return stack;
|
|
}
|
|
|
|
/**Gets the current type of the tool being compared against.*/
|
|
public ToolType getToolType()
|
|
{
|
|
return toolType;
|
|
}
|
|
|
|
/**
|
|
* Sets the transformed state after tool use.
|
|
* If not set, will return the original state.
|
|
* This will be bypassed if canceled returning null instead.
|
|
* */
|
|
public void setFinalState(BlockState finalState)
|
|
{
|
|
this.state = finalState;
|
|
}
|
|
|
|
/**
|
|
* Gets the transformed state after tool use.
|
|
* If setFinalState not called, will return the original state.
|
|
* This will be bypassed if canceled returning null instead.
|
|
* */
|
|
public BlockState getFinalState()
|
|
{
|
|
return state;
|
|
}
|
|
}
|
|
}
|