温馨提示: 这篇文章于2519天前编写,现在可能不再适用或落后.

好久没动过bukkit了,很久没玩过mc了....前几天一个需求所以折腾了一下bukkit,使用bukkitapi向玩家发送sign的open和Update包也就是打开sign和修改sign的信息,然后我找了一些插件研究.

最后2种方法,1.使用ProtocolLib发包,2.艹nms

bukkitapi貌似就是不能发...据我所知,,我就用过bukkitapi修改过sign木牌信息..让玩家打开sigin到没怎么做过

最后当然是选择用ProtocolLib发包咯,nms太麻烦了(nms发包见最下面)

上图是之前插件一张图片...懒得开游戏弄一张...无视木牌内容就行....

先自行下载protocolib的插件吧:https://www.spigotmc.org/resources/protocollib.1997/

自行在plugin.yml里面添加

depend: [ProtocolLib]

先获取ProtocolManager

ProtocolManager pm = ProtocolLibrary.getProtocolManager();

注意:v1_8_3的核心及以上的版本和v1_8_3以下的核心版本发包是不同的所以需要区分一下

另外,游戏版本1.10以上的PacketPlayOutUpdateSign这个包没有了,所以无法在游戏1.10及以上使用

v1_8_3版本以下的发包代码

public static void send17Pack(Player p,String[] lines){
    ProtocolManager pm = ProtocolLibrary.getProtocolManager();
    try {
        int x = p.getLocation().getBlockX();
        int z = p.getLocation().getBlockZ();
        PacketContainer change = pm.createPacket(PacketType.Play.Server.BLOCK_CHANGE);
        change.getIntegers().write(0,x);
        change.getIntegers().write(1,0);
        change.getIntegers().write(2,z);
        change.getIntegers().write(3,0);
        change.getBlocks().write(0, Material.SIGN_POST);
        pm.sendServerPacket(p, change);

        PacketContainer update = pm.createPacket(PacketType.Play.Server.UPDATE_SIGN);
        update.getIntegers().write(0,x);
        update.getIntegers().write(1,0);
        update.getIntegers().write(2,z);
        update.getStringArrays().write(0,lines);
        pm.sendServerPacket(p, update);

        PacketContainer open = pm.createPacket(PacketType.Play.Server.OPEN_SIGN_ENTITY);
        open.getIntegers().write(0,x);
        open.getIntegers().write(1,0);
        open.getIntegers().write(2,z);
        pm.sendServerPacket(p, open);
    } catch (Exception e) {
            e.printStackTrace();
    }
}

v1_8_3版本及以上的发包代码

