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