You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Minecraft Bukkit插件:手持物品时取消左键挥臂动画失败

问题:手持指定物品时取消左键手臂挥动动画

原实现代码

@EventHandler
public void left(PlayerAnimationEvent event) {
    Player plr = event.getPlayer();
    ItemStack hand = plr.getInventory().getItemInMainHand();

    if (event.getAnimationType() == PlayerAnimationType.ARM_SWING) {
        if (hand.getType() == Material.DIAMOND) {
            event.setCancelled(true);
            getLogger().info(plr.getName() + "  diamond  ");
        } else {
            getLogger().info(plr.getName() + "  not diamond  " + hand.getType());
        }
    }
}

服务器日志输出

[03:53:33] [Server thread/INFO]: [EE2] FN7182  not diamond  AIR
[03:53:33] [Server thread/INFO]: [EE2] FN7182  not diamond  AIR
[03:53:34] [Server thread/INFO]: [EE2] FN7182  not diamond  IRON_SWORD
[03:53:35] [Server thread/INFO]: [EE2] FN7182  not diamond  IRON_SWORD
[03:53:36] [Server thread/INFO]: [EE2] FN7182  diamond
[03:53:36] [Server thread/INFO]: [EE2] FN7182  diamond

问题原因

PlayerAnimationEvent的setCancelled(true)仅能阻止服务端将手臂挥动的动画同步给其他玩家,无法取消触发动画的玩家自己客户端上的动画播放——因为客户端是本地触发动画后才通知服务端,此时动画已经在玩家屏幕上显示了。

解决方案

1. 仅阻止其他玩家看到动画(原代码优化)

原代码其实已经实现了这个效果,如果你只需要其他玩家看不到目标玩家的挥动手臂动画,无需修改代码,只是玩家自己仍会看到动画。

2. 拦截左键点击触发的动画(覆盖点击场景)

如果你的需求是玩家点击左键(空气/方块)时取消动画,可以监听PlayerInteractEvent,在事件触发时直接取消,从源头阻止动画触发:

@EventHandler
public void onLeftClickInteract(PlayerInteractEvent event) {
    Player player = event.getPlayer();
    ItemStack mainHand = player.getInventory().getItemInMainHand();
    
    // 检测是否是左键点击动作
    Action action = event.getAction();
    if ((action == Action.LEFT_CLICK_AIR || action == Action.LEFT_CLICK_BLOCK) 
        && mainHand.getType() == Material.DIAMOND) {
        // 取消点击事件,阻止动画触发
        event.setCancelled(true);
        getLogger().info(player.getName() + "  diamond  ");
    } else {
        getLogger().info(player.getName() + "  not diamond  " + mainHand.getType());
    }
}

这种方式可以阻止玩家点击左键时的动画,但无法处理玩家单纯挥动手臂(未点击)的场景。

3. 全场景阻止动画(需依赖ProtocolLib)

如果要覆盖所有挥动手臂的场景(包括单纯挥臂),需要使用ProtocolLib拦截客户端发送的动画数据包,同时阻止服务端同步:

import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;

// 在插件启用时注册数据包监听器
public void onEnable() {
    ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(this, ListenerPriority.NORMAL, PacketType.Play.Client.ANIMATION) {
        @Override
        public void onPacketReceiving(PacketEvent event) {
            Player player = event.getPlayer();
            if (player.getInventory().getItemInMainHand().getType() == Material.DIAMOND) {
                // 拦截客户端发送的挥臂数据包,服务端不会处理,也不会同步给其他玩家
                event.setCancelled(true);
            }
        }
    });
}

注意:这种方式仍无法完全阻止玩家自己客户端的动画(因为客户端本地播放动画不依赖服务端响应),但可以确保其他玩家看不到动画,同时服务端不会处理该动画事件。

补充说明

纯服务端插件无法完全取消玩家自己客户端上的手臂挥动动画,因为该动画是客户端本地触发的。如果需要让玩家自己也看不到动画,必须借助客户端mod或资源包修改动画逻辑。

内容的提问来源于stack exchange,提问作者Async

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 06:29:58