关于forge和bukkit通信,查阅了很多资料发现大多都已经过时,或是不详细。自己折腾了一番,记录一下
forge 接收方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| @Mod("story_hud_show") public class StoryHudShow { private SimpleChannel channel; private static final int idx = 222;
public static String[] data = {"23456","星期天14日","上午9:00"};
public StoryHudShow() { ... }
private void setup(final FMLCommonSetupEvent event) { channel = NetworkRegistry.ChannelBuilder.named(new ResourceLocation("story_hud_show", "main_channel")) .networkProtocolVersion(() -> "bzdo") .serverAcceptedVersions(NetworkRegistry.ACCEPTVANILLA::equals) .clientAcceptedVersions(NetworkRegistry.ACCEPTVANILLA::equals) .simpleChannel(); channel.registerMessage(idx,String.class,this::enc,this::dec,this::proc); } private void enc(String str, FriendlyByteBuf buffer) { buffer.writeBytes(str.getBytes(StandardCharsets.UTF_8)); }
private String dec(FriendlyByteBuf buffer) { return buffer.toString(StandardCharsets.UTF_8); }
private void proc(String str, Supplier<NetworkEvent.Context> supplier) { System.out.println(str); data = str.split("/"); NetworkEvent.Context context = supplier.get(); context.setPacketHandled(true); channel.reply("rpl", context); } }
|
ChannelBuilder用于构建一个频道,显而易见是一个工厂类,所示代码中用到的方法解释如下
named 其中需传入一个ResourceLocation,如资源文件一般的引用方式 namespace:path
networkProtocolVersion 为网络协议版本
server||client AcceptedVersion 参数为NetworkRegistry.ACCEPTVANILLA::equals表示允许未安装forge的原版客户端进入
最后使用simpleChannel得到SimpleChannel对象
SimpleChannel就是我们的主角了,接下来使用registerMessage注册完消息种类
channel.registerMessage(idx,String.class,this::enc,this::dec,this::proc);
其中,idx用于区分不同的消息类型;第二个参数为数据类型,在示例中使用String;后面跟着的分别是编码和解码的处理方法
如此,我们便完成了消息频道的注册,proc便是接收消息的处理了,其中的channel.reply为接收到消息后,对服务端的回复
(其实不写也无关紧要,只是会刷报错不雅观,当然玩家也看不到)
bukkit 发送方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public final class StarHudServerPackPlugin extends JavaPlugin implements Listener { private static final int idx = 222; private final String channel = "star_hud_show:main_channel"; @Override public void onEnable() { getServer().getMessenger().registerIncomingPluginChannel(this,channel,(channel,player,message)->{ getLogger().info("received message from client"); getLogger().info(message.toString()); }); getServer().getMessenger().registerOutgoingPluginChannel(this, channel); getServer().getPluginManager().registerEvents(this, this); }
private void send(Player player, String msg) { msg = "23846"+"/"+"星期天14日"+"/"+"上午9:00"; byte[] bytes = msg.getBytes(StandardCharsets.UTF_8); ByteBuf buf = Unpooled.buffer(bytes.length + 1); buf.writeByte(idx); buf.writeBytes(bytes); player.sendPluginMessage(this, channel, buf.array()); }
private String read(byte[] array) { ByteBuf buf = Unpooled.wrappedBuffer(array); if (buf.readUnsignedByte() == idx) { return buf.toString(StandardCharsets.UTF_8); } else throw new RuntimeException(); }
@EventHandler void onJoin(PlayerJoinEvent event){ Player player = event.getPlayer(); try { Class<? extends CommandSender> senderClass = player.getClass(); Method addChannel = senderClass.getDeclaredMethod("addChannel", String.class); addChannel.setAccessible(true); addChannel.invoke(player, channel); } catch (Exception e) { e.printStackTrace(); } Bukkit.getScheduler().runTaskLater(this, () -> send(player, "23846"+"/"+"星期天14日"+"/"+"上午9:00"), 100); }
@Override public void onDisable() { } }
|
bukkit的代码就较为熟悉了,其中疑惑是这个丑陋的反射是怎么回事?
原因是在1.13之后的版本,forge客户端不会在加入前向服务器注册消息通道,只能用反射假装我们已经收到了register包hh
有了forge和bukkit通信,可以做到很多有意思的事情,且负荷都在客户端,服务端只需发个包就好了。那些付费的龙核,vv等也都是一样的原理
比如说,用hud展示服务器信息,这可比计分板优雅多了
本文标题:1.16+的forge与bukkit通信
文章作者:meteor
发布时间:2023-08-18
最后更新:2023-08-18
原始链接:http://blog.zsenhe.com/2023/08/18/1.16+%E7%9A%84forge%E4%B8%8Ebukkit%E9%80%9A%E4%BF%A1/
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!