Acceder a los Bloques

Información Básica

Los bloques son los más comúnmente identificados y accedidos por su :javadoc:`Ubicación`. Esta ubicación apunta a cierta coordenada dentro de una :javadoc:`Extensión`. En la mayoría de los casos un :javadoc:`Mundo` será utilizado como la Extensión.

import org.spongepowered.api.Sponge;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;

public Location<World> getBlockAt(String worldName, int posX, int posY, int posZ) {
    World world = Sponge.getServer().getWorld(worldName).get();
    Location<World> blockLoc = new Location<World>(world, posX, posY, posZ);
    return blockLoc;
}

Advertencia

Tenga en cuenta que el ejemplo anterior no verifica si el mundo existe.``getWorld(worldName).get()``fallará si no hay un mundo con ese nombre cargado.

Con este objeto Ubicación puede entonces obtener información adicional sobre el bloque. El siguiente código verifica si un bloque referenciado es algún tipo de banner al verificar el tipo de bloque.

import org.spongepowered.api.block.BlockType;
import org.spongepowered.api.block.BlockTypes;

public boolean isBanner(Location<World> blockLoc) {
    BlockType type = blockLoc.getBlock().getType();
    return type.equals(BlockTypes.STANDING_BANNER)
            || type.equals(BlockTypes.WALL_BANNER);
}

Truco

La función == podría ser utilizada en lugar de equals() ya que solo hay una instancia BlockType para cada bloque, sin embargo, generalmente es recomendado utilizar equals().

Manipuladores de Datos de Bloque

Los datos de un bloque son guardados como un DataManipulator, similar a otras partes de la API. Esto es el contenedor que mantiene información sobre componentes de nuestro bloque, como la orientación de un bloque, tipos específicos (piedra vs. granito) y así sucesivamente. Verificar los valores de estos manipuladores es fácil, solo necesita verificar la dirección del bloque DirectionalData.

import org.spongepowered.api.data.key.Keys;
import org.spongepowered.api.data.manipulator.mutable.block.DirectionalData;

public boolean isFacingNorth(Location<World> blockLoc) {
    Optional<DirectionalData> optionalData = blockLoc.get(DirectionalData.class);
    if (!optionalData.isPresent()) {
        return false;
    }
    DirectionalData data = optionalData.get();
    if (data.get(Keys.DIRECTION).get().equals(Direction.NORTH)) {
        return true;
    }
    return false;
}

En primer lugar, necesitamos saber que sub-interfaz DataManipulator necesitamos. Esas que son aplicables a bloques son encontradas en los paquetes org.spongepowered.api.data.manipulator.mutable y org.spongepowered.api.data.manipulator.mutable.block. Entonces, podemos solo pasar esa clase al método get(DataManipulator) de la Ubicación que devolverá un Opcional. Después debemos verificar si nuestro DataManipulator realmente existe para nuestro bloque al verificar ifPresent(). Si existe, entonces podemos utilizarlo.

Más sobre DataManipulators puede ser encontrado en la documentación de datos.

Truco

Si un bloque nunca deja de soportar un particular DataManipulator, como DirectionalData con escalones, entonces no hay necesidad de verificar isPresent(). Solo remueva la opción alrededor del DataManipulator y busque los datos no opcionales para agregar .get() al final de la instrucción. Tenga en cuenta, que esto causará una NullPointerException si un bloque jamás deja de soportar un particular DataManipulator.

Estados de Bloque

Un BlockState contiene un BlockType, cualquier DataManipulator y propiedades que son aplicadas al bloque, y cualquier BlockTrait para un bloque. Almacena todo los valores inmutables para un bloque particular. Un uso para esto es obtener un ImmutableDataManipulator, como se muestra a continuación:

import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.data.manipulator.immutable.ImmutableWetData;

public void isWet(Location blockLoc) {
    BlockState sponge = blockLoc.getBlock();
    if (!sponge.getType().equals(BlockTypes.SPONGE)) {
        return false;
    }
    Optional<ImmutableWetData> wetness = sponge.get(ImmutableWetData.class);
    return wetness.isPresent();
}

Mas información sobre DataManipulators mutables e inmutables puede ser encontrada en la documentación de datos.

