带有NMS和反射的ClassCastException

时间:2016-06-03 19:52:40

标签: java reflection bukkit

我一直在尝试使用 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

我实际上并不知道是什么导致了它。此外,我还包含没有反射的数据包供参考。

1 个答案:

答案 0 :(得分:0)

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);