无敌三脚猫
首先,我对netty一窍不通,只是会依葫芦画瓢而已这篇文章讲了如何用1.12forge在客户端监听收到的数据包https://blog.techno.fish/intercepting-vanilla-minecraft-network-packets/
(唔,如果datapack翻译成数据包,那packet到底该翻译成什么好呢
文章里说要覆写SimpleChannelInboundHandler的构造函数,其实写成匿名内部类new SimpleChannelInboundHandler(false){略}也是一样的,至于@Sharable也是没必要写的,只要你保证自己不会重复注册
如果要监听发出的数据包,则要把SimpleChannelInboundHandler换成ChannelDuplexHandler,但其实ChannelDuplexHandler既可以监听收到包,也可以监听发出的包//1.12forge客户端
        @SubscribeEvent
        public void connect(FMLNetworkEvent.ClientConnectedToServerEvent event) {
                event.getManager().channel().pipeline().addBefore("packet_handler", "awa", new ChannelDuplexHandler() {
                        /*如果要顺便监听收包就写这个函数,不然不用写
                        public void channelRead(ChannelHandlerContext context, Object packet) throws Exception {
                                super.channelRead(context, packet);
                        }
                        */
                        public void write(ChannelHandlerContext context, Object packet, ChannelPromise channelPromise) throws Exception {
                                if(packet instanceof CPacketChatMessage) {
                                        ReflectionHelper.setPrivateValue(CPacketChatMessage.class, (CPacketChatMessage)packet, "hello world", 0);
                                }
                                super.write(context, packet, channelPromise);
                        }
                });
        }复制代码这里修改了客户端发出的聊天数据包,玩家说的任何话都变成了hello world
按理说应该有专门监听收包的存在,盲猜是ChannelOutboundHandlerAdapter,不过我完全不懂
如果要在服务器监听,把ClientConnectedToServerEvent换成ServerConnectionFromClientEvent,高版本这些名字会变,但也大差不差画面转到fabric,相比于forge和bukkit那样的事件总线系统,fabric的事件是真难找,而且fabric里不存在与上文的channel()等效的方法(即返回一个Channel),那就只能进行一个反的射,不知道fabric有没有forge那样辅助反射的方法        private static final MethodHandle channel_mh;
        static {
                MethodHandle mh=null;
                try {
                        Field f=ClientConnection.class.getDeclaredField("field_11651");
                        f.setAccessible(true);
                        mh=MethodHandles.lookup().unreflectGetter(f);
                }catch (IllegalAccessException | NoSuchFieldException e) {
                        e.printStackTrace();
                }
                channel_mh=mh;
        }
        @Override
        public void onInitialize() {
                        ClientPlayConnectionEvents.INIT.register((handler, client)->{
                        Channel channel=null;
                        try {
                                channel = (Channel) channel_mh.invokeExact(handler.getConnection());
                        } catch (Throwable e) {
                                e.printStackTrace();
                        }
                        channel.pipeline().addAfter("packet_handler", "awa", new ChannelDuplexHandler() {
                                @Override
                                public void write(ChannelHandlerContext context, Object packet, ChannelPromise channelPromise) throws Exception {
                                        if(packet instanceof CustomPayloadC2SPacket) {
                                                CustomPayloadC2SPacket cp=(CustomPayloadC2SPacket)packet;
                                                if(cp.getChannel().equals(CustomPayloadC2SPacket.BRAND))
                                                        cp.getData().clear().writeBytes(PacketByteBufs.create().writeString("awa"));
                                        }
                                        super.write(context, packet, channelPromise);
                                }
                        });
                });
        }
复制代码这里修改了客户端发出的BRAND频道的CustomPayloadC2SPacket的内容,而服务端可以这样接收到                ServerPlayNetworking.registerGlobalReceiver(CustomPayloadC2SPacket.BRAND, (server, player, handler, buf, responseSender) -> {
                        LOGGER.info(buf.readString());
                });复制代码[Netty Server IO #1/INFO]: awa复制代码如果要监听服务端收到/发送的包,则把上面的ClientPlayConnectionEvents改成ServerPlayConnectionEvents,如果要监听登录包(或者说握手包)则改成ClientLoginConnectionEvents/ServerLoginConnectionEventsforge似乎监听不了登录包,没有那么早的事件这套方法也可以用在bukkit里,不过bukkit有ProtocolLib就用不着这个了CustomPayload包比较特别,forge、fabric、bukkit自带了接收的方法,上面写的ServerPlayNetworking.registerGlobalReceiver就是其一,这个包在很多地方的教程都有讲https://www.mcbbs.net/thread-873219-1-1.html