public static void send18Pack(Player p,String[] lines){
    ProtocolManager pm = ProtocolLibrary.getProtocolManager();
    try {
        int x = p.getLocation().getBlockX();
        int z = p.getLocation().getBlockZ();
        PacketContainer change = pm.createPacket(PacketType.Play.Server.BLOCK_CHANGE);
        change.getBlockPositionModifier().write(0, new BlockPosition(x, 0, z));
        change.getBlockData().write(0, WrappedBlockData.createData(Material.SIGN_POST));
        pm.sendServerPacket(p, change);

        PacketContainer update = pm.createPacket(PacketType.Play.Server.UPDATE_SIGN);
        update.getBlockPositionModifier().write(0, new BlockPosition(x, 0, z));
        update.getChatComponentArrays().write(0, new WrappedChatComponent[] { 
            WrappedChatComponent.fromText(lines[0]), 
            WrappedChatComponent.fromText(lines[1]), 
            WrappedChatComponent.fromText(lines[2]), 
            WrappedChatComponent.fromText(lines[3]) });
         pm.sendServerPacket(p, update);

         PacketContainer open = pm.createPacket(PacketType.Play.Server.OPEN_SIGN_ENTITY);
         open.getBlockPositionModifier().write(0, new BlockPosition(x, 0, z));
         pm.sendServerPacket(p, open);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

上面的代码是发了3个包,一个修改方块,一个修改sign,一个发送sign

对应sign的2个包在nms里面是PacketPlayOutUpdateSign 和PacketPlayOutOpenSignEditor 

对应的参数可以反编译查看(写这篇的时候我是linux,,,,无奈jd-gui一直下载不下来...)

捕捉sign修改的包也可以用protocolib捕捉,先创建一个类用于监听

//自行导包(纯手打...)
public class SignUpdate extends PacketAdapter implements PacketListener{
    public SignUpdate(Plugin plugin, PacketType[] packets) {
    super(plugin,packets);
    }
    public void onPacketReceiving(PacketEvent e){
        PacketContainer pack = e.getPacket();
        if(pack.getType()==PacketType.Play.Client.UPDATE_SIGN){
            //sign修改触发
            //如果需要获取修改的内容,那么v1_8_3版本也会有区分
            //v1_8_3以下版本
            String[] signLine = (String[])pack.getStringArrays().getValues().get(0);
            //v1_8_3以上版本
            WrappedChatComponent[] signLine = (WrappedChatComponent[])pack.getChatComponentArrays().read(0);
            
            //然后这个signLine就是木牌修改的值了
            //signLine[0] signLine[1] signLine[2] signLine[3]
        }
    }
    
}

注册

//主类中添加
ProtocolManager pm = ProtocolLibrary.getProtocolManager();
PacketType[] packs = { PacketType.Play.Client.UPDATE_SIGN };
pm.addPacketListener(new SignUpdateEvent(主类,packs));

最后向玩家发送包

String[] lines = {"第一行文字","第二行文字","第三行文字","第四行文字"};
Player p = Bukkit.getServer().getPlayer("xxxx");
this.send18Pack(p,lines);//v1_8_3版本
this.send17Pack(p,lines);//v1_8_3以下版本

如何区分呢?自行判断当前版本号然后比较就ok了

关于nms发包的方法,我这里只写1.8.3以上的发包方法

v1_8_3版本及以上使用NMS的发包代码

public void openSign(Player player,String[] lines){
    //获取nms和craftbukkit的一些东西
    CraftPlayer p = (CraftPlayer)player;
    CraftWorld cw = (CraftWorld)p.getWorld();
    PlayerConnection pc = p.getHandle().playerConnection;
    //这里的World类是nms里面的World类  net.minecraft.server.v1_8_3.World
    World nmsWorld = (World)cw.getHandle();
    //获取一个方块的坐标
    BlockPosition block = new BlockPosition(p.getLocation().getBlockX(),0,p.getLocation().getBlockZ());
    //修改方块(因为后面需要修改内容)
    PacketPlayOutBlockChange change = new PacketPlayOutBlockChange(nmsWorld,block);
    change.block = Blocks.STANDING_SIGN.getBlockData();
    pc.sendPacket(change);
    //修改木牌
    PacketPlayOutUpdateSign update = new PacketPlayOutUpdateSign(nmsWorld,block,new IChatBaseComponent[]{
        ChatSerializer.a(lines[0]),
                ChatSerializer.a(lines[1]),
        ChatSerializer.a(lines[2]),
        ChatSerializer.a(lines[3])
        });
    pc.sendPacket(update);
    //打开
    PacketPlayOutOpenSignEditor open = new PacketPlayOutOpenSignEditor(block);
    pc.sendPacket(open);
}

其实方法和ProtocolLib发包区别不是很大,但是nms每个版本的包名都不同啊,而且有些类的方法名称也是改了的,比如这个版本是v1_8_3另一个版本是v1_8_2那么包名就完全不同的

以上就是ProtocolLib和nms的发包方法

注:因为修改木牌需要修改方块,所以一般都是把木牌放到基岩底层也就是0的位置,如果不放心,可以在修改完成的时候删除这个方块

    阁下需要登录后才可以查看评论哦~

    随便看看

      载入中...

      正在准备穿越次元,阁下请稍等片刻~