Propiedades de Bloque

Los bloques pueden contener ciertas propiedades. Una propiedad es un valor preestablecido que define la lógica del juego para ese bloque particular. Por ejemplo, los bloques pueden contener valores de resistencia a explosiones predeterminados que pueden ser utilizados para determinar con que se está trabajando, sin verificar realmente el tipo de bloque que podría ser de uno en uno. Por ejemplo, si queremos obtener la resistencia a explosiones de un bloque y verificar si es mayor o igual a uno, se haría así:

import org.spongepowered.api.data.property.DoubleProperty;
import org.spongepowered.api.data.property.block.BlastResistanceProperty;

public boolean blastResistanceGreaterThanOne(Location<World> blockLoc) {
    Optional<BlastResistanceProperty> optional =
        blockLoc.getProperty(BlastResistanceProperty.class);

    if(optional.isPresent()) {
        BlastResistanceProperty resistance = optional.get();
        DoubleProperty one = DoubleProperty.greaterThanOrEqual(1);
        return one.matches(resistance);
    }
    return false;
}

Esto obtendrá la resistencia a explosiones para nuestro bloque y lo comparará con una nueva DoubleProperty, como BlastResistanceProperty heredada de DoubleProperty. Entonces, si la resistencia a explosiones de nuestro bloque es mayor que uno, el método devolverá el valor en matches() colocado. Si quisiéramos ver si era menor que dos, podríamos remplazarlo con lessThan().

Si estuviéramos comparando dos propiedades preexistentes, tomará el Operador de nuestro primer valor, el único para el que estamos creando una propiedad doble. Si el Operador es DELEGATE, que es el operador nulo, entonces tomará el Operador de nuestro segundo valor, el único en matches(). La comparación devolverá falso si ambos son DELEGATE. Un ejemplo de comparar dos PoweredPropertys, una BooleanProperty, puede ser vista a continuación:

import org.spongepowered.api.data.property.block.PoweredProperty;

public boolean areBlocksPowered(Location<World> blockLoc, Location<World> blockLoc2) {
    Optional<PoweredProperty> optional = blockLoc.getProperty(PoweredProperty.class);
    Optional<PoweredProperty> optional2 = blockLoc2.getProperty(PoweredProperty.class);

    if(optional.isPresent() && optional2.isPresent()) {
        PoweredProperty property1 = optional2.get();
        PoweredProperty property2 = optional2.get();
        BooleanProperty booleanProperty = BooleanProperty.of(property1);
        BooleanProperty booleanProperty2 = BooleanProperty.of(true);

        if(booleanProperty2.matches(property1)) {
            return booleanProperty.matches(property2);
        }
    }
    return false;
}

La segunda verificación if comprueba si una de las propiedades es verdadera. Si es verdadera y ambas son iguales, entonces ambos de valores deben ser verdaderos. Por lo tanto, elimina la necesidad de verificar el segundo valor. Ahora sabemos que ambos bloques están siendo potenciados.

Una lista de posibles propiedades de bloque puede ser encontrada en el paquete org.spongepowered.api.data.property.block.

Rasgos de Bloque

Un rasgo de bloque es un cierto valor sobre el actual estado de un bloque. Un bloque puede o no contener rasgos de bloques dependiendo del tipo de bloque. Por ejemplo, una cama tiene un BooleanTrait llamado BED_OCCUPIED. Como un boolean puede tener solo dos valores, verdadero o falso, el rasgo``BED_OCCUPIED`` solo puede ser verdadero o falso. Verificar estos valores es simple, solo llame el método BlockState#getTraitValue(BlockTrait). Un ejemplo de esto con una cama es mostrado a continuación:

import org.spongepowered.api.block.trait.BooleanTraits;

public boolean isBedOccupied(Location<World> blockLoc) {
    if(blockLoc.getBlock().getType().equals(BlockTypes.BED)) {
        return blockLoc.getBlock().getTraitValue(BooleanTraits.BED_OCCUPIED).get();
    }
    return false;
}

Advertencia

Si es posible, se recomienda utilizar DataManipulators en lugar de BlockTraits donde sea posible ya que son solo para ser utilizados como un respaldo para la compatibilidad modificada.