【Minecraft Spigot 技術共有】パケットの送受信処理に介入する

クライアント/サーバーMODの開発に関する話題、技術交換はこちらで。質問は質問フォーラムへお願いします。
  • (PostNo.318911)

【Minecraft Spigot 技術共有】パケットの送受信処理に介入する

投稿記事by amata1219 » 2018年8月10日(金) 18:09

環境:Spigot 1.12.2
PacketHandler.classのwriteで送信処理に、channelReadで受信処理に介入します。
パケット名はnet.minecraft.server.1_12_R1.PacketPlay…より。
自由にご活用下さい_(:3 ∠ )_。

Main.class
コード: 全て選択
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;

public class Main extends JavaPlugin implements Listener{

    private static PacketInjector injector;

    @Override
    public void onEnable(){
        injector = new PacketInjector();
        getServer().getPluginManager().registerEvents(this, this);
    }

    @Override
    public void onDisable(){

    }

    @EventHandler
    public void onPlayerJoinEvent(PlayerJoinEvent e){
        injector.addPlayer(e.getPlayer());
    }

}


PacketHandler.class
コード: 全て選択
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;

public class PacketHandler extends ChannelDuplexHandler{

    private Player p;

    public PacketHandler(final Player p) {
        this.p = p;
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        super.write(ctx, msg, promise);
    }

    @Override
    public void channelRead(ChannelHandlerContext c, Object m) throws Exception {
        if(m.getClass().getSimpleName().equalsIgnoreCase("PacketPlayInChat")){
            String text = Reflection.getFieldValue(m, "a").toString();
        }
        super.channelRead(c, m);
    }

}


PacketInjector.class
コード: 全て選択
    private Field EntityPlayer_playerConnection;
    private Class<?> PlayerConnection;
    private Field PlayerConnection_networkManager;

    private Class<?> NetworkManager;
    private Field k;
    private Field m;

    public PacketInjector() {
        try{
            EntityPlayer_playerConnection = Reflection.getField(Reflection.getClass("{nms}.EntityPlayer"), "playerConnection");
            PlayerConnection = Reflection.getClass("{nms}.PlayerConnection");
            PlayerConnection_networkManager = Reflection.getField(PlayerConnection, "networkManager");
            NetworkManager = Reflection.getClass("{nms}.NetworkManager");
            k = Reflection.getField(NetworkManager, "channel");
            m = Reflection.getField(NetworkManager, "m");
        }catch(Throwable t) {
            t.printStackTrace();
        }
    }

    public void addPlayer(Player p) {
    try{
        Channel ch = getChannel(getNetworkManager(Reflection.getNmsPlayer(p)));
        if(ch.pipeline().get("PacketInjector") == null) {
            PacketHandler h = new PacketHandler(p);
            ch.pipeline().addBefore("packet_handler", "PacketInjector", h);
        }
    }catch(Throwable t) {
        t.printStackTrace();
        }
    }

    public void removePlayer(Player p) {
        try{
            Channel ch = getChannel(getNetworkManager(Reflection.getNmsPlayer(p)));
            if(ch.pipeline().get("PacketInjector") != null) {
                ch.pipeline().remove("PacketInjector");
            }
        }catch(Throwable t) {
            t.printStackTrace();
        }
    }

    private Object getNetworkManager(Object ep) throws Exception {
        return Reflection.getFieldValueT(PlayerConnection_networkManager, Reflection.getFieldValueT(EntityPlayer_playerConnection, ep));
    }

    private Channel getChannel(Object networkManager) {
        Channel ch = null;
        try{
            ch = Reflection.getFieldValueT(k, networkManager);
        }catch(Exception e) {
            ch = Reflection.getFieldValueT(m, networkManager);
        }
        return ch;
    }

}


Reflection.class
コード: 全て選択
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scoreboard.Scoreboard;

public class Reflection {

    public static Class<?> getClass(String classname) {
        try{
            String version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
            String path = classname.replace("{nms}", "net.minecraft.server."+version).replace("{nm}", "net.minecraft."+version).replace("{cb}", "org.bukkit.craftbukkit.."+version);
            return Class.forName(path);
        }catch(Throwable t){
            t.printStackTrace();
            return null;
        }
    }

    public static Object getNmsPlayer(Player p) throws Exception {
        Method getHandle = p.getClass().getMethod("getHandle");
        return getHandle.invoke(p);
    }

    public static Object getNmsScoreboard(Scoreboard s) throws Exception {
        Method getHandle = s.getClass().getMethod("getHandle");
        return getHandle.invoke(s);
    }

    public static Object getFieldValue(Object instance, String fieldName) throws Exception {
        Field field = instance.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        return field.get(instance);
    }

    @SuppressWarnings("unchecked")
    public static  <T> T getFieldValueT(Field field, Object obj) {
        try{
            return (T) field.get(obj);
        }catch(Exception e) {
            e.printStackTrace();
            return null;
          }
    }

    public static Field getField(Class<?> clazz, String fieldName) throws Exception {
        Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        return field;
    }

    public static void setValue(Object instance, String field, Object value) {
        try{
            Field f = instance.getClass().getDeclaredField(field);
            f.setAccessible(true);
            f.set(instance, value);
        }catch(Throwable t) {
            t.printStackTrace();
        }
    }

    public static void sendAllPacket(Object packet) throws Exception {
        for(Player p : Bukkit.getOnlinePlayers()) {
            Object nmsPlayer = getNmsPlayer(p);
            Object connection = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer);
            connection.getClass().getMethod("sendPacket", Reflection.getClass("{nms}.Packet")).invoke(connection, packet);
        }
    }

    public static void sendListPacket(List<String> players, Object packet) {
        try{
            for(String name : players) {
                Object nmsPlayer = getNmsPlayer(Bukkit.getPlayer(name));
                Object connection = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer);
                connection.getClass().getMethod("sendPacket", Reflection.getClass("{nms}.Packet")).invoke(connection, packet);
            }
        }catch(Throwable t) {
            t.printStackTrace();
        }
    }

    public static void sendPlayerPacket(Player p, Object packet) throws Exception {
        Object nmsPlayer = getNmsPlayer(p);
        Object connection = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer);
        connection.getClass().getMethod("sendPacket", Reflection.getClass("{nms}.Packet")).invoke(connection, packet);
    }

}
アバター
amata1219
ID:b3820ecb
石掘り
 
記事: 70
登録日時: 2016年11月18日(金) 16:46
お住まい: 愛知県

Return to 開発関連

x