我一直在尝试对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);