Minecraft使用ProtocolLib向玩家发送木牌包
- 2017-05-31 22:45:51
- 幻音い
- 10067
温馨提示: 这篇文章于2730天前编写,现在可能不再适用或落后.
好久没动过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的位置,如果不放心,可以在修改完成的时候删除这个方块
阁下需要登录后才可以查看评论哦~