How to use Data API 2.0

Hello! So, as some of you may already know, Data API 2.0 was just pulled with a LOT of changes. So, I’m opening this thread for answering questions on how to use the new Data API in various ways. I’ve already updated Flardians to demonstrate how to use the new Data API in various ways.

So, go ahead and start asking or contributing on some "How-To"s and over time I’ll be submitting them for the docs!

6 Likes

To reply to @soccer66 in this post

To change the game mode of a player, all you have to do now is:

entity.offer(Keys.GAME_MODE, GameModes.CREATIVE);

If there is not a key called GAME_MODE, there likely will be one shortly.

2 Likes

There isn’t one yet, which is what was confusing me. Thanks a ton! :smile:

Could you write a quick example of a custom DataManipulator?

1 Like

To follow up, Could you explain what a custom DataManipulator is and isn’t? I see a lot of people(including my self) linking the idea of a custom data manipulator with custom query’s and I’m not sure it’s 100% correct.

An example of storing and retrieving a value on an entity that is entirely created by a plugin and has no meaning in vanilla would be great.

Is it threadsafe to get or set(offer) data from another thread?

When working with healthdata whats the point of method getHealthData.asImmutable when getHealthData returns a copy. SpongeAPI/Living.java at 7ac34cb45149e3891e79d005e2a36f4ac7bb0d76 · SpongePowered/SpongeAPI · GitHub

How can i damage an (living) entity (something what fires Livingchangehealth event);

How can i set player/entity fly/walk speed/knockback resistance/ with minecraft attributes & modifiers does the data api cover this as well?

How would I get / set velocity data on an entity?

How do you get the x/y/z location of a block now from the block state? @simon816 since I know you’re active right now? :wink:

BlockState doesn’t store that information. There can be multiple locations per state (e.g a dirt block can be in more than one place at a time).

You may want to look into keeping a reference to the Location object rather than the state directly.

Sorry, I was using something along the lines of

event.getBlock().getBlockX()

however, the getBlockX() method was removed from BlockState, so I was trying to figure out how to get the x location from the BlockState in a new way, but didn’t realize I could just do

event.getLocation().getBlockX()

Silly mistake, sorry, and thanks for the help @simon816

There are two ways (though currently one at present time due to a missing Key for Velocity):

Optional<Vector3d> optional = entity.get(Keys.VELOCITY);
if (optional.isPresent()) {
  entity.set(Keys.VELOCITY, optional.get().add(0,1,0);
}

Or

Optional<VelocityData> optional = entity.get(VelocityData.class);
if (optional.isPresent()) {
  final Value<Vector3d> velocityVal = optional.get().velocity();
  entity.offer(optional.get().set(velocityVal.set(velocityVal.get().add(0,1,0)));
}

OR! (this is a bit more interesting if you’re just wanting to transform the velocity)

entity.transform(Keys.VELOCITY, new Function<Vector3d, Vector3d>() {
  @Override
  public Vector3d apply(Vector3d input) {
    return input.add(0,1,0);
  }
}

It’s threadsafe to manipulate a DataManipulator or Value after you’ve retrieved it from a ValueContainer/DataHolder, but it is NOT thread safe to offer it back or retrieve it.

The primary reason for immutable stuff is so that events can especially rely on original values/manipulators not being meddled with, let alone being passed to external threads.

With the Causes PR I’m hoping to provide a feasible way to damage an entity with some provided stuff, including a DamageSource and a bunch of other things.

You can use the AttributeData which currently needs to have some work done due to the Attributes API being a near impossible to actually implement, let alone use.

A custom DataManipulator is quite literally a DataManipulator that you want to be able to store custom data that isn’t already covered by the Data API. So, for example, if you have some Locations of "home"s you want to attach to a Player, you definitely could do so by providing your own custom DataManipulator. Alternatively, you could go the more traditional route of storing that stuff to a config file. More examples of custom DataManipulators can range from storing custom information that you don’t want to be storing onto a map, linking to various entities and possibly having to manage references without leaking them, because you’ll know that the custom data is persisted.

1 Like

This wont compile:

Optional<VelocityData> optional = entity.get(VelocityData.class);

because:

error: incompatible types: no instance(s) of type variable(s) T exist so that com.google.common.base.Optional<T> conforms to java.util.Optional<VelocityData>
        Optional<VelocityData> optional = entity.get(VelocityData.class);
                                                    ^
where T is a type-variable:
    T extends DataManipulator<?,?> declared in method <T>get(Class<T>)
1 error

any ideas @gabizou?

SpongeAPI uses Guava’s Optional (com.google.common.base.Optional) but you’ve imported Java 8’s Optional (java.util.Optional).
Simply change the import.

1 Like

How I can create custom data and assign it to the player? I messed around with it for a while, but I’m not quite sure that I understand everything about it.

1 Like

A copy/pasteable working code example that converts a given location into a polishedgranite block would be an excellent example of how to sort out the new api features, given there are numerous examples on converting/adding blocks from the former methods but none of them work nor have obvious ways to be modified to have analogous results. Have tried too many ways that keep spitting out cant-do errors, would be nice to see how well modified the new system to streamline the process. Assuming it has to do with offering a key/value but can’t get it.

public void setBlockToPolishedGranite(Location block){  //doesnt matter what block was in this location, set it.
   // please to -do here please 
}
1 Like

How to save arbitrary data to Players/blocks? Is this possible?

@Zirconium

I believe so, unless I was mistaken. I just don’t know how to do this. Will this be documented at some point in the near future?

1 Like

There is a WIP Data API Documentation PR

Is that for the old Data API or the new one?

It was for the old one, but will need to be partially rewritten to reflect the new Data API