Minecraft(我的世界)中文论坛

标题: 1.13+ 中 Forge 与 Bukkit 的通信

作者: 海螺螺    时间: 2019-6-14 17:29
标题: 1.13+ 中 Forge 与 Bukkit 的通信
本帖最后由 海螺螺 于 2020-1-27 12:58 编辑

1.13+ 中 Forge 与 Bukkit 的通信

1.12 及以下
1.13 的 Forge 已经更新几个月,变化较大,包括 Plugin Message Channel 的变化。废话在另一篇已经说得比较多了,因此直接上内容。

Forge 接收消息
代码如下,Forge 1.13 自身的一些新用法就不做介绍了。

@Mod("msgtutor")
public class MsgTutorMod {
    private static final int IDX = 233;
    private SimpleChannel channel;
    public MsgTutorMod() {
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::clientSetup);
    }

    private void clientSetup(FMLClientSetupEvent event) {
        channel = NetworkRegistry.ChannelBuilder
                .named(new ResourceLocation("msgtutor", "test"))
                .networkProtocolVersion(() -> "zzzz")
                .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, PacketBuffer buffer) {
        buffer.writeBytes(str.getBytes(StandardCharsets.UTF_8));
    }

    private String dec(PacketBuffer buffer) {
        return buffer.toString(StandardCharsets.UTF_8);
    }

    private void proc(String str, Supplier<NetworkEvent.Context> supplier) {
        System.out.println(str);
        NetworkEvent.Context context = supplier.get();
        context.setPacketHandled(true);
        channel.reply("client hello", context);
    }
}

1.13 中引入了一个新的 ChannelBuilder,显然比较强。其中

因为种种原因我们选择了 SimpleChannel,在创建完 channel 之后,我们就可以着手处理消息了,比如注册一个消息。

使用 registerMessage 注册一种消息,其中

然后我们就注册了一条消息,只要服务器发过来了消息,我们就能接收到。

再看到 proc 方法,这是我们处理接收到消息的方法,输出就不说了,但是
Bukkit 发送接收部分
代码如下
public final class Test extends JavaPlugin implements Listener {
    private static final int IDX = 233;
    private final String channel = "msgtutor:test";

    @Override
    public void onEnable() {
        getServer().getMessenger().registerIncomingPluginChannel(this, channel,
            (channel, player, message) ->
                        System.out.println("awsl " + read(message)));
        getServer().getMessenger().registerOutgoingPluginChannel(this, channel);
        getServer().getPluginManager().registerEvents(this, this);
    }

    @EventHandler
    public 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, "server hello"), 100);
    }

    private void send(Player player, String msg) {
        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();
    }

}

在 onEnable 中
为演示,我们监听玩家加入游戏的事件

发送的逻辑在 send 方法里
现在来到了最后一个问题,那个莫名其妙的反射是啥?
在 Forge 1.13 以前,Forge 客户端在加入服务器之前,会向服务器发送 register 包来注册插件消息通道,而 1.13 和之后的版本却不这么做了,而服务器在没有收到 register 包之前,调用的 sendPluginMessage 方法都不会真正发送出去。详情在这个 issue 里,cpw 表示关我 Forge 什么事,找 Spigot 去。
我们没有办法,毕竟我们不是 cpw 或者 Lex,所以我们只能自己动手丰衣足食,也就是假装我们收到了 register 包,也就是那个反射。
至于反射很丑,而由于作者懒的原因,没有研究用客户端发 register 包的方法。不过也好,这样子的话,想发包就不用像老版本那样等那几秒钟之后再发了。这也是为什么老版本需要等几秒才能发包的原因。




[groupid=1330]PluginsCDTribe[/groupid]
作者: skyliye    时间: 2019-6-14 18:15
我在想,会不会出来1.14的Bukkit+mod的服务端,其实蛮期待的
如果能同时兼容Forgemod+Fabricmod+bukkit+sponge插件岂不美哉(有生之年系列)
作者: 森林蝙蝠    时间: 2019-6-14 19:23
skyliye 发表于 2019-6-14 18:15
我在想,会不会出来1.14的Bukkit+mod的服务端,其实蛮期待的
如果能同时兼容Forgemod+Fabricmod+bukkit+spo ...

fabric+bukkit目前开发者在做。
作者: MC_Huo_Shen    时间: 2019-6-15 13:56
看不懂554654455454
作者: 老油人    时间: 2019-6-16 22:59
23333333333
作者: 简爱爱    时间: 2019-6-16 23:48
提示: 作者被禁止或删除 内容自动屏蔽
作者: slyz    时间: 2019-6-17 11:00
6666666666
作者: 404565377    时间: 2019-6-18 16:40
简爱爱 发表于 2019-6-16 23:48
互通又有什么用呢?大佬的想法我不懂。

和客户端通信,就不用在服务端装mod了
作者: Deeplypie    时间: 2019-6-20 00:00
感谢服主的分享!