cn.nukkit.blockstate.IBlockState Maven / Gradle / Ivy
package cn.nukkit.blockstate;
import cn.nukkit.Server;
import cn.nukkit.api.DeprecationDetails;
import cn.nukkit.api.PowerNukkitOnly;
import cn.nukkit.api.Since;
import cn.nukkit.api.Unsigned;
import cn.nukkit.block.Block;
import cn.nukkit.blockproperty.BlockProperties;
import cn.nukkit.blockproperty.BlockProperty;
import cn.nukkit.blockproperty.exception.InvalidBlockPropertyException;
import cn.nukkit.blockproperty.exception.InvalidBlockPropertyMetaException;
import cn.nukkit.blockproperty.exception.InvalidBlockPropertyValueException;
import cn.nukkit.blockstate.exception.InvalidBlockStateException;
import cn.nukkit.event.blockstate.BlockStateRepairEvent;
import cn.nukkit.event.blockstate.BlockStateRepairFinishEvent;
import cn.nukkit.item.ItemBlock;
import cn.nukkit.level.Level;
import cn.nukkit.level.Position;
import cn.nukkit.math.BlockVector3;
import cn.nukkit.math.Vector3;
import cn.nukkit.plugin.PluginManager;
import cn.nukkit.utils.HumanStringComparator;
import javax.annotation.Nonnegative;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.AbstractMap.SimpleEntry;
import java.util.*;
import java.util.function.Consumer;
import static cn.nukkit.blockstate.Loggers.logIBlockState;
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@ParametersAreNonnullByDefault
public interface IBlockState {
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@Nonnegative
int getBlockId();
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
@Nonnegative
Number getDataStorage();
@PowerNukkitOnly
@Since("1.4.0.0-PN")
boolean isDefaultState();
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
BlockProperties getProperties();
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@Deprecated
@DeprecationDetails(reason = "Can't store all data, exists for backward compatibility reasons", since = "1.4.0.0-PN", replaceWith = "getDataStorage()")
@Nonnegative
int getLegacyDamage();
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@Deprecated
@DeprecationDetails(reason = "Can't store all data, exists for backward compatibility reasons", since = "1.4.0.0-PN", replaceWith = "getDataStorage()")
@Unsigned
int getBigDamage();
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@Deprecated
@DeprecationDetails(reason = "Can't store all data, exists for backward compatibility reasons", since = "1.4.0.0-PN", replaceWith = "getDataStorage()")
@Nonnegative
default int getSignedBigDamage() {
return getBigDamage();
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
@Nonnegative
BigInteger getHugeDamage();
/**
* @throws NoSuchElementException If the property is not registered
* @throws InvalidBlockPropertyValueException If the new value is not accepted by the property
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
Serializable getPropertyValue(String propertyName);
/**
* @throws NoSuchElementException If the property is not registered
* @throws InvalidBlockPropertyValueException If the new value is not accepted by the property
* @throws ClassCastException If the actual property value don't match the type of the given property
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default V getPropertyValue(BlockProperty property) {
return getCheckedPropertyValue(property.getName(), property.getValueClass());
}
/**
* @throws NoSuchElementException If the property is not registered
* @throws InvalidBlockPropertyValueException If the new value is not accepted by the property
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default V getUncheckedPropertyValue(BlockProperty property) {
return getUncheckedPropertyValue(property.getName());
}
/**
* @throws NoSuchElementException If the property is not registered
* @throws InvalidBlockPropertyMetaException If the meta contains invalid data
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
int getIntValue(String propertyName);
/**
* @throws NoSuchElementException If the property is not registered
* @throws InvalidBlockPropertyMetaException If the meta contains invalid data
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
default int getIntValue(BlockProperty> property) {
return getIntValue(property.getName());
}
/**
* @throws NoSuchElementException If the property is not registered
* @throws InvalidBlockPropertyMetaException If the meta contains invalid data
* @throws ClassCastException If the property don't hold boolean values
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
boolean getBooleanValue(String propertyName);
/**
* @throws NoSuchElementException If the property is not registered
* @throws InvalidBlockPropertyMetaException If the meta contains invalid data
* @throws ClassCastException If the property don't hold boolean values
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
default boolean getBooleanValue(BlockProperty> property) {
return getBooleanValue(property.getName());
}
/**
* @throws NoSuchElementException If the property is not registered
* @throws InvalidBlockPropertyMetaException If the meta contains invalid data
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
String getPersistenceValue(String propertyName);
/**
* @throws NoSuchElementException If the property is not registered
* @throws InvalidBlockPropertyMetaException If the meta contains invalid data
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default String getPersistenceValue(BlockProperty> property) {
return getPersistenceValue(property.getName());
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default String getPersistenceName() {
return BlockStateRegistry.getPersistenceName(getBlockId());
}
/**
* Gets a unique persistence identification for this state based on the block properties.
* If the state holds an invalid meta, the result of {@link #getLegacyStateId()} is returned.
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default String getStateId() {
BlockProperties properties = getProperties();
Map propertyMap = new TreeMap<>(HumanStringComparator.getInstance());
try {
properties.getNames().forEach(name -> propertyMap.put(properties.getBlockProperty(name).getPersistenceName(), getPersistenceValue(name)));
} catch (InvalidBlockPropertyException e) {
logIBlockState.debug("Attempted to get the stateId of an invalid state {}:{}\nProperties: {}", getBlockId(), getDataStorage(), properties, e);
return getLegacyStateId();
}
StringBuilder stateId = new StringBuilder(getPersistenceName());
propertyMap.forEach((name, value) -> stateId.append(';').append(name).append('=').append(value));
return stateId.toString();
}
@PowerNukkitOnly
@Since("1.5.2.0-PN")
default String getMinimalistStateId() {
if (isDefaultState()) {
return getPersistenceName();
}
BlockProperties properties = getProperties();
Map propertyMap = new TreeMap<>(HumanStringComparator.getInstance());
try {
properties.getNames().stream()
.map(name -> new SimpleEntry<>(properties.getBlockProperty(name), getPersistenceValue(name)))
.filter(entry -> !entry.getKey().isDefaultPersistentValue(entry.getValue()))
.forEach(entry -> propertyMap.put(entry.getKey().getPersistenceName(), entry.getValue()));
} catch (InvalidBlockPropertyException e) {
logIBlockState.debug("Attempted to get the stateId of an invalid state {}:{}\nProperties: {}", getBlockId(), getDataStorage(), properties, e);
return getLegacyStateId();
}
StringBuilder stateId = new StringBuilder(getPersistenceName());
propertyMap.forEach((name, value) -> stateId.append(';').append(name).append('=').append(value));
return stateId.toString();
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default String getLegacyStateId() {
return getPersistenceName()+";nukkit-unknown="+getDataStorage();
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
BlockState getCurrentState();
/**
* @throws InvalidBlockStateException if the state contains invalid property values
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlock() {
Block block = Block.get(getBlockId());
return block.forState(this);
}
/**
* @throws InvalidBlockStateException if the state contains invalid property values
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlock(@Nullable Level level, int x, int y, int z) {
return getBlock(level, x, y, z, 0, false, null);
}
/**
* @throws InvalidBlockStateException if the state contains invalid property values
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlock(@Nullable Level level, int x, int y, int z, int layer) {
return getBlock(level, x, y, z, layer, false, null);
}
/**
* @throws InvalidBlockStateException if repair is false and the state contains invalid property values
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlock(@Nullable Level level, int x, int y, int z, int layer, boolean repair) {
return getBlock(level, x, y, z, layer, repair, null);
}
/**
* @throws InvalidBlockStateException if repair is false and the state contains invalid property values
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlock(@Nullable Level level, int x, int y, int z, int layer, boolean repair, @Nullable Consumer callback) {
Block block = Block.get(getBlockId());
block.level = level;
block.x = x;
block.y = y;
block.z = z;
block.layer = layer;
BlockState currentState = getCurrentState();
try {
if (currentState.isCachedValidationValid()) {
return block.forState(currentState);
}
} catch (Exception e) {
logIBlockState.error("Unexpected error while trying to set the cached valid state to the block. State: {}, Block: {}", currentState, block, e);
}
try {
block.setDataStorage(currentState.getDataStorage(), repair, callback);
} catch (InvalidBlockStateException e) {
throw new InvalidBlockStateException(getCurrentState(), "Invalid block state in layer "+layer+" at: "+new Position(x, y, z, level), e);
}
return block;
}
/**
* @throws InvalidBlockStateException if the state contains invalid property values
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlock(Position position) {
return getBlock(position, 0);
}
/**
* @throws InvalidBlockStateException if the state contains invalid property values
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlock(Block position) {
return getBlock(position, position.layer);
}
/**
* @throws InvalidBlockStateException if the state contains invalid property values
*/
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlock(Position position, int layer) {
return getBlock(position.getLevel(), position.getFloorX(), position.getFloorY(), position.getFloorZ(), layer);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlockRepairing(Block pos) {
return getBlockRepairing(pos, pos.layer);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlockRepairing(Position position, int layer) {
return getBlockRepairing(position.level, position, layer);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlockRepairing(@Nullable Level level, BlockVector3 pos, int layer) {
return getBlockRepairing(level, pos.x, pos.y, pos.z, layer);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlockRepairing(@Nullable Level level, Vector3 pos) {
return getBlockRepairing(level, pos, 0);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlockRepairing(@Nullable Level level, Vector3 pos, int layer) {
return getBlockRepairing(level, pos.getFloorX(), pos.getFloorY(), pos.getFloorZ());
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlockRepairing(@Nullable Level level, int x, int y, int z) {
return getBlockRepairing(level, x, y, z, 0);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlockRepairing(@Nullable Level level, int x, int y, int z, int layer) {
return getBlockRepairing(level, x, y, z, layer, null);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Block getBlockRepairing(@Nullable Level level, int x, int y, int z, int layer, @Nullable Consumer callback) {
List repairs = new ArrayList<>(0);
Consumer callbackChain = repairs::add;
if (!BlockStateRepairEvent.getHandlers().isEmpty()) {
PluginManager manager = Server.getInstance().getPluginManager();
callbackChain = callbackChain.andThen(repair -> manager.callEvent(new BlockStateRepairEvent(repair)));
}
if (callback != null) {
callbackChain = callbackChain.andThen(callback);
}
Block block = getBlock(level, x, y, z, layer, true, callbackChain);
if (!BlockStateRepairFinishEvent.getHandlers().isEmpty()) {
BlockStateRepairFinishEvent event = new BlockStateRepairFinishEvent(repairs, block);
Server.getInstance().getPluginManager().callEvent(event);
block = event.getResult();
}
if (!repairs.isEmpty() && logIBlockState.isDebugEnabled()) {
logIBlockState.debug("The block that at Level:{}, X:{}, Y:{}, Z:{}, L:{} was repaired. Result: {}, Repairs: {}",
level, x, y, z, layer, block, repairs,
new Exception("Stacktrace")
);
}
return block;
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
default int getRuntimeId() {
return BlockStateRegistry.getRuntimeId(getCurrentState());
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@Deprecated
@DeprecationDetails(reason = "Can't store all data, exists for backward compatibility reasons", since = "1.4.0.0-PN", replaceWith = "the BlockState itself")
default int getFullId() {
return (getBlockId() << Block.DATA_BITS) | (getLegacyDamage() & Block.DATA_MASK);
}
@PowerNukkitOnly
@Deprecated
@DeprecationDetails(reason = "Can't store all data, exists for backward compatibility reasons", since = "1.4.0.0-PN", replaceWith = "the BlockState itself")
default long getBigId() {
return ((long)getBlockId() << 32) | (getBigDamage() & BlockStateRegistry.BIG_META_MASK);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@SuppressWarnings("rawtypes")
@NotNull
default BlockProperty getProperty(String propertyName) {
return getProperties().getBlockProperty(propertyName);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default > T getCheckedProperty(String propertyName, Class tClass) {
return getProperties().getBlockProperty(propertyName, tClass);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default Set getPropertyNames() {
return getProperties().getNames();
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default T getCheckedPropertyValue(String propertyName, Class tClass) {
return tClass.cast(getPropertyValue(propertyName));
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
@SuppressWarnings("unchecked")
default T getUncheckedPropertyValue(String propertyName) {
return (T) getPropertyValue(propertyName);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
default int getBitSize() {
return getProperties().getBitSize();
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@Nonnegative
int getExactIntStorage();
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default ItemBlock asItemBlock() {
return asItemBlock(1);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@NotNull
default ItemBlock asItemBlock(int count) {
return getCurrentState().asItemBlock(count);
}
}