Изменение блоков

Изменение типа блоков

Changing the Type of a Block is as simple as calling the Location#setBlockType(BlockType, Cause) method with the new BlockType. As with most block modifications, we need to supply a cause for the block change. In most cases, this can be your main plugin class. The following code turns the block at the given Location into a sponge:

import org.spongepowered.api.block.BlockTypes;
import org.spongepowered.api.event.cause.Cause;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;

public void setToSponge(Location<World> blockLoc, Object myPluginInstance) {
    blockLoc.setBlockType(BlockTypes.SPONGE, Cause.source(myPluginInstance).build());
}

It’s as simple as that. If you just want to „delete“ a block (which is done by replacing it with air), you may just use the Location#removeBlock(Cause) method provided by Location.

Изменение состояний блока

Подобно приведенному выше примеру, класс Location предоставляет метод Location#setBlock(BlockState, Cause), принимающий новый BlockState. Чтобы использовать его, вы сначала должны получить BlockState, который вы можете изменить. Это можно сделать либо путем получения текущего состояния блока с помощью метода Location#getBlock(), либо с помощью состояния BlockType-ов по умолчанию. Последнее показано ниже. Состояние по умолчанию для блока Sponge извлекается, а затем изменяется для непосредственного создания блока мокрой губки:

import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.data.manipulator.mutable.WetData;

public void setToWetSponge(Location<World> blockLoc, Object myPluginInstance) {
    BlockState state = BlockTypes.SPONGE.getDefaultState();
    WetData wetness = Sponge.getDataManager().
        getManipulatorBuilder(WetData.class).get().create();
    wetness.set(wetness.wet().set(true));
    BlockState newState = state.with(wetness.asImmutable()).get();
    blockLoc.setBlock(newState, Cause.source(myPluginInstance).build());
}

Поскольку BlockState - это ImmutableDataHolder, то вы можете использовать методы with() и without(), которые вернут или новый измененный BlockState, или Optional.empty(), если заданный ImmutableDataManipulator не применим к данному BlockState.

The with() method accepts an ImmutableDataManipulator and will try to create a new BlockState with the given data set, overwriting existing values. The following example will change any dirt block to podzol.

import org.spongepowered.api.data.key.Keys;
import
    org.spongepowered.api.data.manipulator.immutable.block.ImmutableDirtData;
import org.spongepowered.api.data.manipulator.mutable.block.DirtData;
import org.spongepowered.api.data.type.DirtTypes;

public void dirtToPodzol(Location<World> blockLoc, Object myPluginInstance) {
    BlockState state = blockLoc.getBlock();
    Optional<ImmutableDirtData> dirtDataOpt =
        state.get(ImmutableDirtData.class);

    if (dirtDataOpt.isPresent()) {
        DirtData dirtData = dirtDataOpt.get().asMutable();
        dirtData.set(Keys.DIRT_TYPE, DirtTypes.PODZOL);
        BlockState dirtState = state.with(dirtData.asImmutable()).get();
        blockLoc.setBlock(dirtState, Cause.source(myPluginInstance).build());
    }
}

Note that the DirtData is a mutable copy of the data held in the BlockState. It is changed and then converted back to an immutable and used to create a new BlockState which then replaces the original block.

The without() method accepts a class reference and will create a new BlockState without the data represented by the given class. If the block state would not be valid without that data, a default value will be used. So if the DirtData from a dirt blocks state is removed, it will fall back to DirtTypes#DIRT, the default value. The following example will dry the block at a given Location, if possible.

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

public void dry(Location<World> blockLoc, Object myPluginInstance) {
    BlockState wetState = blockLoc.getBlock();
    Optional<BlockState> dryState = wetState.without(ImmutableWetData.class);
    if (dryState.isPresent()) {
        blockLoc.setBlock(dryState.get(), Cause.source(myPluginInstance).build());
    }
}

Since the WetData data manipulator represents boolean data, by removing it we set the wetness of the block (if it has any) to false. The dryState.isPresent() check will fail on block states that can not be wet since dryState will be Optional.empty() in that case.

Копирование блоков

If you want to copy all of a block’s data, the BlockSnapshot class is your best friend. While it doesn’t expose all the data, it stores a BlockType, its BlockState and, if necessary, all additional Tile Entity Data (for example chest inventories). Conveniently, the Location class provides a Location#createSnapshot() method to create a snapshot of the block at that point in time. That makes copying blocks from one location to another very simple:

import org.spongepowered.api.block.BlockSnapshot;

public void copyBlock(Location<World> from, Location<World> to, Object myPluginInstance) {
    BlockSnapshot snapshot = from.createSnapshot();
    to.setBlock(snapshot.getState(), Cause.source(myPluginInstance).build());
}