How to put a door programmatically?

Hi!

I want to be able to create doors, which one can open and close.

In Bukkit this was a non-obvious task (see code below). What code do I need to write in order to create a door (which I and other players can open and close) at some location?

Thanks in advance

Dmitri

P. S.: Here’s the code, which does it in Bukkit:

@Override
public void putDoor(final DoorPlacementInstruction instr) {
    final Block bottom = getWorld().getBlockAt(
        instr.x(),
        instr.y(),
        instr.z()
    );
    final Block top = bottom.getRelative(BlockFace.UP, 1);
    top.setType(instr.material());
    bottom.setType(instr.material());
    top.setTypeIdAndData(64, (byte) 0x8, true);
    bottom.setTypeIdAndData(64, (byte) 0x4, true);
}

import org.bukkit.Material;

public class DoorPlacementInstruction implements BukkitInstruction {
    private final int x;
    private final int y;
    private final int z;
    private final Material material;

    public DoorPlacementInstruction(int x, int y, int z, Material material) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.material = material;
    }

    public int x() {
        return this.x;
    }

    public int y() {
        return this.y;
    }

    public int z() {
        return this.z;
    }

    public Material material() {
        return this.material;
    }
}

Take a look at Keys.HINGE_POSITION, Keys.OPEN, Keys.DIRECTION, and Keys.PORTION_TYPE. You can apply those to a door’s BlockState to change all of the values that Minecraft attaches to the blocks.

1 Like

There is a key to be used with the data api. I am pretty sure that you have to offer that key with true to the Location the door is standing at, because a door is a tile entity.

Edit: I complety misread your post. Sorry. @ZephireNZ seems to be right.

@RandomByte Door are not tile entities - they just use bit-fields in the BlockState

Okay, thanks for the clarification!

Note that although all of those Keys/manipulators exists in the API, I’m fairly certain they aren’t implemented in Sponge just yet.

1 Like

They kinda are.

1 Like

Ah, my mistake.

Hello!

Recently I tried out to write a piece of code, which would put a door. Sorry it took me so long. Here’s the Kotlin code:

internal open fun createDoor(
      door: Door,
      coords: McCoords
) {
    val loc = createSpongeLocation(
          x = coords.x + door.x,
          y = coords.y + door.elevation,
          z = coords.z + door.z
    )
    setBlockType(loc, getBlockType(door.blockType))
    setBlockState(loc, createDoorBlockState(door))
}

internal open fun createDoorBlockState(
      door: Door
): org.spongepowered.api.block.BlockState {
    var state: org.spongepowered.api.block.BlockState =
          BlockTypes.SPONGE.getDefaultState()
    state = state.with(Keys.OPEN, false).get() // Error
    state = state.with(Keys.DIRECTION, parseDirection(door.direction)).get()
    return state
}

internal open fun createSpongeLocation(
        x: Int,
        y: Int,
        z: Int
): org.spongepowered.api.world.Location<World> {
    return org.spongepowered.api.world.Location<World>(
            world,
            x,
            y,
            z)
}

Note: createDoorBlockState and createSpongeLocation are placed into separate methods purely for the purpose of easier testing.

When I run this code, I get an error at line state = state.with(Keys.OPEN, false).get():

java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Unknown Source) ~[?:1.8.0_66]

What exactly is wrong with my code?

Thanks in advance

Dmitri Pisarenko

org.spongepowered.api.block.BlockState = BlockTypes.SPONGE.getDefaultState()

OpenData isn’t compatible with the block state you’re using. Sponge is not a door

1 Like

Thanks. Now I use BlockTypes.WOODEN_DOOR.getDefaultState() instead. The rest of the code is the same.

The door appears, but it’s lying on the floor (I can pick it up).

How do I need to change the code (apart from adding the upper part of the door) in order to get a normal door, which I can open and close?

Hello!

Update: I tried to use Keys.PORTION_TYPE, but it’s not compatible with the door’s block state (both empirically and according to lists of applicable keys by block type).

I tried to use different directions (SOUTH, WEST, EAST, NORTH, NORTHWEST), but it didn’t help.

I also tried to set the direction of the upper half of the door to Direction.DOWN and that of the lower half to Direction.UP, without any change.

Is this functionality implemente in Sponge at all? If not and if I wanted to contribute it, where should I start?

Thanks

Dmitri

Just tried it for myself and everything works just fine with this code:

                CommandSpec.builder()
                    .executor((src, args) -> {
                        if(!(src instanceof Locatable)) return CommandResult.empty();

                        Location<World> bLoc = ((Locatable) src).getLocation()
                                .getBlockRelative(Direction.EAST)
                                .getBlockRelative(Direction.EAST);
                        bLoc.setBlockType(BlockTypes.WOODEN_DOOR);
                        bLoc.offer(Keys.PORTION_TYPE, PortionTypes.BOTTOM);
                        bLoc.offer(Keys.HINGE_POSITION, Hinges.LEFT);

                        Location<World> tLoc = bLoc.getRelative(Direction.UP);
                        tLoc.setBlockType(BlockTypes.WOODEN_DOOR);
                        tLoc.offer(Keys.PORTION_TYPE, PortionTypes.TOP);
                        tLoc.offer(Keys.HINGE_POSITION, Hinges.LEFT);

                        return CommandResult.success();
                    })
                .build(),
1 Like

Also, that list is out of date - support for portion data was added 20 days ago:

Yes; you are supposed to run code yourself and get generated list from output file.

It would be really cool to see this be a part of the documentation generation somehow. Something like this could be really really useful.