How to use Data API 2.0

So are DataProcessors equivalent to keys? @Tzk

A DataProcessor is the actual implementation to retrieving/setting a DataManipulator to and from a DataHolder, since a DataHolder can be an ItemStack, an Entity, a TileEntity and even a BlockState. If there isn’t a DataProcessor implemented and registered (including a ValueProcessor for each of the Values provided by the DataManipulator), then the DataManipulator is non-functional. This is true for SpongeAPI provided DataManipulators only though, since custom DataManipulators are meant to be translated to a DataContainer and stored customarily to each DataHolder if possible. BlockStates will likely not support custom data for the foreseeable future. Locations however might sometime later this year after the core implementation is done.

Blood just bumped common ref, I can confirm its not working after your velocity implementation commit

[SignData] How to set text in the sign (The sign is in the world)?

Location is a DataHolder, so you can just offer a List<Text> to it using the Keys.SIGN_LINES key.

The docs page is not yet ready, yet you may refer to the preview for the PR and, if that does not help, consult here again. According to the checklist above the Sign data processors are already implemented

1 Like

You actually need to get the TileEntity from the location IIRC Location doesn’t forward data queries to the tile entity.
so it would be something like

Location loc = ...;
List<Text> lines = ...;
if (loc.hasTileEntity()) {
    loc.getTileEntity().get().offer(Keys.SIGN_LINES, lines);
}
1 Like

@simon816

Ah I see, you need to have a ListValue rather than a List
Either use the list value you get when calling get(Keys.SIGN_LINES)
or create a new ListValue:

ListValue<Text> signLines = game.getRegistry().createValueBuilder().createListValue(Keys.SIGN_LINES, lines);

then offer the signLines

1 Like

Complicated. I’ll wait. Let others do.

It would be cool if “location forwards data requests for the TileEntity”.

What? no…

final Text[] text = { Texts.of("foo"), Texts.of("bar") };
ArrayList<Text> list = Lists.newArrayList(text);
dataHolder.offer(Keys.SIGN_LINES, list);

compiles just fine. Ignore that I’m using Lists, but it should still work just fine.

1 Like

If I was to store custom data about an item, say an attribute such as “fire resistance”- would you recommend storing it in memory with the data api or separately in memory (ie: my own collection(s)) if I was to have the data persist in a database?

EDIT: @gabizou How would one go about offering custom keys/values to a DataHolder? Would I simply be able to dataHolder.offer(key, value)? Do I have to implement anything for the values or instantiate them in a certain way? I’m currently going off of the Keys class in SpongeAPI, a little nudge in the right direction would be nice :smile:

1 Like

So, I actually managed to implement the first phase of custom data tonight. Unfortunately, custom keys/values aren’t directly supported unless a DataManipulator is already provided in the DataHolder. The reasoning is that a Key, let a lone a Value, does not actually know how to serialize/deserialize itself from a DataContainer, something that a DataManipulator/ImmutableDataManipulator knows how to do.

TL;DR: If you want to store a piece of custom data, offer the manipulator first. Then you can query and manipulate using keys.

If you want to store custom data, just make a data manipulator and store it. Just note that when you create custom data on ItemStacks, you might make it impossible for that item to stack on other items unless the data is exactly the same. Also remember, because custom data is actively being serialized/deserialized you really do need to have registered your DataManipulatorBuilders and likewise ImmutableDataManipulatorBuilders (for snapshots). This will work almost always because you can’t really keep track of ItemStack instances between events, let alone over time, unless you’re storing these things as attributes and attribute modifiers, there’s no real way around it.

Will there be an example of how to do this in the docs at some point?

I included it in my Todo List, although I cannot say when it will be finished. Just a friendly reminder to all reading: Contributions to the docs are welcome :wink:

2 Likes

Thanks!

Now, I’m curious- is the PR about the Data API v2 (the OP) accurate/current usage/explanation? I am interested in storing “attributes” for items (or anything for that matter) and the data api looks perfect in terms of offering/retrieving. My issue stems from if I would like to implement the same functionality locally (in my classes) would I have to do the whole mile with making manipulators etc and registering etc? (DISCLAIMER: I have not fiddled around with what you mentioned in your previous reply yet)

I want to be able get values the same way as we do with Sponge’s Keys#<some-key> but with custom ones. What would you recommend?

EDIT 23/09/2015 @ 8:07
In external sites, people keep recommending that I utilize the Visitor pattern but I can’t help but doubt that it will actually solve my problem. Since it doesn’t do return values, only void operations (if going off the pattern cookie-cutter, unless I’m misunderstanding it).

If you are making custom DataManipulators to store and retrieve from entities/items/tileentities, you will always need to have serialization setup. The same is to be said about the vanilla manipulators, all of the vanilla manipulators have their own DataManipulatorBuilders to deserialize the manipulator from a DataView. In order for you to test this out though, you’d likely need to do a lot of mocking or creation of dummy DataHolders

You’re understanding it correctly, because the visitor pattern never really has to return anything. Data API can be used with the Visitor pattern, but it’s not really all that much favorable since Data API doesn’t follow that pattern at all.

Okay cool. I am currently designing it around primitives (well, you know the basics String/int/double and obv the primitive’s object counterparts). Although don’t want to limit the types that can be used as I may change this in the future, future proofing would be ideal. Also, I want these “attributes” to be fully optional. You know, an item could have a “soul” attachment of type String, whereas another item might not so it just wouldn’t exist in it. At the same time, I don’t want to limit the system by hard-coding every attribute as the classes would then get huge, also new items may have attributes that weren’t originally thought of. So you can see why I need a dynamic way of setting/getting these attributes (key=String identifier, and a value=some object).

To explain a little more, I would like to do the same system you guys have done where you may not know what type “strength-modifier” is, but the type is stored in a AttributeKeys#STRENGHT_MODIFIER and of course you know how retrieval works with the data api (it’s just perfect).

If you’re pulling an id BY NAME, then you’re explicitly trying to work with it, and therefore should know the type.

I don’t need them to be applied to an ItemStack or Entity, I was just curious which would be easier to implement. If I could just make an AttributeHolder (implementation of a DataHolder) that would be great. Although for value getting/setting would I have to do anything special per-DataHolder?

Sorry, I’m not hugely familiar with the Data API (reading through right now).

EDIT 28/09/2015 @ 7:45pm EST
@gabizou (mentioning in-case you didn’t see, very interested in your take on the matter)

I was looking through Sponge, and have a question about an alternative to custom DataManipulators (I’m still on my quest to assign custom data to a player). Is it possible to just create a custom key and a value to offer to the player? All I need to do is be able to is do something like this:

Set a value (In the form of a string) for a key (i.e. "MyKey").
Be able to retrieve a value by supplying the key.

You first need to implement a custom DataManipulator that contains that key and offer it, else the Key will not be recognised, if I understood gabizou correctly. Also, if you create a custom key it must implement the Key interface.

1 Like

Ok, thanks :grinning: . This is still kind of confusing to me, so I think I will wait until there is a solid example somewhere before I attempt to implement this.