From e8ea52558bbb9926d0a8694f132b5a572a360d1c Mon Sep 17 00:00:00 2001 From: Vincent Lee Date: Mon, 4 Apr 2016 19:58:46 -0500 Subject: [PATCH] Player Interact Event --- .../net/minecraft/client/Minecraft.java.patch | 18 + .../multiplayer/PlayerControllerMP.java.patch | 72 +++- .../entity/player/EntityPlayer.java.patch | 2 +- .../network/NetHandlerPlayServer.java.patch | 19 +- .../PlayerInteractionManager.java.patch | 87 +++- .../minecraft/client/Minecraft.java.patch.rej | 33 -- .../ItemInWorldManager.java.patch.rej | 71 ---- .../net/minecraftforge/common/ForgeHooks.java | 41 ++ .../event/ForgeEventFactory.java | 21 - .../entity/player/EntityInteractEvent.java | 41 -- .../entity/player/PlayerInteractEvent.java | 384 ++++++++++++++---- .../test/PlayerInteractEventLocalTest.java | 29 -- .../test/PlayerInteractEventTest.java | 154 +++++++ .../test/TestCapabilityMod.java | 7 +- 14 files changed, 685 insertions(+), 294 deletions(-) delete mode 100644 rejects/minecraft/net/minecraft/client/Minecraft.java.patch.rej delete mode 100644 rejects/minecraft/net/minecraft/server/management/ItemInWorldManager.java.patch.rej delete mode 100644 src/main/java/net/minecraftforge/event/entity/player/EntityInteractEvent.java delete mode 100644 src/test/java/net/minecraftforge/test/PlayerInteractEventLocalTest.java create mode 100644 src/test/java/net/minecraftforge/test/PlayerInteractEventTest.java diff --git a/patches/minecraft/net/minecraft/client/Minecraft.java.patch b/patches/minecraft/net/minecraft/client/Minecraft.java.patch index 3d1788e0e..8b505b450 100644 --- a/patches/minecraft/net/minecraft/client/Minecraft.java.patch +++ b/patches/minecraft/net/minecraft/client/Minecraft.java.patch @@ -175,6 +175,24 @@ { this.field_71442_b.func_180511_b(blockpos, this.field_71476_x.field_178784_b); break; +@@ -1473,7 +1491,7 @@ + switch (this.field_71476_x.field_72313_a) + { + case ENTITY: +- ++ if(!net.minecraftforge.common.ForgeHooks.onInteractEntityAt(field_71439_g, field_71476_x.field_72308_g, field_71476_x, field_71439_g.func_184586_b(enumhand), enumhand)) + if (this.field_71442_b.func_187102_a(this.field_71439_g, this.field_71476_x.field_72308_g, this.field_71476_x, this.field_71439_g.func_184586_b(enumhand), enumhand) == EnumActionResult.SUCCESS) + { + return; +@@ -1516,7 +1534,7 @@ + } + + ItemStack itemstack1 = this.field_71439_g.func_184586_b(enumhand); +- ++ if (itemstack1 == null) net.minecraftforge.common.ForgeHooks.onEmptyClick(this.field_71439_g, enumhand); + if (itemstack1 != null && this.field_71442_b.func_187101_a(this.field_71439_g, this.field_71441_e, itemstack1, enumhand) == EnumActionResult.SUCCESS) + { + this.field_71460_t.field_78516_c.func_187460_a(enumhand); @@ -1623,6 +1641,8 @@ --this.field_71467_ac; } diff --git a/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.java.patch b/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.java.patch index e28a1fd5c..b9fcfafa1 100644 --- a/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.java.patch +++ b/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.java.patch @@ -50,8 +50,39 @@ return flag; } } -@@ -373,11 +379,18 @@ +@@ -217,14 +223,17 @@ + } + + this.field_78774_b.func_147297_a(new CPacketPlayerDigging(CPacketPlayerDigging.Action.START_DESTROY_BLOCK, p_180511_1_, p_180511_2_)); ++ net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock event = net.minecraftforge.common.ForgeHooks.onLeftClickBlock(this.field_78776_a.field_71439_g, p_180511_1_, p_180511_2_, net.minecraftforge.common.ForgeHooks.rayTraceEyeHitVec(this.field_78776_a.field_71439_g, func_78757_d() + 1)); ++ + IBlockState iblockstate = this.field_78776_a.field_71441_e.func_180495_p(p_180511_1_); + boolean flag = iblockstate.func_185904_a() != Material.field_151579_a; + + if (flag && this.field_78770_f == 0.0F) + { ++ if (event.getUseBlock() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY) + iblockstate.func_177230_c().func_180649_a(this.field_78776_a.field_71441_e, p_180511_1_, this.field_78776_a.field_71439_g); + } +- ++ if (event.getUseItem() == net.minecraftforge.fml.common.eventhandler.Event.Result.DENY) return true; + if (flag && iblockstate.func_185903_a(this.field_78776_a.field_71439_g, this.field_78776_a.field_71439_g.field_70170_p, p_180511_1_) >= 1.0F) + { + this.func_187103_a(p_180511_1_); +@@ -371,13 +380,32 @@ + } + else { ++ net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock event = net.minecraftforge.common.ForgeHooks ++ .onRightClickBlock(p_187099_1_, p_187099_7_, p_187099_3_, p_187099_4_, p_187099_5_, net.minecraftforge.common.ForgeHooks.rayTraceEyeHitVec(p_187099_1_, func_78757_d() + 1)); ++ if (event.isCanceled()) ++ { ++ // Give the server a chance to fire event as well. That way server event is not dependant on client event. ++ this.field_78774_b.func_147297_a(new CPacketPlayerTryUseItem(p_187099_4_, p_187099_5_, p_187099_7_, f, f1, f2)); ++ return EnumActionResult.PASS; ++ } ++ EnumActionResult result = EnumActionResult.PASS; ++ if (this.field_78779_k != WorldSettings.GameType.SPECTATOR) { + net.minecraft.item.Item item = p_187099_3_ == null ? null : p_187099_3_.func_77973_b(); @@ -64,25 +95,54 @@ + bypass = bypass && (s == null || s.func_77973_b().doesSneakBypassUse(s, p_187099_2_, p_187099_4_, p_187099_1_)); - if ((!p_187099_1_.func_70093_af() || p_187099_1_.func_184614_ca() == null && p_187099_1_.func_184592_cb() == null) && iblockstate.func_177230_c().func_180639_a(p_187099_2_, p_187099_4_, iblockstate, p_187099_1_, p_187099_7_, p_187099_3_, p_187099_5_, f, f1, f2)) -+ if (!p_187099_1_.func_70093_af() || bypass) ++ if (!p_187099_1_.func_70093_af() || bypass || event.getUseBlock() == net.minecraftforge.fml.common.eventhandler.Event.Result.ALLOW) { - flag = true; ++ if(event.getUseBlock() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY) + flag = iblockstate.func_177230_c().func_180639_a(p_187099_2_, p_187099_4_, iblockstate, p_187099_1_, p_187099_7_, p_187099_3_, p_187099_5_, f, f1, f2); ++ if(flag) result = EnumActionResult.SUCCESS; } if (!flag && p_187099_3_ != null && p_187099_3_.func_77973_b() instanceof ItemBlock) -@@ -418,7 +431,9 @@ +@@ -393,7 +421,7 @@ + + this.field_78774_b.func_147297_a(new CPacketPlayerTryUseItem(p_187099_4_, p_187099_5_, p_187099_7_, f, f1, f2)); + +- if (!flag && this.field_78779_k != WorldSettings.GameType.SPECTATOR) ++ if (!flag && this.field_78779_k != WorldSettings.GameType.SPECTATOR || event.getUseItem() == net.minecraftforge.fml.common.eventhandler.Event.Result.ALLOW) + { + if (p_187099_3_ == null) + { +@@ -411,14 +439,19 @@ + { + int i = p_187099_3_.func_77960_j(); + int j = p_187099_3_.field_77994_a; ++ if (event.getUseItem() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY) { + EnumActionResult enumactionresult = p_187099_3_.func_179546_a(p_187099_1_, p_187099_2_, p_187099_4_, p_187099_7_, p_187099_5_, f, f1, f2); + p_187099_3_.func_77964_b(i); + p_187099_3_.field_77994_a = j; + return enumactionresult; ++ } else return result; } else { - return p_187099_3_.func_179546_a(p_187099_1_, p_187099_2_, p_187099_4_, p_187099_7_, p_187099_5_, f, f1, f2); -+ EnumActionResult ret = p_187099_3_.func_179546_a(p_187099_1_, p_187099_2_, p_187099_4_, p_187099_7_, p_187099_5_, f, f1, f2); ++ if (event.getUseItem() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY) ++ result = p_187099_3_.func_179546_a(p_187099_1_, p_187099_2_, p_187099_4_, p_187099_7_, p_187099_5_, f, f1, f2); + if (p_187099_3_.field_77994_a <= 0) net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(p_187099_1_, p_187099_3_, p_187099_7_); -+ return ret; ++ return result; } } else -@@ -453,9 +468,10 @@ +@@ -445,6 +478,7 @@ + } + else + { ++ if (net.minecraftforge.common.ForgeHooks.onItemRightClick(p_187101_1_, p_187101_4_, p_187101_3_)) return net.minecraft.util.EnumActionResult.PASS; + int i = p_187101_3_.field_77994_a; + ActionResult actionresult = p_187101_3_.func_77957_a(p_187101_2_, p_187101_1_, p_187101_4_); + ItemStack itemstack = (ItemStack)actionresult.func_188398_b(); +@@ -453,9 +487,10 @@ { p_187101_1_.func_184611_a(p_187101_4_, itemstack); diff --git a/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch b/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch index 68bdc3287..8da477eb3 100644 --- a/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch +++ b/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch @@ -218,7 +218,7 @@ } else { -+ if (!net.minecraftforge.event.ForgeEventFactory.canInteractWith(this, p_184822_1_, p_184822_2_, p_184822_3_)) return EnumActionResult.PASS; ++ if (net.minecraftforge.common.ForgeHooks.onInteractEntity(this, p_184822_1_, p_184822_2_, p_184822_3_)) return EnumActionResult.PASS; ItemStack itemstack = p_184822_2_ != null ? p_184822_2_.func_77946_l() : null; if (!p_184822_1_.func_184230_a(this, p_184822_2_, p_184822_3_)) diff --git a/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch b/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch index 657125557..df2660338 100644 --- a/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch +++ b/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch @@ -31,14 +31,7 @@ itemstack = null; } } -@@ -703,12 +709,14 @@ - - if (itemstack != null) - { -+ //TODO: Hook interact event here... we don't know the type of itneration tho... - this.field_147369_b.field_71134_c.func_187250_a(this.field_147369_b, worldserver, itemstack, enumhand); - itemstack = this.field_147369_b.func_184586_b(enumhand); - +@@ -709,6 +715,7 @@ if (itemstack != null && itemstack.field_77994_a == 0) { this.field_147369_b.func_184611_a(enumhand, (ItemStack)null); @@ -46,7 +39,7 @@ itemstack = null; } } -@@ -888,7 +896,9 @@ +@@ -888,7 +895,9 @@ } else { @@ -57,6 +50,14 @@ this.field_147367_d.func_184103_al().func_148544_a(itextcomponent, false); } +@@ -1018,6 +1027,7 @@ + { + EnumHand enumhand1 = p_147340_1_.func_186994_b(); + ItemStack itemstack1 = this.field_147369_b.func_184586_b(enumhand1); ++ if(net.minecraftforge.common.ForgeHooks.onInteractEntityAt(field_147369_b, entity, p_147340_1_.func_179712_b(), itemstack1, enumhand1)) return; + entity.func_184199_a(this.field_147369_b, p_147340_1_.func_179712_b(), itemstack1, enumhand1); + } + else if (p_147340_1_.func_149565_c() == CPacketUseEntity.Action.ATTACK) @@ -1057,7 +1067,7 @@ return; } diff --git a/patches/minecraft/net/minecraft/server/management/PlayerInteractionManager.java.patch b/patches/minecraft/net/minecraft/server/management/PlayerInteractionManager.java.patch index d7f9cbd1e..623e191d2 100644 --- a/patches/minecraft/net/minecraft/server/management/PlayerInteractionManager.java.patch +++ b/patches/minecraft/net/minecraft/server/management/PlayerInteractionManager.java.patch @@ -36,22 +36,23 @@ int l = (int)(f1 * 10.0F); if (l != this.field_73094_o) -@@ -138,6 +140,14 @@ +@@ -138,6 +140,15 @@ public void func_180784_a(BlockPos p_180784_1_, EnumFacing p_180784_2_) { -+ net.minecraftforge.event.entity.player.PlayerInteractEvent event = net.minecraftforge.event.ForgeEventFactory.onPlayerInteract(field_73090_b, -+ net.minecraftforge.event.entity.player.PlayerInteractEvent.Action.LEFT_CLICK_BLOCK, field_73092_a, p_180784_1_, p_180784_2_, net.minecraftforge.common.ForgeHooks.rayTraceEyeHitVec(field_73090_b, getBlockReachDistance() + 1)); ++ net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock event = net.minecraftforge.common.ForgeHooks.onLeftClickBlock(field_73090_b, p_180784_1_, p_180784_2_, net.minecraftforge.common.ForgeHooks.rayTraceEyeHitVec(field_73090_b, getBlockReachDistance() + 1)); + if (event.isCanceled()) + { ++ // Restore block and te data + field_73090_b.field_71135_a.func_147359_a(new SPacketBlockChange(field_73092_a, p_180784_1_)); ++ field_73092_a.func_184138_a(p_180784_1_, field_73092_a.func_180495_p(p_180784_1_), field_73092_a.func_180495_p(p_180784_1_), 3); + return; + } + if (this.func_73083_d()) { if (!this.field_73092_a.func_175719_a((EntityPlayer)null, p_180784_1_, p_180784_2_)) -@@ -173,17 +183,32 @@ +@@ -173,17 +184,36 @@ } } @@ -70,7 +71,9 @@ + } + else + { ++ // Restore block and te data + field_73090_b.field_71135_a.func_147359_a(new SPacketBlockChange(field_73092_a, p_180784_1_)); ++ field_73092_a.func_184138_a(p_180784_1_, field_73092_a.func_180495_p(p_180784_1_), field_73092_a.func_180495_p(p_180784_1_), 3); + } f = iblockstate.func_185903_a(this.field_73090_b, this.field_73090_b.field_70170_p, p_180784_1_); } @@ -78,7 +81,9 @@ + { + if (f >= 1.0F) + { ++ // Restore block and te data + field_73090_b.field_71135_a.func_147359_a(new SPacketBlockChange(field_73092_a, p_180784_1_)); ++ field_73092_a.func_184138_a(p_180784_1_, field_73092_a.func_180495_p(p_180784_1_), field_73092_a.func_180495_p(p_180784_1_), 3); + } + return; + } @@ -88,7 +93,7 @@ { this.func_180237_b(p_180784_1_); } -@@ -205,7 +230,7 @@ +@@ -205,7 +235,7 @@ int i = this.field_73100_i - this.field_73089_e; IBlockState iblockstate = this.field_73092_a.func_180495_p(p_180785_1_); @@ -97,7 +102,7 @@ { float f = iblockstate.func_185903_a(this.field_73090_b, this.field_73090_b.field_70170_p, p_180785_1_) * (float)(i + 1); -@@ -234,13 +259,17 @@ +@@ -234,13 +264,17 @@ private boolean func_180235_c(BlockPos p_180235_1_) { @@ -119,7 +124,7 @@ } return flag; -@@ -248,7 +277,8 @@ +@@ -248,7 +282,8 @@ public boolean func_180237_b(BlockPos p_180237_1_) { @@ -129,7 +134,7 @@ { return false; } -@@ -264,41 +294,22 @@ +@@ -264,41 +299,22 @@ } else { @@ -176,7 +181,7 @@ if (itemstack1 != null) { -@@ -310,12 +321,18 @@ +@@ -310,12 +326,18 @@ } } @@ -195,7 +200,15 @@ return flag1; } } -@@ -359,6 +376,7 @@ +@@ -333,6 +355,7 @@ + } + else + { ++ if (net.minecraftforge.common.ForgeHooks.onItemRightClick(p_187250_1_, p_187250_4_, p_187250_3_)) return net.minecraft.util.EnumActionResult.PASS; + int i = p_187250_3_.field_77994_a; + int j = p_187250_3_.func_77960_j(); + ActionResult actionresult = p_187250_3_.func_77957_a(p_187250_2_, p_187250_1_, p_187250_4_); +@@ -359,6 +382,7 @@ if (itemstack.field_77994_a == 0) { p_187250_1_.func_184611_a(p_187250_4_, (ItemStack)null); @@ -203,7 +216,59 @@ } if (!p_187250_1_.func_184587_cr()) -@@ -445,4 +463,13 @@ +@@ -403,13 +427,26 @@ + } + else + { +- if (!p_187251_1_.func_70093_af() || p_187251_1_.func_184614_ca() == null && p_187251_1_.func_184592_cb() == null) ++ net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock event = net.minecraftforge.common.ForgeHooks ++ .onRightClickBlock(p_187251_1_, p_187251_4_, p_187251_3_, p_187251_5_, p_187251_6_, net.minecraftforge.common.ForgeHooks.rayTraceEyeHitVec(field_73090_b, getBlockReachDistance() + 1)); ++ if (event.isCanceled()) return EnumActionResult.PASS; ++ ++ net.minecraft.item.Item item = p_187251_3_ == null ? null : p_187251_3_.func_77973_b(); ++ EnumActionResult ret = item == null ? EnumActionResult.PASS : item.onItemUseFirst(p_187251_3_, p_187251_1_, p_187251_2_, p_187251_5_, p_187251_6_, p_187251_7_, p_187251_8_, p_187251_9_, p_187251_4_); ++ if (ret != EnumActionResult.PASS) return ret; ++ ++ boolean bypass = true; ++ for (ItemStack s : new ItemStack[]{p_187251_1_.func_184614_ca(), p_187251_1_.func_184592_cb()}) //TODO: Expand to more hands? player.inv.getHands()? ++ bypass = bypass && (s == null || s.func_77973_b().doesSneakBypassUse(s, p_187251_2_, p_187251_5_, p_187251_1_)); ++ EnumActionResult result = EnumActionResult.PASS; ++ ++ if (!p_187251_1_.func_70093_af() || bypass || event.getUseBlock() == net.minecraftforge.fml.common.eventhandler.Event.Result.ALLOW) + { + IBlockState iblockstate = p_187251_2_.func_180495_p(p_187251_5_); +- ++ if(event.getUseBlock() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY) + if (iblockstate.func_177230_c().func_180639_a(p_187251_2_, p_187251_5_, iblockstate, p_187251_1_, p_187251_4_, p_187251_3_, p_187251_6_, p_187251_7_, p_187251_8_, p_187251_9_)) + { +- return EnumActionResult.SUCCESS; ++ result = EnumActionResult.SUCCESS; + } + } + +@@ -429,14 +466,21 @@ + { + int j = p_187251_3_.func_77960_j(); + int i = p_187251_3_.field_77994_a; ++ if (result != EnumActionResult.SUCCESS && event.getUseItem() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY ++ || result == EnumActionResult.SUCCESS && event.getUseItem() == net.minecraftforge.fml.common.eventhandler.Event.Result.ALLOW) { + EnumActionResult enumactionresult = p_187251_3_.func_179546_a(p_187251_1_, p_187251_2_, p_187251_5_, p_187251_4_, p_187251_6_, p_187251_7_, p_187251_8_, p_187251_9_); + p_187251_3_.func_77964_b(j); + p_187251_3_.field_77994_a = i; + return enumactionresult; ++ } else return result; ++ + } + else + { ++ if (result != EnumActionResult.SUCCESS && event.getUseItem() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY ++ || result == EnumActionResult.SUCCESS && event.getUseItem() == net.minecraftforge.fml.common.eventhandler.Event.Result.ALLOW) + return p_187251_3_.func_179546_a(p_187251_1_, p_187251_2_, p_187251_5_, p_187251_4_, p_187251_6_, p_187251_7_, p_187251_8_, p_187251_9_); ++ else return result; + } + } + } +@@ -445,4 +489,13 @@ { this.field_73092_a = p_73080_1_; } diff --git a/rejects/minecraft/net/minecraft/client/Minecraft.java.patch.rej b/rejects/minecraft/net/minecraft/client/Minecraft.java.patch.rej deleted file mode 100644 index af5d4ff9b..000000000 --- a/rejects/minecraft/net/minecraft/client/Minecraft.java.patch.rej +++ /dev/null @@ -1,33 +0,0 @@ -++++ REJECTED PATCH 11 - case BLOCK: - BlockPos blockpos = this.objectMouseOver.getBlockPos(); - -- if (this.theWorld.getBlockState(blockpos).getBlock().getMaterial() != Material.air) -+ if (!this.theWorld.isAirBlock(blockpos)) - { - int i = itemstack != null ? itemstack.stackSize : 0; - -+ -+ boolean result = !net.minecraftforge.event.ForgeEventFactory.onPlayerInteract(thePlayer, net.minecraftforge.event.entity.player.PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK, this.theWorld, blockpos, this.objectMouseOver.sideHit, this.objectMouseOver.hitVec).isCanceled(); -+ if (result) { //Forge: Kept separate to simplify patch - if (this.playerController.onPlayerRightClick(this.thePlayer, this.theWorld, itemstack, blockpos, this.objectMouseOver.sideHit, this.objectMouseOver.hitVec)) - { - flag = false; - this.thePlayer.swingItem(); - } -+ } - - if (itemstack == null) - { -++++ END PATCH -++++ REJECTED PATCH 12 - { - ItemStack itemstack1 = this.thePlayer.inventory.getCurrentItem(); - -- if (itemstack1 != null && this.playerController.sendUseItem(this.thePlayer, this.theWorld, itemstack1)) -+ boolean result = !net.minecraftforge.event.ForgeEventFactory.onPlayerInteract(thePlayer, net.minecraftforge.event.entity.player.PlayerInteractEvent.Action.RIGHT_CLICK_AIR, theWorld, null, null, null).isCanceled(); -+ if (result && itemstack1 != null && this.playerController.sendUseItem(this.thePlayer, this.theWorld, itemstack1)) - { - this.entityRenderer.itemRenderer.resetEquippedProgress2(); - } -++++ END PATCH \ No newline at end of file diff --git a/rejects/minecraft/net/minecraft/server/management/ItemInWorldManager.java.patch.rej b/rejects/minecraft/net/minecraft/server/management/ItemInWorldManager.java.patch.rej deleted file mode 100644 index a9f9605b4..000000000 --- a/rejects/minecraft/net/minecraft/server/management/ItemInWorldManager.java.patch.rej +++ /dev/null @@ -1,71 +0,0 @@ -++++ REJECTED PATCH 11 - } - else - { -- if (!player.isSneaking() || player.getHeldItem() == null) -+ net.minecraftforge.event.entity.player.PlayerInteractEvent event = net.minecraftforge.event.ForgeEventFactory.onPlayerInteract(player, -+ net.minecraftforge.event.entity.player.PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK, worldIn, pos, side, new net.minecraft.util.Vec3(offsetX, offsetY, offsetZ)); -+ if (event.isCanceled()) - { -- IBlockState iblockstate = worldIn.getBlockState(pos); -- -- if (iblockstate.getBlock().onBlockActivated(worldIn, pos, iblockstate, player, side, offsetX, offsetY, offsetZ)) -- { -- return true; -- } -+ thisPlayerMP.playerNetServerHandler.sendPacket(new S23PacketBlockChange(theWorld, pos)); -+ return false; - } - -- if (stack == null) -+ if (stack != null && stack.getItem().onItemUseFirst(stack, player, worldIn, pos, side, offsetX, offsetY, offsetZ)) - { -- return false; -+ if (stack.stackSize <= 0) net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, stack); -+ return true; - } -- else if (this.isCreative()) -+ -+ IBlockState iblockstate = worldIn.getBlockState(pos); -+ boolean isAir = worldIn.isAirBlock(pos); -+ boolean useBlock = !player.isSneaking() || player.getHeldItem() == null; -+ if (!useBlock) useBlock = player.getHeldItem().getItem().doesSneakBypassUse(worldIn, pos, player); -+ boolean result = false; -+ -+ if (useBlock) - { -- int j = stack.getMetadata(); -- int i = stack.stackSize; -- boolean flag = stack.onItemUse(player, worldIn, pos, side, offsetX, offsetY, offsetZ); -- stack.setItemDamage(j); -- stack.stackSize = i; -- return flag; -+ if (event.useBlock != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY) -+ { -+ result = iblockstate.getBlock().onBlockActivated(worldIn, pos, iblockstate, player, side, offsetX, offsetY, offsetZ); -+ } -+ else -+ { -+ thisPlayerMP.playerNetServerHandler.sendPacket(new S23PacketBlockChange(theWorld, pos)); -+ result = event.useItem != net.minecraftforge.fml.common.eventhandler.Event.Result.ALLOW; -+ } - } -- else -+ if (stack != null && !result && event.useItem != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY) - { -- return stack.onItemUse(player, worldIn, pos, side, offsetX, offsetY, offsetZ); -+ int meta = stack.getMetadata(); -+ int size = stack.stackSize; -+ result = stack.onItemUse(player, worldIn, pos, side, offsetX, offsetY, offsetZ); -+ if (isCreative()) -+ { -+ stack.setItemDamage(meta); -+ stack.stackSize = size; -+ } -+ if (stack.stackSize <= 0) net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, stack); - } -+ return result; - } - } - -++++ END PATCH diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index a58281933..b1f17fcca 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -86,6 +86,7 @@ import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; import net.minecraftforge.event.entity.player.AnvilRepairEvent; import net.minecraftforge.event.entity.player.AttackEntityEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerOpenContainerEvent; import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.event.world.NoteBlockEvent; @@ -934,4 +935,44 @@ public class ForgeHooks RayTraceResult git = rayTraceEyes(entity, length); return git == null ? null : git.hitVec; } + + public static boolean onInteractEntityAt(EntityPlayer player, Entity entity, RayTraceResult ray, ItemStack stack, EnumHand hand) + { + Vec3d vec3d = new Vec3d(ray.hitVec.xCoord - entity.posX, ray.hitVec.yCoord - entity.posY, ray.hitVec.zCoord - entity.posZ); + return onInteractEntityAt(player, entity, vec3d, stack, hand); + } + + public static boolean onInteractEntityAt(EntityPlayer player, Entity entity, Vec3d vec3d, ItemStack stack, EnumHand hand) + { + return MinecraftForge.EVENT_BUS.post(new PlayerInteractEvent.EntityInteractSpecific(player, hand, stack, entity, vec3d)); + } + + public static boolean onInteractEntity(EntityPlayer player, Entity entity, ItemStack item, EnumHand hand) + { + return MinecraftForge.EVENT_BUS.post(new PlayerInteractEvent.EntityInteract(player, hand, item, entity)); + } + + public static boolean onItemRightClick(EntityPlayer player, EnumHand hand, ItemStack stack) + { + return MinecraftForge.EVENT_BUS.post(new PlayerInteractEvent.RightClickItem(player, hand, stack)); + } + + public static PlayerInteractEvent.LeftClickBlock onLeftClickBlock(EntityPlayer player, BlockPos pos, EnumFacing face, Vec3d hitVec) + { + PlayerInteractEvent.LeftClickBlock evt = new PlayerInteractEvent.LeftClickBlock(player, pos, face, hitVec); + MinecraftForge.EVENT_BUS.post(evt); + return evt; + } + + public static PlayerInteractEvent.RightClickBlock onRightClickBlock(EntityPlayer player, EnumHand hand, ItemStack stack, BlockPos pos, EnumFacing face, Vec3d hitVec) + { + PlayerInteractEvent.RightClickBlock evt = new PlayerInteractEvent.RightClickBlock(player, hand, stack, pos, face, hitVec); + MinecraftForge.EVENT_BUS.post(evt); + return evt; + } + + public static void onEmptyClick(EntityPlayer player, EnumHand hand) + { + MinecraftForge.EVENT_BUS.post(new PlayerInteractEvent.RightClickEmpty(player, hand)); + } } diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java index b356576e0..9bbdfceb5 100644 --- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java +++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java @@ -61,7 +61,6 @@ import net.minecraftforge.event.entity.living.ZombieEvent.SummonAidEvent; import net.minecraftforge.event.entity.player.ArrowLooseEvent; import net.minecraftforge.event.entity.player.ArrowNockEvent; import net.minecraftforge.event.entity.player.BonemealEvent; -import net.minecraftforge.event.entity.player.EntityInteractEvent; import net.minecraftforge.event.entity.player.EntityItemPickupEvent; import net.minecraftforge.event.entity.player.FillBucketEvent; import net.minecraftforge.event.entity.player.ItemTooltipEvent; @@ -69,8 +68,6 @@ import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent; import net.minecraftforge.event.entity.player.PlayerDropsEvent; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.entity.player.PlayerFlyableFallEvent; -import net.minecraftforge.event.entity.player.PlayerInteractEvent; -import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; import net.minecraftforge.event.entity.player.PlayerSetSpawnEvent; import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent; import net.minecraftforge.event.entity.player.PlayerWakeUpEvent; @@ -128,19 +125,6 @@ public class ForgeEventFactory return (MinecraftForge.EVENT_BUS.post(event) ? -1 : event.getNewSpeed()); } - @Deprecated - public static PlayerInteractEvent onPlayerInteract(EntityPlayer player, Action action, World world, BlockPos pos, EnumFacing face) - { - return onPlayerInteract(player, action, world, pos, face, null); - } - - public static PlayerInteractEvent onPlayerInteract(EntityPlayer player, Action action, World world, BlockPos pos, EnumFacing face, Vec3d localPos) - { - PlayerInteractEvent event = new PlayerInteractEvent(player, action, pos, face, world, localPos); - MinecraftForge.EVENT_BUS.post(event); - return event; - } - public static void onPlayerDestroyItem(EntityPlayer player, ItemStack stack, EnumHand hand) { MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, stack, hand)); @@ -369,11 +353,6 @@ public class ForgeEventFactory } } - public static boolean canInteractWith(EntityPlayer player, Entity entity, ItemStack item, EnumHand hand) - { - return !MinecraftForge.EVENT_BUS.post(new EntityInteractEvent(player, entity, item, hand)); - } - public static boolean canMountEntity(Entity entityMounting, Entity entityBeingMounted, boolean isMounting) { boolean isCanceled = MinecraftForge.EVENT_BUS.post(new EntityMountEvent(entityMounting, entityBeingMounted, entityMounting.worldObj, isMounting)); diff --git a/src/main/java/net/minecraftforge/event/entity/player/EntityInteractEvent.java b/src/main/java/net/minecraftforge/event/entity/player/EntityInteractEvent.java deleted file mode 100644 index ce817b003..000000000 --- a/src/main/java/net/minecraftforge/event/entity/player/EntityInteractEvent.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.minecraftforge.event.entity.player; - -import net.minecraftforge.fml.common.eventhandler.Cancelable; -import net.minecraftforge.fml.common.eventhandler.Event.HasResult; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; - -/** - * EntityInteractEvent is fired when a player interacts with an Entity.
- * This event is fired whenever a player interacts with an Entity in - * EntityPlayer#interactWith(Entity).
- *
- * {@link #target} contains the Entity the player interacted with.
- *
- * This event is {@link Cancelable}.
- * If this event is canceled, the player does not interact with the Entity.
- *
- * This event does not have a result. {@link HasResult}
- *
- * This event is fired on the {@link MinecraftForge#EVENT_BUS}. - **/ -@Cancelable -public class EntityInteractEvent extends PlayerEvent -{ - private final Entity target; - private final ItemStack item; - private final EnumHand hand; - public EntityInteractEvent(EntityPlayer player, Entity target, ItemStack item, EnumHand hand) - { - super(player); - this.target = target; - this.item = item; - this.hand = hand; - } - - public Entity getTarget() { return this.target; } - public ItemStack getItem() { return this.item; } - public EnumHand getHand() { return this.hand; } -} diff --git a/src/main/java/net/minecraftforge/event/entity/player/PlayerInteractEvent.java b/src/main/java/net/minecraftforge/event/entity/player/PlayerInteractEvent.java index 1f4851289..90325e3ee 100644 --- a/src/main/java/net/minecraftforge/event/entity/player/PlayerInteractEvent.java +++ b/src/main/java/net/minecraftforge/event/entity/player/PlayerInteractEvent.java @@ -1,88 +1,336 @@ package net.minecraftforge.event.entity.player; +import com.google.common.base.Preconditions; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.Cancelable; +import net.minecraftforge.fml.relauncher.Side; + +import javax.annotation.Nullable; + import static net.minecraftforge.fml.common.eventhandler.Event.Result.DEFAULT; import static net.minecraftforge.fml.common.eventhandler.Event.Result.DENY; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; -import net.minecraftforge.fml.common.eventhandler.Cancelable; /** * PlayerInteractEvent is fired when a player interacts in some way. - *
- * This event is fired whenever a player interacts in - * Minecraft#func_147121_ag(), - * NetHandlerPlayServer#processPlayerBlockPlacement(C08PacketPlayerBlockPlacement), - * ItemInWorldManager#activateBlockOrUseItem(EntityPlayer, World, ItemStack, int, int, int, int, float, float, float), - * ItemInWorldManager#onBlockClicked(int, int, int, int).
- *
- * This event is fired via the {@link ForgeEventFactory#onPlayerInteract(EntityPlayer, Action, BlockPos, EnumFacing)}. - *
- * {@link #action} contains the Action the player performed during this interaction.
- * {@link #pos} contains the coordinate of where this event occurred.
- * {@link #face} contains the face of the block that was interacted with. May be null if unknown.
- * {@link #world} contains the world in which this event is occurring.
- *
- * This event is {@link Cancelable}.
- * If this event is canceled, the player does not interact.
- *
- * This event does not have a result. {@link HasResult}
- *
- * This event is fired on the {@link MinecraftForge#EVENT_BUS}. + * All subclasses are fired on {@link MinecraftForge#EVENT_BUS}. + * See the individual documentation on each subevent for more details. **/ -@Cancelable public class PlayerInteractEvent extends PlayerEvent { - public static enum Action - { - RIGHT_CLICK_AIR, - RIGHT_CLICK_BLOCK, - LEFT_CLICK_BLOCK - } - - private final Action action; - private final World world; + private final EnumHand hand; + private final ItemStack stack; private final BlockPos pos; - private final EnumFacing face; // Can be null if unknown - private final Vec3d localPos; // Can be null if unknown + private final EnumFacing face; - private Result useBlock = DEFAULT; - private Result useItem = DEFAULT; - - @Deprecated - public PlayerInteractEvent(EntityPlayer player, Action action, BlockPos pos, EnumFacing face, World world) + private PlayerInteractEvent(EntityPlayer player, EnumHand hand, ItemStack stack, BlockPos pos, EnumFacing face) { - this(player, action, pos, face, world, null); - } - - public PlayerInteractEvent(EntityPlayer player, Action action, BlockPos pos, EnumFacing face, World world, Vec3d localPos) - { - super(player); - this.action = action; - this.pos = pos; + super(Preconditions.checkNotNull(player, "Null player in PlayerInteractEvent!")); + this.hand = Preconditions.checkNotNull(hand, "Null hand in PlayerInteractEvent!"); + this.stack = stack; + this.pos = Preconditions.checkNotNull(pos, "Null position in PlayerInteractEvent!"); this.face = face; - if (face == null) setUseBlock(DENY); - this.world = world; - this.localPos = localPos; } - @Override - public void setCanceled(boolean cancel) + /** + * This event is fired on both sides whenever a player right clicks an entity. + * + * "Interact at" is an interact where the local vector (which part of the entity you clicked) is known. + * The state of this event affects whether {@link Entity#applyPlayerInteraction} is called. + * If {@link Entity#applyPlayerInteraction} returns {@link net.minecraft.util.EnumActionResult#SUCCESS}, then processing ends. + * Otherwise processing will continue to {@link EntityInteract} + * + * Canceling the event clientside will cause processing to continue to {@link EntityInteract}, + * while canceling serverside will simply do no further processing. + */ + @Cancelable + public static class EntityInteractSpecific extends PlayerInteractEvent { - super.setCanceled(cancel); - setUseBlock((cancel ? DENY : getUseBlock() == DENY ? DEFAULT : getUseBlock())); - setUseItem((cancel ? DENY : getUseItem() == DENY ? DEFAULT : getUseItem())); + private final Vec3d localPos; + private final Entity target; + + public EntityInteractSpecific(EntityPlayer player, EnumHand hand, ItemStack stack, Entity target, Vec3d localPos) + { + super(player, hand, stack, new BlockPos(target), null); + this.localPos = localPos; + this.target = target; + } + + /** + * Returns the local interaction position. This is a 3D vector, where (0, 0, 0) is centered exactly at the + * center of the entity's bounding box at their feet. This means the X and Z values will be in the range + * [-width / 2, width / 2] while Y values will be in the range [0, height] + * @return The local position + */ + public Vec3d getLocalPos() + { + return localPos; + } + + public Entity getTarget() + { + return target; + } + } + + /** + * This event is fired on both sides when the player right clicks an entity. + * It is responsible for all general entity interactions. + * + * This event is fired completely independently of the above {@link EntityInteractSpecific}, except for the case + * where the above call to {@link Entity#applyPlayerInteraction} returns {@link net.minecraft.util.EnumActionResult#SUCCESS}. + * In that case, general entity interactions, and hence this event, will not be called. See the above javadoc for more details. + * + * This event's state affects whether {@link Entity#processInitialInteract} and {@link net.minecraft.item.Item#itemInteractionForEntity} are called. + * + * Canceling the event clientside will cause processing to continue to {@link RightClickItem}, + * while canceling serverside will simply do no further processing. + */ + @Cancelable + public static class EntityInteract extends PlayerInteractEvent + { + private final Entity target; + + public EntityInteract(EntityPlayer player, EnumHand hand, ItemStack stack, Entity target) + { + super(player, hand, stack, new BlockPos(target), null); + this.target = target; + } + + public Entity getTarget() + { + return target; + } + } + + /** + * This event is fired on both sides whenever the player right clicks while targeting a block. + * This event controls which of {@link net.minecraft.block.Block#onBlockActivated} and/or {@link net.minecraft.item.Item#onItemUse} + * will be called after {@link net.minecraft.item.Item#onItemUseFirst} is called. + * Canceling the event will cause none of the above three to be called. + * There are various results to this event, see the getters below. + * Note that handling things differently on the client vs server may cause desynchronizations! + */ + @Cancelable + public static class RightClickBlock extends PlayerInteractEvent + { + private Result useBlock = DEFAULT; + private Result useItem = DEFAULT; + private final Vec3d hitVec; + + public RightClickBlock(EntityPlayer player, EnumHand hand, ItemStack stack, + BlockPos pos, EnumFacing face, Vec3d hitVec) { + super(player, hand, stack, pos, face); + this.hitVec = hitVec; + } + + /** + * @return The hit vector of this click + */ + public Vec3d getHitVec() + { + return hitVec; + } + + /** + * @return If {@link net.minecraft.block.Block#onBlockActivated} should be called + */ + public Result getUseBlock() + { + return useBlock; + } + + /** + * @return If {@link net.minecraft.item.Item#onItemUse} should be called + */ + public Result getUseItem() + { + return useItem; + } + + /** + * DENY: Block will never be used. + * DEFAULT: Default behaviour (sneak will not use block, unless all items return true in {@link net.minecraft.item.Item#doesSneakBypassUse}). + * ALLOW: Block will always be used, regardless of sneaking and doesSneakBypassUse. + */ + public void setUseBlock(Result triggerBlock) + { + this.useBlock = triggerBlock; + } + + /** + * DENY: The item will never be used. + * DEFAULT: The item will be used if the block fails. + * ALLOW: The item will always be used. + */ + public void setUseItem(Result triggerItem) + { + this.useItem = triggerItem; + } + + @Override + public void setCanceled(boolean canceled) + { + super.setCanceled(canceled); + useBlock = DENY; + useItem = DENY; + } + } + + /** + * This event is fired on both sides before the player triggers {@link net.minecraft.item.Item#onItemRightClick}. + * Note that this is NOT fired if the player is targeting a block. For that case, see {@link RightClickBlock}. + * Canceling the event clientside causes processing to continue to the other hands, + * while canceling serverside will simply do no further processing. + */ + @Cancelable + public static class RightClickItem extends PlayerInteractEvent + { + public RightClickItem(EntityPlayer player, EnumHand hand, ItemStack stack) + { + super(player, hand, stack, new BlockPos(player), null); + } + } + + /** + * This event is fired on the client side when the player right clicks empty space with an empty hand. + * The server is not aware of when the client right clicks empty space with an empty hand, you will need to tell the server yourself. + * This event cannot be canceled. + */ + public static class RightClickEmpty extends PlayerInteractEvent + { + public RightClickEmpty(EntityPlayer player, EnumHand hand) + { + super(player, hand, null, new BlockPos(player), null); + } + } + + /** + * This event is fired when a player left clicks while targeting a block. + * This event controls which of {@link net.minecraft.block.Block#onBlockClicked} and/or the item harvesting methods will be called + * Canceling the event will cause none of the above noted methods to be called. + * There are various results to this event, see the getters below. + * Note that if the event is canceled and the player holds down left mouse, the event will continue to fire. + * This is due to how vanilla calls the left click handler methods. + */ + @Cancelable + public static class LeftClickBlock extends PlayerInteractEvent + { + private Result useBlock = DEFAULT; + private Result useItem = DEFAULT; + private final Vec3d hitVec; + + public LeftClickBlock(EntityPlayer player, BlockPos pos, EnumFacing face, Vec3d hitVec) + { + super(player, EnumHand.MAIN_HAND, player.getHeldItem(EnumHand.MAIN_HAND), pos, face); + this.hitVec = hitVec; + } + + /** + * @return The local hit vector of this click + */ + public Vec3d getHitVec() + { + return hitVec; + } + + /** + * @return If {@link net.minecraft.block.Block#onBlockClicked} should be called + */ + public Result getUseBlock() + { + return useBlock; + } + + /** + * @return If the block should be attempted to be mined with the current item + */ + public Result getUseItem() + { + return useItem; + } + + public void setUseBlock(Result triggerBlock) + { + this.useBlock = triggerBlock; + } + + public void setUseItem(Result triggerItem) + { + this.useItem = triggerItem; + } + + @Override + public void setCanceled(boolean canceled) + { + super.setCanceled(canceled); + useBlock = DENY; + useItem = DENY; + } + } + + /** + * @return The hand involved in this interaction. Will never be null. + */ + public EnumHand getHand() + { + return hand; + } + + /** + * @return The itemstack involved in this interaction, or null if the hand was empty. + */ + @Nullable + public ItemStack getItemStack() + { + return stack; + } + + /** + * If the interaction was on an entity, will be a BlockPos centered on the entity. + * If the interaction was on a block, will be the position of that block. + * Otherwise, will be a BlockPos centered on the player. + * Will never be null. + * @return The position involved in this interaction. + */ + public BlockPos getPos() + { + return pos; + } + + /** + * @return The face involved in this interaction. For all non-block interactions, this will return null. + */ + @Nullable + public EnumFacing getFace() + { + return face; + } + + /** + * @return Convenience method to get the world of this interaction. + */ + public World getWorld() + { + return getEntityPlayer().getEntityWorld(); + } + + /** + * @return The effective, i.e. logical, side of this interaction. This will be {@link Side#CLIENT} on the client thread, and {@link Side#SERVER} on the server thread. + */ + public Side getSide() + { + return getWorld().isRemote ? Side.CLIENT : Side.SERVER; } - public Action getAction() { return action; } - public World getWorld() { return world; } - public BlockPos getPos() { return pos; } - public EnumFacing getFace() { return face; } - public Vec3d getLocalPos() { return localPos; } - public Result getUseBlock() { return useBlock; } - public void setUseBlock(Result useBlock) { this.useBlock = useBlock; } - public Result getUseItem() { return useItem; } - public void setUseItem(Result useItem) { this.useItem = useItem; } } diff --git a/src/test/java/net/minecraftforge/test/PlayerInteractEventLocalTest.java b/src/test/java/net/minecraftforge/test/PlayerInteractEventLocalTest.java deleted file mode 100644 index 16da5af0b..000000000 --- a/src/test/java/net/minecraftforge/test/PlayerInteractEventLocalTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.minecraftforge.test; - -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.eventhandler.SubscribeEvent; - -@Mod(modid="PlayerInteractEventLocalTest", name="PlayerInteractEventLocalTest", version="0.0.0") -public class PlayerInteractEventLocalTest -{ - - public static final boolean ENABLE = false; - - @EventHandler - public void init(FMLInitializationEvent event) - { - MinecraftForge.EVENT_BUS.register(this); - } - - @SubscribeEvent - public void onPlayerInteract(PlayerInteractEvent event) - { - if(ENABLE && event.getLocalPos() != null) { - System.out.println(event.getLocalPos().toString()); - } - } -} diff --git a/src/test/java/net/minecraftforge/test/PlayerInteractEventTest.java b/src/test/java/net/minecraftforge/test/PlayerInteractEventTest.java new file mode 100644 index 000000000..97739dd87 --- /dev/null +++ b/src/test/java/net/minecraftforge/test/PlayerInteractEventTest.java @@ -0,0 +1,154 @@ +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.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityChest; +import net.minecraft.tileentity.TileEntityDropper; +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") +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); + } + + @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() != null) + { + 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() != null && 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() != null && evt.getItemStack().getItem() == Items.painting) { + evt.setUseItem(Event.Result.ALLOW); + } + + // Spawn egg in main hand, block in offhand -> block should be placed + // Sword in main hand, spawn egg in offhand -> nothing should happen + if (evt.getItemStack() != null && evt.getItemStack().getItem() == Items.spawn_egg) { + evt.setCanceled(true); + } + + + } + + @SubscribeEvent + public void rightClickItem(PlayerInteractEvent.RightClickItem evt) + { + if (!ENABLE) return; + + // Use survival mode + // 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() != null && 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() != null + && 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.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 becomes wither skeleton. Otherwise nothing happens. + ((EntitySkeleton) evt.getTarget()).setSkeletonType(1); + evt.setCanceled(true); + } + } + + @SubscribeEvent + public void interactNormal(PlayerInteractEvent.EntityInteract evt) + { + if (!ENABLE) return; + + if (evt.getItemStack() != null && (evt.getTarget() instanceof EntityHorse || evt.getTarget() instanceof EntityCreeper)) + // Should not be able to feed wild horses with golden apple (you will start eating it in survival) + // Should not be able to ignite creeper with F+S + // Applies to both hands + evt.setCanceled(true); + } +} diff --git a/src/test/java/net/minecraftforge/test/TestCapabilityMod.java b/src/test/java/net/minecraftforge/test/TestCapabilityMod.java index d6babd4b3..44a6d2224 100644 --- a/src/test/java/net/minecraftforge/test/TestCapabilityMod.java +++ b/src/test/java/net/minecraftforge/test/TestCapabilityMod.java @@ -42,11 +42,10 @@ public class TestCapabilityMod } @SubscribeEvent - public void onInteract(PlayerInteractEvent event) + public void onInteract(PlayerInteractEvent.LeftClickBlock event) { - if (event.getAction() != PlayerInteractEvent.Action.LEFT_CLICK_BLOCK) return; - if (event.getEntityPlayer().inventory.getCurrentItem() == null) return; - if (event.getEntityPlayer().inventory.getCurrentItem().getItem() != Items.stick) return; + if (event.getItemStack() == null) return; + if (event.getItemStack().getItem() != Items.stick) return; // This is just a example of how to interact with the TE, note the strong type binding that getCapability has TileEntity te = event.getWorld().getTileEntity(event.getPos());