Inventory Serializing problems

I was working on a way to serialize inventories easily, I thought I had it figured out but there’s this one issue. Once I run the backpack command for the first time when the data hasn’t been added yet, it works fine and continues to work during that session. However once I restart the server and try again i keep getting this error: http://pastebin.com/mb2wUnPy

Here’s all the necessary code used : Backpack.java · GitHub

I may be completely oblivious as I’m still not entirely sure on how the whole data api works but I can’t figure out how I’m getting a RegularImmutableMap when I should be getting an ItemStack.

    @Override
    public Optional<InventoryData> from(DataContainer container) {
        if (container.contains(this.usedKey.getQuery())) {
            Map<Integer, ItemStack> items = (Map<Integer, ItemStack>) container.getMap(this.usedKey.getQuery()).get();
            this.setValue(items);
            return Optional.of(this);
        }
        return Optional.empty();
    }
    @Override
    protected Optional<InventoryData> buildContent(DataView container) throws InvalidDataException {
        if (container.contains(this.key)) {
            InventoryData data = create();
            Map<Integer, ItemStack> items = (Map<Integer, ItemStack>) container.getMap(this.key.getQuery()).get();
            data = data.set(this.key, items);
            return Optional.of(data);
        }
        return Optional.empty();
    }

Here’s you’re problems… Unlike lists, which can be deserialized completely, through getSerializableList, maps do not de-serialize their keys and elements…

Sorry if this seems a bit stupid but how would I go about doing custom serializing? Everything I’ve used with the data api has been able to be serialized on its own so far.

Well, there’s a couple different options that I know of, one of which I have working, though it’s a bit of a work around. You could either get the raw map and deserialize each container, but I’m pretty sure that only allows keys of the type String, and I’ve never been able to get that working. Alternatively, you could create a SerializablePair or something, which stores two serializable objects, and store them in a list. In fact, I use this second solution in one of my plugins, but I don’t particularly like it, it feels like a hack or something, but it does work. (at the moment it’s a little broke, and I’m about to go off wifi, but I’ll post by tonight)

I’ve managed to fix it on my own with this code:

public static Map<Integer, ItemStack> serializeItems(DataView container, DataQuery query) {
        Map<Integer, ItemStack> items = new HashMap<>();
        if (container.getView(query).isPresent()) {
            DataView view = container.getView(query).get();
            Map<DataQuery, Object> values = view.getValues(true);
            values.forEach((dataQuery, object) -> {
                try {
                    int slot = Integer.parseInt(dataQuery.toString());
                    DataView itemStackContainer = null;
                    if (object instanceof Map<?, ?>) {
                        Map<?, ?> map = (Map) object;
                        itemStackContainer = new MemoryDataContainer().createView(DataQuery.of("ItemStack"), map);

                    }
                    if (itemStackContainer != null) {
                        ItemStack stack = ItemStack.builder().fromContainer(itemStackContainer).build();
                        items.put(slot, stack);
                    }
                } catch (NumberFormatException ignored) {}

            });
        }
        return items;
    }

Doesn’t really seem clean to me but at least it works.

1 Like

It’s probably the best way at the moment. I do it differently, but to be honest, I’d rather have been able to do it that way (I just couldn’t figure it out).

Google protocol buffers?