diff --git a/src/main/java/net/fabricmc/fabric/events/PlayerInteractionEvent.java b/src/main/java/net/fabricmc/fabric/events/PlayerInteractionEvent.java index 70b5a97f1..388d4bf3a 100644 --- a/src/main/java/net/fabricmc/fabric/events/PlayerInteractionEvent.java +++ b/src/main/java/net/fabricmc/fabric/events/PlayerInteractionEvent.java @@ -32,10 +32,16 @@ import net.minecraft.world.World; * * These hook in BEFORE the spectator checks, so make sure to check for the player's game mode as well! * + * In general, the events return an ActionResult with the following side effects: + * - SUCCESS cancels further processing and, on the client, sends a packet to the server. + * - PASS falls back to further processing. + * - FAIL cancels further processing and does not send a packet to the server. + * * CURRENT LIMITATIONS: * * - INTERACT_BLOCK/INTERACT_ITEM do not expect the ItemStack instance in the player's held hand to change! * If you must do that, consider returning an ActionResult.SUCCESS and re-emitting the event in some manner! + * - ATTACK_BLOCK does not let you control the packet sending process yet. */ public final class PlayerInteractionEvent { @FunctionalInterface diff --git a/src/main/java/net/fabricmc/fabric/mixin/events/playerinteraction/MixinClientPlayerInteractionManager.java b/src/main/java/net/fabricmc/fabric/mixin/events/playerinteraction/MixinClientPlayerInteractionManager.java index edaf2817e..ee9d139dc 100644 --- a/src/main/java/net/fabricmc/fabric/mixin/events/playerinteraction/MixinClientPlayerInteractionManager.java +++ b/src/main/java/net/fabricmc/fabric/mixin/events/playerinteraction/MixinClientPlayerInteractionManager.java @@ -26,6 +26,8 @@ import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.network.packet.PlayerInteractBlockServerPacket; +import net.minecraft.server.network.packet.PlayerInteractEntityServerPacket; +import net.minecraft.server.network.packet.PlayerInteractItemServerPacket; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.HitResult; @@ -100,11 +102,14 @@ public class MixinClientPlayerInteractionManager { } } - @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;getStackInHand(Lnet/minecraft/util/Hand;)Lnet/minecraft/item/ItemStack;", ordinal = 0), method = "interactItem", cancellable = true) + @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/Packet;)V", ordinal = 0), method = "interactItem", cancellable = true) public void interactItem(PlayerEntity player, World world, Hand hand, CallbackInfoReturnable info) { for (PlayerInteractionEvent.Item handler : ((HandlerArray) PlayerInteractionEvent.INTERACT_ITEM).getBackingArray()) { ActionResult result = handler.interact(player, world, hand); if (result != ActionResult.PASS) { + if (result == ActionResult.SUCCESS) { + this.networkHandler.sendPacket(new PlayerInteractItemServerPacket(hand)); + } info.setReturnValue(result); info.cancel(); return; @@ -112,18 +117,21 @@ public class MixinClientPlayerInteractionManager { } } - @Inject(at = @At("HEAD"), method = "attackEntity", cancellable = true) + @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/Packet;)V", ordinal = 0), method = "attackEntity", cancellable = true) public void attackEntity(PlayerEntity player, Entity entity, CallbackInfo info) { for (PlayerInteractionEvent.Entity handler : ((HandlerArray) PlayerInteractionEvent.ATTACK_ENTITY).getBackingArray()) { ActionResult result = handler.interact(player, player.getEntityWorld(), Hand.MAIN /* TODO */, entity); if (result != ActionResult.PASS) { + if (result == ActionResult.SUCCESS) { + this.networkHandler.sendPacket(new PlayerInteractEntityServerPacket(entity)); + } info.cancel(); return; } } } - @Inject(at = @At("HEAD"), method = "interactEntityAtLocation", cancellable = true) + @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/Packet;)V", ordinal = 0), method = "interactEntityAtLocation", cancellable = true) public void interactEntityAtLocation(PlayerEntity player, Entity entity, HitResult hitResult, Hand hand, CallbackInfoReturnable info) { // TODO: Remove double Vec3d creation? Vec3d hitVec = new Vec3d(hitResult.pos.x - entity.x, hitResult.pos.y - entity.y, hitResult.pos.z - entity.z); @@ -131,6 +139,9 @@ public class MixinClientPlayerInteractionManager { for (PlayerInteractionEvent.EntityPositioned handler : ((HandlerArray) PlayerInteractionEvent.INTERACT_ENTITY_POSITIONED).getBackingArray()) { ActionResult result = handler.interact(player, player.getEntityWorld(), hand, entity, hitVec); if (result != ActionResult.PASS) { + if (result == ActionResult.SUCCESS) { + this.networkHandler.sendPacket(new PlayerInteractEntityServerPacket(entity, hand, hitVec)); + } info.setReturnValue(result); info.cancel(); return;