package net.minecraftforge.test;
import net.minecraft.entity.item.EntityArmorStand;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.EntitySkeleton;
import net.minecraft.entity.passive.EntityHorse;
import net.minecraft.init.Items;
import net.minecraft.item.ItemBlock;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityChest;
import net.minecraft.tileentity.TileEntityDropper;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.Event;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.apache.logging.log4j.Logger;
@Mod(modid="playerinteracteventtest", name="PlayerInteractEventTest", version="0.0.0", acceptableRemoteVersions = "*")
public class PlayerInteractEventTest
{
// NOTE: Test with both this ON and OFF - ensure none of the test behaviours show when this is off!
private static final boolean ENABLE = false;
private Logger logger;
@EventHandler
public void preinit(FMLPreInitializationEvent event)
{
logger = event.getModLog();
MinecraftForge.EVENT_BUS.register(this);
MinecraftForge.EVENT_BUS.register(PlayerInteractEventTest.class); // Test Static event listeners
}
@SubscribeEvent(receiveCanceled = true) // this triggers after the subclasses below, and we'd like to log them all
public void global(PlayerInteractEvent evt)
{
if (!ENABLE) return;
logger.info("{} | {}", evt.getClass().getSimpleName(), evt.getSide().name());
logger.info("{} | stack: {}", evt.getHand(), evt.getItemStack());
logger.info("{} | face: {}", evt.getPos(), evt.getFace());
}
@SubscribeEvent
public void leftClickBlock(PlayerInteractEvent.LeftClickBlock evt)
{
if (!ENABLE) return;
logger.info("HIT VEC: {}", evt.getHitVec());
if (!evt.getItemStack().isEmpty())
{
if (evt.getItemStack().getItem() == Items.GOLDEN_PICKAXE)
evt.setCanceled(true); // Redstone should not activate and pick should not be able to dig anything
if (evt.getItemStack().getItem() == Items.DIAMOND_PICKAXE)
evt.setUseBlock(Event.Result.DENY); // Redstone should not activate, pick should still dig
if (evt.getItemStack().getItem() == Items.IRON_PICKAXE)
evt.setUseItem(Event.Result.DENY); // Pick should not dig, Redstone should still activate
}
// When item use denied, the event will keep firing as long as the left click button is held.
// This is due to how vanilla calls the left click handling methods to let people not lift their button when mining multiple blocks.
// Note that when item use is denied, the cool down for the item does not occur. This is good!
}
@SubscribeEvent
public void rightClickBlock(PlayerInteractEvent.RightClickBlock evt)
{
if (!ENABLE) return;
logger.info("HIT VEC: {}", evt.getHitVec());
// Shift right clicking dropper with an item in hand should still open the dropper contrary to normal mechanics
// The item in hand is used as well (not specifying anything would not use the item)
TileEntity te = evt.getWorld().getTileEntity(evt.getPos());
if (te instanceof TileEntityDropper)
{
evt.setUseBlock(Event.Result.ALLOW);
evt.setUseItem(Event.Result.ALLOW);
}
// Same as above, except the item should no longer be used
if (te instanceof TileEntityChest)
{
evt.setUseBlock(Event.Result.ALLOW);
evt.setUseItem(Event.Result.DENY); // could be left out as well
}
// Case: Flint and steel in main hand on top of a TE will light a fire, not open the TE.
// Note that if you do this on a chest, the f+s will fail, but then your off hand will open the chest
// If you dual wield flints and steels and right click a chest nothing should happen
if (!evt.getItemStack().isEmpty() && evt.getItemStack().getItem() == Items.FLINT_AND_STEEL)
evt.setUseBlock(Event.Result.DENY);
// Case: Painting in main hand
// Opening a TE will also place a painting on the TE if possible
if (evt.getHand() == EnumHand.MAIN_HAND && !evt.getItemStack().isEmpty() && evt.getItemStack().getItem() == Items.PAINTING) {
evt.setUseItem(Event.Result.ALLOW);
}
// Spawn egg in main hand, block in offhand -> block should be placed
if (!evt.getItemStack().isEmpty()
&& evt.getItemStack().getItem() == Items.SPAWN_EGG
&& evt.getHand() == EnumHand.MAIN_HAND
&& !evt.getEntityPlayer().getHeldItemOffhand().isEmpty()
&& evt.getEntityPlayer().getHeldItemOffhand().getItem() instanceof ItemBlock) {
evt.setCanceled(true);
}
// Spawn egg in main hand, potion in offhand -> potion should NOT be thrown
if (!evt.getItemStack().isEmpty()
&& evt.getItemStack().getItem() == Items.SPAWN_EGG
&& evt.getHand() == EnumHand.MAIN_HAND
&& !evt.getEntityPlayer().getHeldItemOffhand().isEmpty()
&& evt.getEntityPlayer().getHeldItemOffhand().getItem() == Items.SPLASH_POTION) {
evt.setCanceled(true);
// Fake spawn egg success so splash potion does not trigger
evt.setCancellationResult(EnumActionResult.SUCCESS);
}
}
@SubscribeEvent
public void rightClickItem(PlayerInteractEvent.RightClickItem evt)
{
if (!ENABLE) return;
// Case: Ender pearl in main hand, block in offhand -> Block is NOT placed
if (!evt.getItemStack().isEmpty()
&& evt.getItemStack().getItem() == Items.ENDER_PEARL
&& evt.getHand() == EnumHand.MAIN_HAND
&& !evt.getEntityPlayer().getHeldItemOffhand().isEmpty()
&& evt.getEntityPlayer().getHeldItemOffhand().getItem() instanceof ItemBlock)
{
evt.setCanceled(true);
evt.setCancellationResult(EnumActionResult.SUCCESS); // We fake success on the ender pearl so block is not placed
return;
}
// Case: Ender pearl in main hand, bow in offhand with arrows in inv -> Bow should trigger
// Case: Sword in main hand, ender pearl in offhand -> Nothing should happen
if (!evt.getItemStack().isEmpty() && evt.getItemStack().getItem() == Items.ENDER_PEARL)
{
evt.setCanceled(true);
}
}
@SubscribeEvent
public void interactSpecific(PlayerInteractEvent.EntityInteractSpecific evt)
{
if (!ENABLE) return;
logger.info("LOCAL POS: {}", evt.getLocalPos());
if (!evt.getItemStack().isEmpty()
&& evt.getTarget() instanceof EntityArmorStand
&& evt.getItemStack().getItem() == Items.IRON_HELMET)
evt.setCanceled(true); // Should not be able to place iron helmet onto armor stand (you will put it on instead)
if (!evt.getItemStack().isEmpty()
&& evt.getTarget() instanceof EntityArmorStand
&& evt.getItemStack().getItem() == Items.GOLDEN_HELMET)
{
evt.setCanceled(true);
evt.setCancellationResult(EnumActionResult.SUCCESS);
// Should not be able to place golden helmet onto armor stand
// However you will NOT put it on because we fake success on the armorstand.
}
if (!evt.getWorld().isRemote
&& evt.getTarget() instanceof EntitySkeleton
&& evt.getLocalPos().yCoord > evt.getTarget().height / 2.0)
{
// If we right click the upper half of a skeleton it dies.
evt.getTarget().setDead();
evt.setCanceled(true);
}
}
@SubscribeEvent
public static void interactNormal(PlayerInteractEvent.EntityInteract evt)
{
if (!ENABLE) return;
if (!evt.getItemStack().isEmpty() && evt.getTarget() instanceof EntityHorse) {
// Should not be able to feed wild horses with golden apple (you will start eating it in survival)
if (evt.getItemStack().getItem() == Items.GOLDEN_APPLE
&& evt.getItemStack().getItemDamage() == 0)
evt.setCanceled(true);
// Should not be able to feed wild horses with notch apple but you will NOT eat it
if (evt.getItemStack().getItem() == Items.GOLDEN_APPLE
&& evt.getItemStack().getItemDamage() == 1)
{
evt.setCanceled(true);
evt.setCancellationResult(EnumActionResult.SUCCESS);
}
}
}
}