1.14.4 Problems in serializing itemstack into yaml

Discussion in 'Spigot Plugin Development' started by Viosin, Jan 31, 2020.

  1. There were some problems when I tried to use the following code:
    Code (Text):
        public Quest(ConfigurationSection config) {
            name = config.getString("name");
            weekend = config.getBoolean("weekend");
            displayItem = config.getItemStack("displayItem");
        }
    Yaml is as follows:
    Code (YAML):
    name: "Test"

    weekend
    : true

    displayItem
    :
      ==
    : org.bukkit.inventory.ItemStack
      type
    : TORCH
      meta
    :
        ==
    : ItemMeta
        meta-type
    : UNSPECIFIC
        display-name
    : "§e§l[ §c§l Test Quest §e§l]"
        lore
    :
         - "§aTarget:"
          - " §fGet 64 torches"
          - ""
          - "§dRewards:"
          - " §f50$ | 10Points"
    When my plug-n is running normally (I'm sure it can run in 1.12.2 and below), I can normally see the display items and accept and complete the Quest.
    However, when I transferred the plugin to 1.14.4, there was an exception: the lore of the display item disappeared!
    I speculate that this is because the itemstack serialization code in 1.14.4 has changed, so I try to use the test code to serialize an itemstack into yaml to facilitate observation of its structure.

    Code (Java):
                YamlConfiguration yml = new YamlConfiguration();
                ItemStack stack = new ItemStack(Material.DIAMOND_SWORD);
                ItemMeta meta = stack.getItemMeta();
                List<String> lore = new ArrayList<>();
                lore.add("test lore");
                meta.addEnchant(Enchantment.DAMAGE_ALL, 1, true);
                meta.setDisplayName("test item");
                meta.setLore(lore);
                meta.addItemFlags(ItemFlag.values());
                stack.setItemMeta(meta);
                yml.set("testItem", stack);
                try {
                    yml.save(new File(getDataFolder(), "test.yml"));
                } catch (IOException e) {
                    e.printStackTrace();
                }
    I got the following yaml:
    Code (YAML):
    testItem:
      ==
    : org.bukkit.inventory.ItemStack
      v
    : 1976
      type
    : LEGACY_DIAMOND_SWORD
      meta
    :
        ==
    : ItemMeta
        meta-type
    : UNSPECIFIC
        display-name
    : test item
        lore
    :
       - test lore
        enchants
    :
          DAMAGE_ALL
    : 1
        ItemFlags
    :
       - HIDE_ENCHANTS
        - HIDE_ATTRIBUTES
        - HIDE_UNBREAKABLE
        - HIDE_DESTROYS
        - HIDE_PLACED_ON
        - HIDE_POTION_EFFECTS
    I noticed that in itemstack in 1.14.4, there is an attribute V, which may be related to the answer I want.
    So I added V: 1976 to all the exhibits in my mission document.
    I thought he could run normally, but I was too naive.
    This time, it's not that the item doesn't have lore, but the whole file can't be loaded!

    Code (Text):
    [14:17:15] [nioEventLoopGroup-3-1/ERROR]: Could not call method 'public static org.bukkit.inventory.ItemStack org.bukkit.inventory.ItemStack.deserialize(java.util.Map)' of class org.bukkit.inventory.ItemStack for deserialization
    java.lang.IllegalArgumentException: Material cannot be null
        at org.apache.commons.lang.Validate.notNull(Validate.java:192) ~[spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.inventory.ItemStack.<init>(ItemStack.java:70) ~[spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.inventory.ItemStack.<init>(ItemStack.java:58) ~[spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.inventory.ItemStack.deserialize(ItemStack.java:490) ~[spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source) ~[?:?]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_241]
        at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_241]
        at org.bukkit.configuration.serialization.ConfigurationSerialization.deserializeViaMethod(ConfigurationSerialization.java:85) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.configuration.serialization.ConfigurationSerialization.deserialize(ConfigurationSerialization.java:127) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.configuration.serialization.ConfigurationSerialization.deserializeObject(ConfigurationSerialization.java:207) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.configuration.file.YamlConstructor$ConstructCustomObject.construct(YamlConstructor.java:37) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:204) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:193) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping2ndStep(BaseConstructor.java:453) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.constructor.SafeConstructor.constructMapping2ndStep(SafeConstructor.java:184) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping(BaseConstructor.java:434) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructYamlMap.construct(SafeConstructor.java:521) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.configuration.file.YamlConstructor$ConstructCustomObject.construct(YamlConstructor.java:28) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:204) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:193) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:159) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:146) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.Yaml.loadFromReader(Yaml.java:524) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.yaml.snakeyaml.Yaml.load(Yaml.java:437) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.configuration.file.YamlConfiguration.loadFromString(YamlConfiguration.java:54) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.configuration.file.FileConfiguration.load(FileConfiguration.java:160) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.configuration.file.FileConfiguration.load(FileConfiguration.java:128) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(YamlConfiguration.java:183) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at cn.hamster3.dailyquest.DataManager.init(DataManager.java:83) [DailyQuest.jar:?]
        at cn.hamster3.dailyquest.DailyQuest.reload(DailyQuest.java:77) [DailyQuest.jar:?]
        at cn.hamster3.dailyquest.listener.QuestListener.onServiceReceive(QuestListener.java:350) [DailyQuest.jar:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_241]
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_241]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_241]
        at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_241]
        at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:316) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:529) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:508) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at cn.hamster3.service.spigot.ServiceReadHandler.channelRead0(ServiceReadHandler.java:12) [HamsterService.jar:?]
        at cn.hamster3.service.spigot.ServiceReadHandler.channelRead0(ServiceReadHandler.java:8) [HamsterService.jar:?]
        at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:647) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:582) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:499) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:461) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [spigot.jar:git-Spigot-cbd1a1b-009d8af]
        at java.lang.Thread.run(Unknown Source) [?:1.8.0_241]
    Later, I tried to decompile spigot.jar and found the code for itemstack. I find it seems to be related to bukkit. Getunsafe(). Getdataversion()! But I'm not sure what the problem is.
    Recall some changes in the API in 1.13 (material enumeration fields changed a lot).
    At first, I thought that the V attribute might be used to make the upgrade from the lower version plugin to the higher version consistent?
    But obviously not! Otherwise, why can my plugin run in 1.12.2 instead of 1.14.4?
    I speculate that this V attribute may be related to the item of data attribute, but for technical reasons, I am not sure whether the problem must be here.
    In summary, I tried several ways:
    Do not add V attribute - > no lore
    Add V attribute - > some items will cause an error
    Delete the V attribute of the items that will report an error - > the item lore disappears again
    So what should I do to make sure that part of my items are both lore and not wrong?

    My English is not very good, so maybe I can't express it clearly in some places. I'm very sorry if I offend you.
     
  2. Mmmh...
    I think that the V attribute is something like an unique id for the item, so to make it work you have to save it programmaticaly
    I think that is better just to have a custom serialization for the item, to save just the lore, the name and the material. Maybe using Json.
     
  3. I just investigated a lot of data and found that in version 1.14.4, the V attribute of all itemstacks is the same value (1976), while in 1.14.3, all items are the same value (1968). So I guess this property is related to version
    Maybe it's a good way to use JSON to store data, but if I do, all my code about itemstack will be rewritten (yes, I do write a lot of code directly deserializing itemstack with the bukkit API). These codes are distributed in different projects, and it may take a lot of time to complete it
    So I need to figure out how this V attribute works
     
  4. I can’t
    I can’t help more than. All the items that I have ever serialized were serialized from the code, and than loaded back again, without problems. I don’t know exactly how V works, so I’m sorry. My knowledge stops here
     
  5. drives_a_ford

    Moderator

    Perhaps this is simply a compatibility layer issue?

    Does your plugin.yml declare a api-version? If so, what is the value?

    If you don't specify an api version, Spigot will assume you've got a legacy plugin and will use a compatibility layer for Materials. It's possible this also messes with some other things.
     
  6. Why didn’t I thought of that? It can be effectively the reason
     
  7. TeamBergerhealer

    Supporter

    The v property is a data serialization version. Its a number Mojang internally uses to identify the data version in which contents are saved, so they can perform conversion. Pre-1.13 this was not present in the ItemStack, post-1.13 it is.

    Bukkit added this so they can convert ItemStack YAML from 1.13.2 to the proper names/attributes on 1.14. It is also used to reject items saved on, say, 1.14 when loading yaml on 1.13. I've had to write a custom conversion layer so that my multiversion plugins can load yaml from future minecraft versions.

    Changing it will have little to no effect most of the time, but the conversion from pre-1.13 to post-1.13 is messy. If your yaml was saved pre-1.13, the 'v' property should not be there, otherwise conversion will fail spectacularly.

    Loading YAML saved on 1.13+ on 1.12.2 or before will not work out of the box
     
    #8 TeamBergerhealer, Jan 31, 2020
    Last edited: Jan 31, 2020