我一直在尝试对Net Minecraft Server类使用反射,因为它们与版本有关。我做了一个模拟PacketPlayOutWorldParticles的类,但是我想做更多。由于我需要打开Chest的外观,因此,首先确保该数据包可以工作。然后我做了这个:

public class ChestReflection {
    // Reference
    // PacketPlayOutBlockAction packet = new PacketPlayOutBlockAction(new
    // BlockPosition(x, y, z), BlockChest, 1, 1);

    private Class<?> getNMSClass(String nmsClassString) throws ClassNotFoundException {
        String version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3] + ".";
        String name = "net.minecraft.server." + version + nmsClassString;
        Class<?> nmsClass = Class.forName(name);
        return nmsClass;
    }

    private Object getConnection(Player player) throws SecurityException, NoSuchMethodException, NoSuchFieldException,
            IllegalArgumentException, IllegalAccessException, InvocationTargetException {
        Method getHandle = player.getClass().getMethod("getHandle");
        Object nmsPlayer = getHandle.invoke(player);
        Field conField = nmsPlayer.getClass().getField("playerConnection");
        Object con = conField.get(nmsPlayer);
        return con;
    }

    private Object getBlockPosition(Location loc)
            throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, NoSuchMethodException, SecurityException {
        Class<?> nmsBlockPosition = getNMSClass("BlockPosition");
        Object nmsBlockPositionInstance = nmsBlockPosition
                .getConstructor(new Class[] { Double.TYPE, Double.TYPE, Double.TYPE })
                .newInstance(new Object[] { loc.getX(), loc.getY(), loc.getZ() });

        return nmsBlockPositionInstance;
    }

    public void setChest(Player player, int open, Location loc) {
        try {
            Class<?> nmsBlockPositionClass = getNMSClass("BlockPosition");
            Object nmsBlockPos = getBlockPosition(loc);
            Class<?> nmsPacketBlockAction = getNMSClass("PacketPlayOutBlockAction");
            Class<?> nmsBlock = getNMSClass("Block");
            Object nmsChest = getNMSClass("Blocks").getField("Chest");
            Class<?> nmsPacket = getNMSClass("Packet");

            Object nmsPackInstance = nmsPacketBlockAction
                    .getConstructor(new Class[] { nmsBlockPositionClass, nmsBlock, Integer.TYPE, Integer.TYPE })
                    .newInstance(new Object[] { nmsBlockPos, nmsChest, Integer.valueOf(1), Integer.valueOf(open) });
            Method sendPacket = getConnection(player).getClass().getMethod("sendPacket", nmsPacket);
            sendPacket.invoke(new Object[] { nmsPackInstance });

        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException | NoSuchMethodException | SecurityException | NoSuchFieldException e) {
            e.printStackTrace();
        }
        // -this is the reference-
        new PacketPlayOutBlockAction(new BlockPosition(loc.getX(), loc.getY(), loc.getZ()), Blocks.CHEST, 1, 0);
    }

    public void setChestOpenForEveryone(int open, Location loc) {
        for (Player player : Bukkit.getOnlinePlayers()) {
            setChest(player, open, loc);
        }
    }
}


在第54行,

newInstance(new Object[] { nmsBlockPos, nmsChest, Integer.valueOf(1), Integer.valueOf(open) });


它给我一个错误:

Error: java.lang.IllegalArgumentException: java.lang.ClassCastException@61f9358b


我实际上不知道是什么原因造成的。另外,我还包括了无反射的包装,以供参考。

最佳答案

nmsChest的类型为java.lang.reflect.Field,而不是whatever.Block。要获取该字段的值,您必须执行以下操作:


如果Blocks.CHEST是一个枚举值(或者它是Blocks.Chest?您似乎混淆了它们):

nmsChest = Enum.valueOf((Class<Enum>) getNMSClass("Blocks"), "CHEST");

否则,如果Blocks.CHEST是静态字段(此方法也适用于枚举值,但效果不佳):

nmsChest = getNMSClass("Blocks").getField("CHEST").get(null);

10-06 02:11