mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-05 19:47:00 -04:00
add entity interaction events
This commit is contained in:
parent
4d3bd0d35f
commit
b291a955de
6 changed files with 162 additions and 9 deletions
src/main
|
@ -23,12 +23,15 @@ import net.minecraft.util.ActionResult;
|
|||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Facing;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* This is a class for INTERACTION EVENTS (think left-clicking/right-clicking). For block placement/break
|
||||
* events, look elsewhere - this just handles the interaction!
|
||||
*
|
||||
* These hook in BEFORE the spectator checks, so make sure to check for the player's game mode as well!
|
||||
*
|
||||
* CURRENT LIMITATIONS:
|
||||
*
|
||||
* - INTERACT_BLOCK/INTERACT_ITEM do not expect the ItemStack instance in the player's held hand to change!
|
||||
|
@ -40,20 +43,39 @@ public final class PlayerInteractionEvent {
|
|||
ActionResult interact(PlayerEntity player, World world, Hand hand, BlockPos pos, Facing facing);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Entity {
|
||||
ActionResult interact(PlayerEntity player, World world, Hand hand, net.minecraft.entity.Entity entity);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface BlockPositioned {
|
||||
ActionResult interact(PlayerEntity player, World world, Hand hand, BlockPos pos, Facing facing, float hitX, float hitY, float hitZ);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface EntityPositioned {
|
||||
ActionResult interact(PlayerEntity player, World world, Hand hand, net.minecraft.entity.Entity entity, Vec3d hitPos);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Item {
|
||||
ActionResult interact(PlayerEntity player, World world, Hand hand);
|
||||
}
|
||||
|
||||
public static final HandlerRegistry<Block> BREAK_BLOCK = new HandlerList<>();
|
||||
public static final HandlerRegistry<Block> ATTACK_BLOCK = new HandlerList<>();
|
||||
public static final HandlerRegistry<Entity> ATTACK_ENTITY = new HandlerList<>();
|
||||
|
||||
// TODO: For completeness' sake, but requires us to add a custom packet. Is it worth the complexity?
|
||||
/* public static final HandlerRegistry<Item> ATTACK_ITEM = new HandlerList<>(); */
|
||||
|
||||
public static final HandlerRegistry<BlockPositioned> INTERACT_BLOCK = new HandlerList<>();
|
||||
public static final HandlerRegistry<EntityPositioned> INTERACT_ENTITY_POSITIONED = new HandlerList<>();
|
||||
public static final HandlerRegistry<Item> INTERACT_ITEM = new HandlerList<>();
|
||||
|
||||
@Deprecated
|
||||
public static final HandlerRegistry<Block> BREAK_BLOCK = ATTACK_BLOCK;
|
||||
|
||||
private PlayerInteractionEvent() {
|
||||
|
||||
}
|
||||
|
|
|
@ -22,21 +22,18 @@ import net.minecraft.client.MinecraftClient;
|
|||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.network.ClientPlayerInteractionManager;
|
||||
import net.minecraft.client.network.packet.BlockUpdateClientPacket;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.network.ServerPlayerInteractionManager;
|
||||
import net.minecraft.server.network.packet.PlayerInteractBlockServerPacket;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.HitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Facing;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.GameMode;
|
||||
import net.minecraft.world.World;
|
||||
import org.lwjgl.system.CallbackI;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
@ -55,7 +52,7 @@ public class MixinClientPlayerInteractionManager {
|
|||
|
||||
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/world/GameMode;isCreative()Z", ordinal = 0), method = "attackBlock", cancellable = true)
|
||||
public void attackBlock(BlockPos pos, Facing facing, CallbackInfoReturnable<Boolean> info) {
|
||||
for (Object handler : ((HandlerList<PlayerInteractionEvent.Block>) PlayerInteractionEvent.BREAK_BLOCK).getBackingArray()) {
|
||||
for (Object handler : ((HandlerList<PlayerInteractionEvent.Block>) PlayerInteractionEvent.ATTACK_BLOCK).getBackingArray()) {
|
||||
PlayerInteractionEvent.Block event = (PlayerInteractionEvent.Block) handler;
|
||||
ActionResult result = event.interact(client.player, client.world, Hand.MAIN, pos, facing);
|
||||
if (result != ActionResult.PASS) {
|
||||
|
@ -72,7 +69,7 @@ public class MixinClientPlayerInteractionManager {
|
|||
return;
|
||||
}
|
||||
|
||||
for (Object handler : ((HandlerList<PlayerInteractionEvent.Block>) PlayerInteractionEvent.BREAK_BLOCK).getBackingArray()) {
|
||||
for (Object handler : ((HandlerList<PlayerInteractionEvent.Block>) PlayerInteractionEvent.ATTACK_BLOCK).getBackingArray()) {
|
||||
PlayerInteractionEvent.Block event = (PlayerInteractionEvent.Block) handler;
|
||||
ActionResult result = event.interact(client.player, client.world, Hand.MAIN, pos, facing);
|
||||
if (result != ActionResult.PASS) {
|
||||
|
@ -118,4 +115,32 @@ public class MixinClientPlayerInteractionManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "attackEntity", cancellable = true)
|
||||
public void attackEntity(PlayerEntity player, Entity entity, CallbackInfo info) {
|
||||
for (Object handler : ((HandlerList<PlayerInteractionEvent.Entity>) PlayerInteractionEvent.ATTACK_ENTITY).getBackingArray()) {
|
||||
PlayerInteractionEvent.Entity event = (PlayerInteractionEvent.Entity) handler;
|
||||
ActionResult result = event.interact(player, player.getEntityWorld(), Hand.MAIN /* TODO */, entity);
|
||||
if (result != ActionResult.PASS) {
|
||||
info.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "interactEntityAtLocation", cancellable = true)
|
||||
public void interactEntityAtLocation(PlayerEntity player, Entity entity, HitResult hitResult, Hand hand, CallbackInfoReturnable<ActionResult> 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);
|
||||
|
||||
for (Object handler : ((HandlerList<PlayerInteractionEvent.EntityPositioned>) PlayerInteractionEvent.INTERACT_ENTITY_POSITIONED).getBackingArray()) {
|
||||
PlayerInteractionEvent.EntityPositioned event = (PlayerInteractionEvent.EntityPositioned) handler;
|
||||
ActionResult result = event.interact(player, player.getEntityWorld(), hand, entity, hitVec);
|
||||
if (result != ActionResult.PASS) {
|
||||
info.setReturnValue(result);
|
||||
info.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.events;
|
||||
|
||||
import net.fabricmc.fabric.events.PlayerInteractionEvent;
|
||||
import net.fabricmc.fabric.util.HandlerList;
|
||||
import net.minecraft.client.network.packet.BlockUpdateClientPacket;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.network.ServerPlayerInteractionManager;
|
||||
import net.minecraft.server.network.packet.PlayerInteractEntityServerPacket;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Facing;
|
||||
import net.minecraft.world.World;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(ServerPlayNetworkHandler.class)
|
||||
public class MixinServerPlayNetworkHandler {
|
||||
@Shadow
|
||||
public ServerPlayerEntity player;
|
||||
|
||||
@Inject(method = "onPlayerInteractEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;interactAt(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;"), cancellable = true)
|
||||
public void onPlayerInteractEntity(PlayerInteractEntityServerPacket packet, CallbackInfo info) {
|
||||
for (Object handler : ((HandlerList<PlayerInteractionEvent.EntityPositioned>) PlayerInteractionEvent.INTERACT_ENTITY_POSITIONED).getBackingArray()) {
|
||||
PlayerInteractionEvent.EntityPositioned event = (PlayerInteractionEvent.EntityPositioned) handler;
|
||||
ActionResult result = event.interact(player, player.getEntityWorld(), packet.getHand(), packet.getEntity(player.world), packet.getHitPosition());
|
||||
if (result != ActionResult.PASS) {
|
||||
info.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.events;
|
||||
|
||||
import net.fabricmc.fabric.events.PlayerInteractionEvent;
|
||||
import net.fabricmc.fabric.util.HandlerList;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.network.packet.PlayerInteractEntityServerPacket;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayerEntity.class)
|
||||
public class MixinServerPlayerEntity {
|
||||
@Inject(method = "attack", at = @At("HEAD"), cancellable = true)
|
||||
public void onPlayerInteractEntity(Entity target, CallbackInfo info) {
|
||||
ServerPlayerEntity player = (ServerPlayerEntity) (Object) this;
|
||||
|
||||
for (Object handler : ((HandlerList<PlayerInteractionEvent.Entity>) PlayerInteractionEvent.ATTACK_ENTITY).getBackingArray()) {
|
||||
PlayerInteractionEvent.Entity event = (PlayerInteractionEvent.Entity) handler;
|
||||
ActionResult result = event.interact(player, player.getEntityWorld(), Hand.MAIN, target);
|
||||
if (result != ActionResult.PASS) {
|
||||
info.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@ public class MixinServerPlayerInteractionManager {
|
|||
|
||||
@Inject(at = @At("HEAD"), method = "method_14263", cancellable = true)
|
||||
public void startBlockBreak(BlockPos pos, Facing facing, CallbackInfo info) {
|
||||
for (Object handler : ((HandlerList<PlayerInteractionEvent.Block>) PlayerInteractionEvent.BREAK_BLOCK).getBackingArray()) {
|
||||
for (Object handler : ((HandlerList<PlayerInteractionEvent.Block>) PlayerInteractionEvent.ATTACK_BLOCK).getBackingArray()) {
|
||||
PlayerInteractionEvent.Block event = (PlayerInteractionEvent.Block) handler;
|
||||
ActionResult result = event.interact(player, world, Hand.MAIN, pos, facing);
|
||||
if (result != ActionResult.PASS) {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
"mixins": [
|
||||
"commands.MixinServerCommandManager",
|
||||
"events.MixinMinecraftServer",
|
||||
"events.MixinServerPlayNetworkHandler",
|
||||
"events.MixinServerPlayerEntity",
|
||||
"events.MixinServerPlayerInteractionManager",
|
||||
"events.MixinWorld",
|
||||
"helpers.MixinBlock",
|
||||
|
|
Loading…
Add table
Reference in a new issue