diff --git a/projects/fabric/src/main/java/dan200/computercraft/mixin/ItemMixin.java b/projects/fabric/src/main/java/dan200/computercraft/mixin/ItemMixin.java index b1b18593bb..9384c67425 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/mixin/ItemMixin.java +++ b/projects/fabric/src/main/java/dan200/computercraft/mixin/ItemMixin.java @@ -9,24 +9,38 @@ import net.minecraft.world.item.Item; import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(Item.class) class ItemMixin { /** * Replace the reach distance in {@link Item#getPlayerPOVHitResult(Level, Player, ClipContext.Fluid)}. * - * @param reach The original reach distance. - * @param level The current level. - * @param player The current player. - * @return The new reach distance. + * @param level The current level. + * @param player The current player. + * @param fluidMode The current clip-context fluid mode. + * @param cir Callback info to store the new reach distance. * @see FakePlayer#getBlockReach() */ - @ModifyConstant(method = "getPlayerPOVHitResult", constant = @Constant(doubleValue = 5)) + @Inject(method = "getPlayerPOVHitResult", at = @At("HEAD"), cancellable = true) @SuppressWarnings("UnusedMethod") - private static double getReachDistance(double reach, Level level, Player player) { - return player instanceof FakePlayer fp ? fp.getBlockReach() : reach; + private static void getReachDistance(Level level, Player player, ClipContext.Fluid fluidMode, CallbackInfoReturnable cir) { + // It would theoretically be cleaner to use @ModifyConstant here, but as it's treated as a @Redirect, it doesn't + // compose with other mods. Instead, we replace the method when working with our fake player. + if (player instanceof FakePlayer fp) cir.setReturnValue(getHitResult(level, fp, fluidMode)); + } + + @Unique + private static BlockHitResult getHitResult(Level level, FakePlayer player, ClipContext.Fluid fluidMode) { + var start = player.getEyePosition(); + var reach = player.getBlockReach(); + var direction = player.getViewVector(1.0f); + var end = start.add(direction.x() * reach, direction.y() * reach, direction.z() * reach); + return level.clip(new ClipContext(start, end, ClipContext.Block.OUTLINE, fluidMode, player)); } }