Block data / state / enchantment API

I’m playing with the following way to work with blocks, block data, and enchantments.

Note:

  • Location below is basically Bukkit’s Block and Location in one. It will contain doubles but they will be rounded to ints when accessing block data. The plus is that you do not have to convert between Bukkit Blocks and Locations.
  • Block below is not Bukkit’s Block. It’s MCP/Forge’s Block, which is the type of block (i.e. Bukkit Material).
  • Location below is basically a convenience class. You can do everything on World (or more specifically, Extent, which all worlds implement). For example, you can extent.getBlock(x, y, z) == type
  • Enchantments are not really a critical part of the API in the following suggestion. It’s helper API to work on NBT data.
Location loc = world.at(x, y, z);
Block block = loc.getBlock();

if (!block.equals(stone) && block.isMovableByPiston()) {
    loc.add(0, 1, 0).setBlock(stone);
    // longer way: world.setBlock(loc.getPosition().add(0, 1, 0), stone);
    loc.breakBlock();

    CompoundTag tag = loc.getState().copyNbt();
    Enchantments container = Enchantments.fromNbt(tag);
    container.add(Enchantment.SHARPNESS, 5);
    loc.getState().replaceNbt(tag);
    // Note: Don't read into whether the above code "makes sense" -- it's
    // just an example of proposed API
}

Please make suggestions.

5 Likes

I like the idea of Location being a convenience combination of a World/Extend and a Vector3. Is the idea on Enchantments in this case that it’s a simple wrapper for a CompoundTag with some helper get/set stuff? Seems reasonable, but it could be useful to instead have a container with to/from NBT methods that isn’t explicitly backed by an NBT tag.

So Voxel will be renamed to Location?
https://github.com/SpongePowered/SpongeAPI/blob/master/src/main/java/org/spongepowered/api/world/Voxel.java

Omg

True. I will have to freshen myself on how enchantments are structured first.

Not quite. Voxel is only for blocks and thus uses integer coordinates. Location would use doubles. For block access, the values would be rounded.

Enchantments container = Enchantments.fromNbt(tag);

Wouldn’t similar methods create too many instances used just once? If you put it, for example, in a PlayerMoveEvent, the garbage collector might get busy.

1 Like

Guess to some extent it’d be up to the developer. If it’d cause GC to be too busy, then it could be worth caching, although I could see that being potentially worse. There’s probably similar methods in nearly any other API that can cause the same issue if used in high-frequency.

Great to see things simplified when possible. When I was just learning java, some of the class distinctions in Bukkit made it hard to keep track of what was going on, and why I was doing the things I was. This new method looks more like how a newbie would be expecting Minecraft to be structured, and I think that will help more people get started.

It’s also nice to see NBT not being treated as the spawn of Satan.

And this isn’t a comment about the API, but I’m curious as to what

loc.breakBlock();
block.getState().replaceNbt(tag);

would be expected to do in this context. Would that be adding a sharpness enchant to the block in the worldspace (which should be air since you broke it)? Was this just to show you can do anything you need to with NBT, even if a specific group of people can’t think of a use case for it?

The initialization of the Enchantments class would be fairly negligible. Think of all the other objects that are currently being created, especially in 1.8, for vectors, etc.

What would be pretty heavy is creating a copy of the NBT data. Therefore, Enchantments (or whatever scheme we come up with) needs to handle more than just NBT data.

First off, block actually needs to be loc because blocks are types (and not instances) here. That’s a typo.

However, the example doesn’t make sense. It was just an example of NBT data access + enchantments wrapper.

I like this apporch. I only hope that Enchantments.formNbt() would replaced with constructor.

Looks easy enough, just as long as plugins/mods have the access needed to create wrappers for custom data, like “Electric Charge” or “Contained Creature”. Last bit is, shouldn’t there be some line in

Enchantments container = Enchantments.fromNbt(tag);
container.add(Enchantment.SHARPNESS, 5);
loc.getState().replaceNbt(tag);

where you write your modified data back into the tag before setting the tag back onto the original object?

I guess the Enchantments class might be meant to operate directly with the NBT instance. If that was the intention, maybe static methods would be better?

Enchantments.add(tag, Enchantment.SHARPNESS, 5);

or add something like

container.apply(tag);
3 Likes