Доступ к блокам
Основная информация
Чаще всего блоки идентифицируют и получают к ним доступ через их Location. Локация указывает координаты в пределах Extent. Чаще всего именно World будет использован как Extent.
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;
}
Предупреждение
Внимание: данный пример не проверяет мир на существование. getWorld(worldName).get() непременно вызовет ошибку, если мира с таким именем не будет существовать.
С помощью этого объекта «Location» вы сможете получить дополнительную информацию о блоке. Следующий код проверяет, является ли ссылочный блок каким-либо видом баннера путем проверки типа этого блока.
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);
}
Совет
Оператор сравнения == может быть использован вместо equals() так как существует только один вариант BlockType для каждого блока, однако в основном мы рекомендуем использовать именно equals().
Манипуляторы данными блока
Данные о блоке содержатся в DataManipulator подобно остальным частям API. Это является контейнером которые хранит в себе информацию о блоке, такую как направление блока, тип блока (камень или гранит) и так далее. Проверить эти значения очень просто, например для проверки направления блока необходимо использовать 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;
}
First, we need to know which DataManipulator sub-interface we need. Those that are applicable to blocks are found
in the org.spongepowered.api.data.manipulator.mutable and
org.spongepowered.api.data.manipulator.mutable.block packages. Then, we can just pass that class to the
get(DataManipulator) method of Location which will return an Optional. We then have to check if our
DataManipulator actually exists for our block by checking ifPresent(). If it exists, then we can use it.
Подробнее о``DataManipulator`` можно прочитать в data documentation.
Совет
If a block will never stop supporting a particular DataManipulator, such as DirectionalData with stairs,
then there is no need to check for isPresent(). Just remove the optional around the DataManipulator and
fetch the non-optional data by adding .get() to the end of the statement. Note, that this will cause a
NullPointerException if a block ever stops supporting a particular DataManipulator.
Состояния блока
A BlockState contains a BlockType, any DataManipulators and properties that are applied to
the block, and any BlockTraits for a block. It stores all immutable values for a particular block. One
use of this is getting an ImmutableDataManipulator, as shown below:
import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.data.manipulator.immutable.ImmutableWetData;
public boolean 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();
}
More information on mutable and immutable DataManipulators can be found in the data documentation.
Свойства блока
Блоки могут содержать определенные свойства. Свойство представляет собой заданное значение, которое определяет логику игры в этом конкретном блоке. Например, блоки могут содержать предопределенные значения сопротивления взрывам, которые могут использоваться для определения того, с чем вы работаете, без фактической проверки типа блока; он может быть один 10: один. Например, если мы хотели получить сопротивление взрывам блока и проверяем, больше оно или равно одному, это будет сделано так:
import org.spongepowered.api.data.Property;
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 = new DoubleProperty(1, Property.Operator.GEQUAL);
return one.matches(resistance);
}
return false;
}
This will get the blast resistance of our block and compare it to a new DoubleProperty, as
BlastResistanceProperty inherits from DoubleProperty. The method will then return if the blast
resistance of our block is greater than one, the value in placed matches(). If we wanted to see if it was less than
two, we would replace the property operator in the DoubleProperty ctor with Property.Operator.LESS.
If we were comparing two pre-existing properties, it will take the Operator of our first value, the one we are
creating a double property for. If the Operator is DELEGATE, which is the none operator, then it will take the
Operator of the second value, the one in matches(). Comparison will return false if both are DELEGATE.
An example of comparing two PoweredPropertys, a BooleanProperty, can be seen below:
import org.spongepowered.api.data.property.BooleanProperty;
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 = new BooleanProperty(true, Property.Operator.EQUAL);
if(booleanProperty.matches(property1)) {
return property1.matches(property2);
}
}
return false;
}
Второй «if»-контроль проверяет, является ли одно из свойств истинным. Если оно истинно, и оба равны, то оба значения должны быть истинными. Таким образом устраняется необходимость проверки второго значения. Теперь мы знаем, что оба блока приведены в действие.
Список возможных свойств для блоков можно найти в пакете org.spongepowered.api.data.property.block.
Черты блока
A block trait is a certain value on the current state of a block. A block may or may not contain block traits depending
on the type of block. For example, a bed has a BooleanTrait called
BED_OCCUPIED. As a boolean can only have two values, true and false, the BED_OCCUPIED trait can only be true or
false. Checking this value is simple, just call the BlockState#getTraitValue(BlockTrait) method. An example
of this with a bed is shown below:
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;
}
Предупреждение
If possible, it is recommended to use DataManipulators in place of BlockTraits where possible as they are
only to be meant as a fallback for modded compatibility.