学后余生 | MC玩家的日常分享 划水owo - Bukkit 插件
type: channel
link: https://www.lzjsmc.cn/category/bukkit/
description: 这里将存放Bukkit插件有关的内容 如食用方法以及我开发的一些内容分享
items: [Bukkit]利用反射序列化/反序列化ItemStack

[Bukkit]利用反射序列化/反序列化ItemStack
type: item
date: 2022-06-01T16:48:00+08:00
description: *~~今天是儿童节，而我在写代码~~* ### 写这东西的原因 本来写一个简简单单的插件以为会很快，结果写到将ItemStack序列化并保存为文件这里的时候，我才发现原来Bukkit中的ItemStack这东西并没有实现Serializable这个接口。看一下源代码，是这么写的： ```java public class ItemStack implements Cloneable, ConfigurationSerializable ``` 完蛋，它实现的是ConfigurationSerializable接口，也就是说如果要序列化ItemStack的时候，只能是序列化成YAML的一组元素，这就变得阴间起来了，且不说它序列化之后原本物品中包含的NBT标签（包括非原版的NBT或者是自定义的标签）能不能被Bukkit正常识别，而且操作也很阴间。 ### 第一步 我现在想要把包含ItemStack的一个类叫UIPart的东西实例化(这里我需要用UIPart存储三个ItemStack，然后在别的地方渲染UI的时候用)，首先得让这东西实现Java的序列化接口： ```java public class UIPart implements Serializable ``` 因为是内部类，所以完整代码如下: ```java public static class UIPart implements Serializable { private final String smelt; private final String fuel; private final String result; public UIPart(String smelt, String fuel, String result) { this.smelt = smelt; this.fuel = fuel; this.result = result; } public ItemStack getSmelt() { return NBTUtil.deserializeItemStack(smelt); } public ItemStack getFuel() { return NBTUtil.deserializeItemStack(fuel); } public ItemStack getResult() { return NBTUtil.deserializeItemStack(result); } } ``` 其中，NBTUtil.deserializeItemStack(String)方法会在后文中提到。 ### 第二步 如果要将ItemStack序列化，需要用到NMS包与OBC包，为什么呢？只因为Bukkit提供的API并没有给你操作它NBT标签数据的方式，因此只能使用原版类也就是NMS的方式来操作。而Bukkit与NMS交互的中间人就是OBC（是包名org.bukkit.craftbukkit的简称），所以要通过NMS来操作Bukkit的ItemStack类，需要用到OBC来将其转换成CraftItemStack进而转换为NMS的ItemStack类。1.17/1.18以后的版本NMS不再以上述方式获取，因为新版本用了mojang官方的映射表，因此1.18以后如需调用NMS则需要额外的步骤，反射：使用新的包名，如net.minecraft.item，普通方式：需要重映射原版端后才能调用，不然看到的类就是混淆后的东西比如a.a.B。 那么，我们现在需要通过反射的方式来获取NMS与OBC包，因为在不同版本中，这些包被单独存放在了不同的位置，如net.minecraft.server.v1_7_R4以及org.bukkit.craftbukkit.v1_7_R4，v1_7_R4是版本号，对应1.7.10版本。 获取NMS类： ```java private static Class getNMSClass(String name) { String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; try { return Class.forName("net.minecraft.server." + version + "." + name); } catch (ClassNotFoundException ex) { ex.printStackTrace(); return null; } } ``` 获取OBC类： ```java private static Class getOBClass(String name) { String versi…