All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.nukkit.blockstate.BlockState Maven / Gradle / Ivy

There is a newer version: 1.20.40-r1
Show newest version
package cn.nukkit.blockstate;

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.block.BlockID;
import cn.nukkit.blockproperty.BlockProperties;
import cn.nukkit.blockproperty.BlockProperty;
import cn.nukkit.blockproperty.exception.InvalidBlockPropertyValueException;
import cn.nukkit.blockstate.exception.InvalidBlockStateDataTypeException;
import cn.nukkit.blockstate.exception.InvalidBlockStateException;
import cn.nukkit.item.ItemBlock;
import cn.nukkit.level.Level;
import cn.nukkit.math.NukkitMath;
import cn.nukkit.utils.OptionalBoolean;
import cn.nukkit.utils.Validation;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer;

@PowerNukkitOnly
@Since("1.4.0.0-PN")
@ToString
@ParametersAreNonnullByDefault
@Log4j2
public final class BlockState implements Serializable, IBlockState {
    private static final long serialVersionUID = 623759888114628578L;

    private static final BigInteger SIXTEEN = BigInteger.valueOf(16);
    private static final BigInteger BYTE_LIMIT = BigInteger.valueOf(Byte.MAX_VALUE);
    private static final BigInteger INT_LIMIT = BigInteger.valueOf(Integer.MAX_VALUE);
    private static final BigInteger LONG_LIMIT = BigInteger.valueOf(Long.MAX_VALUE);
    
    private static final ZeroStorage ZERO_STORAGE = new ZeroStorage();
    
    @SuppressWarnings({"deprecation", "java:S1874"})
    private static final BlockState[][] STATES_COMMON = new BlockState[16][Block.MAX_BLOCK_ID];
    private static final ConcurrentMap STATES_UNCOMMON = new ConcurrentHashMap<>();

    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public static final BlockState AIR = BlockState.of(BlockID.AIR, 0);
    
    private static BlockState growCommonPool(@Nonnegative int blockId, @Nonnegative byte blockData) {
        synchronized (STATES_COMMON) {
            BlockState[] blockIds = STATES_COMMON[blockData];
            int newLen = blockId + 1;
            if (blockIds.length < newLen) {
                STATES_COMMON[blockData] = blockIds = Arrays.copyOf(blockIds, blockId + 1);
            }
            BlockState state = new BlockState(blockId, blockData);
            blockIds[blockId] = state;
            return state;
        }
    }
    
    private static BlockState of0xF(@Nonnegative int blockId, @Nonnegative byte blockData) {
        BlockState[] blockIds = STATES_COMMON[blockData];
        if (blockIds.length <= blockId) {
            return growCommonPool(blockId, blockData);
        }

        BlockState state = blockIds[blockId];
        if (state != null) {
            return state;
        }
        
        BlockState newState = new BlockState(blockId, blockData);
        blockIds[blockId] = newState;
        return newState;
    }

    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    @Nonnull
    public static BlockState of(@Nonnegative int blockId) {
        return of0xF(blockId, (byte)0);
    }

    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    @Nonnull
    public static BlockState of(@Nonnegative int blockId, @Nonnegative byte blockData) {
        Validation.checkPositive("blockData", blockData);
        if (blockData < 16) {
            return of0xF(blockId, blockData);
        }
        return STATES_UNCOMMON.computeIfAbsent(blockId+":"+blockData, k-> new BlockState(blockId, blockData));
    }

    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    @Nonnull
    public static BlockState of(@Nonnegative int blockId, @Nonnegative int blockData) {
        Validation.checkPositive("blockData", blockData);
        if (blockData < 16) {
            return of0xF(blockId, (byte)blockData);
        }
        return STATES_UNCOMMON.computeIfAbsent(blockId+":"+blockData, k-> new BlockState(blockId, blockData));
    }

    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    @Nonnull
    public static BlockState of(@Nonnegative int blockId, @Nonnegative long blockData) {
        Validation.checkPositive("blockData", blockData);
        if (blockData < 16) {
            return of0xF(blockId, (byte)blockData);
        }
        return STATES_UNCOMMON.computeIfAbsent(blockId+":"+blockData, k-> new BlockState(blockId, blockData));
    }

    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    @Nonnull
    public static BlockState of(@Nonnegative int blockId, @Nonnegative BigInteger blockData) {
        Validation.checkPositive("blockData", blockData);
        if (blockData.compareTo(SIXTEEN) < 0) {
            return of0xF(blockId, blockData.byteValue());
        }
        return STATES_UNCOMMON.computeIfAbsent(blockId+":"+blockData, k-> new BlockState(blockId, blockData));
    }

    /**
     * @throws InvalidBlockStateDataTypeException If the {@code blockData} param is not {@link Integer}, {@link Long},
     * or {@link BigInteger}.
     */
    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    @Nonnull
    public static BlockState of(@Nonnegative int blockId, @Nonnegative Number blockData) {
        Class c = blockData.getClass();
        if (c == Byte.class) {
            return of(blockId, blockData.byteValue()); 
        } else if (c == Integer.class) {
            return of(blockId, blockData.intValue());
        } else if (c == Long.class) {
            return of(blockId, blockData.longValue());
        } else if (c == BigInteger.class) {
            return of(blockId, (BigInteger) blockData);
        } else {
            throw new InvalidBlockStateDataTypeException(blockData);
        }
    }

    /**
     * 

Returns the {@link BlockState} object that represents the given {@code persistedStateId}. * *

Same as {@code of(persistedStateid, true}. * * @param persistedStateId Must follow the same syntax returned by {@link #getStateId()} or {@link #getLegacyStateId()} * @throws InvalidBlockPropertyValueException If any property value in the given {@code persistedStateId} is not valid for the state. * * @return The block state, never null */ @PowerNukkitOnly @Since("1.5.2.0-PN") @Nonnull public static BlockState of(@Nonnull String persistedStateId) { return of(persistedStateId, true); } /** * Returns the {@link BlockState} object that represents the given {@code persistedStateId}. * * @param persistedStateId Must follow the same syntax returned by {@link #getStateId()} or {@link #getLegacyStateId()} * @param useDefaultPropertyValues When {@code true}, the default value will be used for any missing {@link BlockProperty} * in {@code persistedStateId}. * @throws IllegalArgumentException If {@code useDefaultPropertyValues} is false and there are missing properties * @throws InvalidBlockPropertyValueException If any property value in the given {@code persistedStateId} is not valid for the state. * @throws NoSuchElementException If there are no block registered with the given id. * * @return The block state, never null */ @PowerNukkitOnly @Since("1.5.2.0-PN") @Nonnull public static BlockState of(@Nonnull String persistedStateId, boolean useDefaultPropertyValues) { String[] stateParts = persistedStateId.split(";"); String namespacedId = stateParts[0]; int id = Optional.ofNullable(BlockStateRegistry.getBlockId(namespacedId)) .map(OptionalInt::of) .orElse(OptionalInt.empty()) .orElseThrow(()-> new NoSuchElementException("Block " + namespacedId + " not found.")); // Fast path BlockState state = BlockState.of(id); if (stateParts.length == 1 && useDefaultPropertyValues) { return state; } if (stateParts.length == 2 && (stateParts[1].startsWith("nukkit-unknown=") || stateParts[1].startsWith("unknown="))) { BigInteger damage = new BigInteger(stateParts[1].split("=", 2)[1]); return BlockState.of(id, damage); } if (stateParts.length == 1 && state.getPropertyNames().isEmpty()) { return state; } if (useDefaultPropertyValues) { for (int i = 1; i < stateParts.length; i++) { String[] propertyKeyValue = stateParts[i].split("=", 2); state = state.withProperty(propertyKeyValue[0], propertyKeyValue[1]); } return state; } else { Set defined = new LinkedHashSet<>(); Set needed = new LinkedHashSet<>(state.getPropertyNames()); for (int i = 1; i < stateParts.length; i++) { String[] propertyKeyValue = stateParts[i].split("=", 2); state = state.withProperty(propertyKeyValue[0], propertyKeyValue[1]); defined.add(propertyKeyValue[0]); } needed.removeAll(defined); if (needed.isEmpty()) { return state; } throw new IllegalArgumentException( "The state id " + persistedStateId + " is missing the following properties: " + needed ); } } @Nonnegative private final int blockId; @Nonnull @Nonnegative private final Storage storage; @ToString.Exclude @Nonnull private OptionalBoolean valid = OptionalBoolean.empty(); private BlockState(@Nonnegative int blockId) { Validation.checkPositive("blockId", blockId); this.blockId = blockId; storage = ZERO_STORAGE; } private BlockState(@Nonnegative int blockId, @Nonnegative byte blockData) { Validation.checkPositive("blockId", blockId); this.blockId = blockId; storage = blockData == 0? ZERO_STORAGE : new ByteStorage(blockData); } private BlockState(@Nonnegative int blockId, @Nonnegative int blockData) { Validation.checkPositive("blockId", blockId); this.blockId = blockId; storage = blockData == 0? ZERO_STORAGE : //blockData < 0? new IntStorage(blockData) : blockData <= Byte.MAX_VALUE? new ByteStorage((byte)blockData) : new IntStorage(blockData); } private BlockState(@Nonnegative int blockId, @Nonnegative long blockData) { Validation.checkPositive("blockId", blockId); this.blockId = blockId; storage = blockData == 0? ZERO_STORAGE : //blockData < 0? new LongStorage(blockData) : blockData <= Byte.MAX_VALUE? new ByteStorage((byte)blockData) : blockData <= Integer.MAX_VALUE? new IntStorage((int)blockData) : new LongStorage(blockData); } private BlockState(@Nonnegative int blockId, @Nonnegative BigInteger blockData) { Validation.checkPositive("blockId", blockId); this.blockId = blockId; int zeroCmp = BigInteger.ZERO.compareTo(blockData); if (zeroCmp == 0) { storage = ZERO_STORAGE; //} else if (zeroCmp < 0) { // storage = new BigIntegerStorage(blockData); } else if (blockData.compareTo(BYTE_LIMIT) <= 0) { storage = new ByteStorage(blockData.byteValue()); } else if (blockData.compareTo(INT_LIMIT) <= 0) { storage = new IntStorage(blockData.intValue()); } else if (blockData.compareTo(LONG_LIMIT) <= 0) { storage = new LongStorage(blockData.longValue()); } else { storage = new BigIntegerStorage(blockData); } } @PowerNukkitOnly @Since("1.4.0.0-PN") @Nonnegative @Override public int getBlockId() { return blockId; } @PowerNukkitOnly @Since("1.4.0.0-PN") @Nonnull public BlockState withData(@Nonnegative int data) { return of(blockId, data); } @PowerNukkitOnly @Since("1.4.0.0-PN") @Nonnull public BlockState withData(@Nonnegative long data) { return of(blockId, data); } @PowerNukkitOnly @Since("1.4.0.0-PN") @Nonnull public BlockState withData(@Nonnegative BigInteger data) { return of(blockId, data); } @PowerNukkitOnly @Since("1.4.0.0-PN") @Nonnull public BlockState withData(@Nonnegative Number data) { return of(blockId, data); } @PowerNukkitOnly @Since("1.4.0.0-PN") @Nonnull public BlockState withBlockId(@Nonnegative int blockId) { return storage.withBlockId(blockId); } @PowerNukkitOnly @Since("1.4.0.0-PN") @Nonnull public BlockState withProperty(BlockProperty property, @Nullable E value) { return withProperty(property.getName(), value); } /** * @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") @Nonnull public BlockState withProperty(String propertyName, @Nullable Serializable value) { return storage.withProperty(blockId, getProperties(), propertyName, value); } @PowerNukkitOnly @Since("1.4.0.0-PN") @Nonnull public BlockState withProperty(String propertyName, String persistenceValue) { return storage.withPropertyString(blockId, getProperties(), propertyName, persistenceValue); } /** * @throws NoSuchElementException If any of the property is not registered */ @PowerNukkitOnly @Since("1.4.0.0-PN") public BlockState onlyWithProperties(BlockProperty... properties) { String[] names = new String[properties.length]; for (int i = 0; i < properties.length; i++) { names[i] = properties[i].getName(); } return onlyWithProperties(names); } /** * @throws NoSuchElementException If any of the given property names is not found */ @PowerNukkitOnly @Since("1.4.0.0-PN") public BlockState onlyWithProperties(String... propertyNames) { BlockProperties properties = getProperties(); List list = Arrays.asList(propertyNames); if (!properties.getNames().containsAll(list)) { Set missing = new LinkedHashSet<>(list); missing.removeAll(properties.getNames()); throw new NoSuchElementException("Missing properties: " + String.join(", ", missing)); } return storage.onlyWithProperties(this, list); } /** * @throws NoSuchElementException If the property was not found */ @PowerNukkitOnly @Since("1.4.0.0-PN") public BlockState onlyWithProperty(String name) { return onlyWithProperties(name); } /** * @throws NoSuchElementException If the property was not found */ @PowerNukkitOnly @Since("1.4.0.0-PN") public BlockState onlyWithProperty(BlockProperty property) { return onlyWithProperties(property); } /** * @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") public BlockState onlyWithProperty(String name, Serializable value) { return storage.onlyWithProperty(this, name, value); } /** * @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") public BlockState onlyWithProperty(BlockProperty property, T value) { return onlyWithProperty(property.getName(), value); } @Since("1.4.0.0-PN") @PowerNukkitOnly public BlockState forItem() { BlockProperties allProperties = getProperties(); Set allNames = allProperties.getNames(); BlockProperties itemProperties = allProperties.getItemBlockProperties(); List itemNames = itemProperties.getItemPropertyNames(); if (allNames.size() == itemNames.size() && allNames.containsAll(itemNames)) { return this; } return storage.onlyWithProperties(this, itemNames); } @Since("1.4.0.0-PN") @PowerNukkitOnly @Nonnull @Override public ItemBlock asItemBlock(int count) { BlockProperties allProperties = getProperties(); Set allNames = allProperties.getNames(); int itemBlockMeta; BlockProperties itemProperties = allProperties.getItemBlockProperties(); List itemNames = itemProperties.getItemPropertyNames(); BlockState trimmedState; if (allNames.size() == itemNames.size() && allNames.containsAll(itemNames)) { itemBlockMeta = getExactIntStorage(); trimmedState = this; } else if (itemNames.isEmpty()) { itemBlockMeta = 0; trimmedState = isDefaultState()? this : of(getBlockId()); } else { trimmedState = storage.onlyWithProperties(this, itemNames); MutableBlockState itemState = itemProperties.createMutableState(getBlockId()); itemNames.forEach(property -> itemState.setPropertyValue(property, getPropertyValue(property))); itemBlockMeta = itemState.getExactIntStorage(); } int runtimeId = trimmedState.getRuntimeId(); if (runtimeId == BlockStateRegistry.getUpdateBlockRegistration() && !"minecraft:info_update".equals(trimmedState.getPersistenceName())) { log.warn("The current block state can't be represented as an item. State: {}, Trimmed: {} ItemBlockMeta: {}", this, trimmedState, itemBlockMeta); //throw new UnknownRuntimeIdException("The current block state can't be represented as an item. State: "+trimmedState+", Trimmed: "+trimmedState+" ItemBlockMeta: "+itemBlockMeta); } Block block = trimmedState.getBlock(); return new ItemBlock(block, itemBlockMeta, count); } @Nonnegative @Nonnull @Override @PowerNukkitOnly public Number getDataStorage() { return storage.getNumber(); } @Nonnull @Override @PowerNukkitOnly public BlockProperties getProperties() { return BlockStateRegistry.getProperties(blockId); } @Nonnegative @Deprecated @DeprecationDetails(reason = "Can't store all data, exists for backward compatibility reasons", since = "1.4.0.0-PN", replaceWith = "getDataStorage()") @Override @PowerNukkitOnly public int getLegacyDamage() { return storage.getLegacyDamage(); } @Unsigned @Deprecated @DeprecationDetails(reason = "Can't store all data, exists for backward compatibility reasons", since = "1.4.0.0-PN", replaceWith = "getDataStorage()") @PowerNukkitOnly @Override public int getBigDamage() { return storage.getBigDamage(); } @Nonnegative @Since("1.4.0.0-PN") @PowerNukkitOnly @Deprecated @DeprecationDetails(reason = "Can't store all data, exists for backward compatibility reasons", since = "1.4.0.0-PN", replaceWith = "getDataStorage()") @Override public int getSignedBigDamage() { return storage.getSignedBigDamage(); } @Nonnegative @PowerNukkitOnly @Since("1.4.0.0-PN") @Nonnull @Override public BigInteger getHugeDamage() { return storage.getHugeDamage(); } @Nonnull @Override @PowerNukkitOnly public Serializable getPropertyValue(String propertyName) { return storage.getPropertyValue(getProperties(), propertyName); } @Override @PowerNukkitOnly public int getIntValue(String propertyName) { return storage.getIntValue(getProperties(), propertyName); } @PowerNukkitOnly @Override public boolean getBooleanValue(String propertyName) { return storage.getBooleanValue(getProperties(), propertyName); } @Nonnull @Override @PowerNukkitOnly public String getPersistenceValue(String propertyName) { return storage.getPersistenceValue(getProperties(), propertyName); } @Nonnull @Override @PowerNukkitOnly public BlockState getCurrentState() { return this; } @PowerNukkitOnly @Override public int getBitSize() { return storage.getBitSize(); } /** * @throws ArithmeticException If the storage have more than 32 bits */ @Since("1.4.0.0-PN") @PowerNukkitOnly @Override public int getExactIntStorage() { Class storageClass = storage.getClass(); if (getBitSize() >= 32 || storageClass != ZeroStorage.class && storageClass != ByteStorage.class && storageClass != IntStorage.class) { throw new ArithmeticException(getDataStorage()+" cant be stored in a signed 32 bits integer without losses. It has "+getBitSize()+" bits"); } return getSignedBigDamage(); } @Since("1.4.0.0-PN") @PowerNukkitOnly @Override public boolean isDefaultState() { return storage.isDefaultState(); } @Override public boolean equals(@Nullable Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; BlockState that = (BlockState) o; if (blockId != that.blockId) return false; if (storage.getBitSize() != that.storage.getBitSize()) return false; return compareDataEquality(storage.getNumber(), that.storage.getNumber()); } @Override public int hashCode() { int bitSize = storage.getBitSize(); int result = blockId; result = 31 * result + bitSize; if (bitSize <= 32) { result = 31 * result + storage.getBigDamage(); } else if (bitSize <= 64) { result = 31 * result + Long.hashCode(storage.getNumber().longValue()); } else { result = 31 * result + storage.getHugeDamage().hashCode(); } return result; } private static boolean compareDataEquality(Number a, Number b) { Class aClass = a.getClass(); Class bClass = b.getClass(); if (aClass == bClass) { return a.equals(b); } if (aClass != BigInteger.class && bClass != BigInteger.class) { return a.longValue() == b.longValue(); } BigInteger aBig = aClass == BigInteger.class? (BigInteger) a : new BigInteger(a.toString()); BigInteger bBig = bClass == BigInteger.class? (BigInteger) b : new BigInteger(b.toString()); return aBig.equals(bBig); } /** * @throws InvalidBlockStateException If the stored state is invalid */ @PowerNukkitOnly @Since("1.4.0.0-PN") public void validate() { if (valid == OptionalBoolean.TRUE) { return; } BlockProperties properties = getProperties(); if (storage.getBitSize() > properties.getBitSize()) { throw new InvalidBlockStateException(this, "The stored data overflows the maximum properties bits. Stored bits: "+storage.getBitSize()+", " + "Properties Bits: "+properties.getBitSize()+", Stored data: "+storage.getNumber() ); } try { storage.validate(properties); valid = OptionalBoolean.TRUE; } catch (Exception e) { valid = OptionalBoolean.FALSE; throw new InvalidBlockStateException(this, e); } } @PowerNukkitOnly @Since("1.4.0.0-PN") public boolean isCachedValidationValid() { return valid.orElse(false); } @PowerNukkitOnly @Since("1.4.0.0-PN") public OptionalBoolean getCachedValidation() { return valid; } @Nonnull @Override @PowerNukkitOnly public Block getBlock() { try { Block block = IBlockState.super.getBlock(); valid = OptionalBoolean.TRUE; return block; } catch (InvalidBlockStateException e) { valid = OptionalBoolean.FALSE; throw e; } } @Nonnull @Override @PowerNukkitOnly public Block getBlock(@Nullable Level level, int x, int y, int z, int layer, boolean repair, @Nullable Consumer callback) { if (valid == OptionalBoolean.TRUE) { Block block = IBlockState.super.getBlock(); block.x = x; block.y = y; block.z = z; block.layer = layer; block.level = level; return block; } if (valid == OptionalBoolean.FALSE) { return IBlockState.super.getBlock(level, x, y, z, layer, repair, callback); } Consumer updater = r-> valid = OptionalBoolean.FALSE; if (repair && callback != null) { callback = updater.andThen(callback); } else { callback = updater.andThen(rep -> { throw new InvalidBlockStateException(this, "Attempted to repair when repair was false. "+rep.toString(), rep.getValidationException()); }); } try { Block block = IBlockState.super.getBlock(level, x, y, z, layer, true, callback); if (valid == OptionalBoolean.EMPTY) { valid = OptionalBoolean.TRUE; } return block; } catch (InvalidBlockStateException e) { valid = OptionalBoolean.FALSE; throw e; } } @ParametersAreNonnullByDefault private interface Storage extends Serializable { @Nonnull Number getNumber(); int getLegacyDamage(); int getBigDamage(); default int getSignedBigDamage() { return getBigDamage(); } @Nonnull Serializable getPropertyValue(BlockProperties properties, String propertyName); int getIntValue(BlockProperties properties, String propertyName); boolean getBooleanValue(BlockProperties properties, String propertyName); @Nonnull BlockState withBlockId(int blockId); @Nonnull String getPersistenceValue(BlockProperties properties, String propertyName); int getBitSize(); @Nonnull BigInteger getHugeDamage(); @Nonnull BlockState withProperty(int blockId, BlockProperties properties, String propertyName, @Nullable Serializable value); @Nonnull BlockState onlyWithProperties(BlockState currentState, List propertyNames); @Nonnull BlockState onlyWithProperty(BlockState currentState, String name, Serializable value); void validate(BlockProperties properties); boolean isDefaultState(); @Nonnull BlockState withPropertyString(int blockId, BlockProperties properties, String propertyName, String value); } @ParametersAreNonnullByDefault private static class ZeroStorage implements Storage { private static final long serialVersionUID = -4199347838375711088L; @Override public int getBitSize() { return 1; } @Nonnull @Override public Integer getNumber() { return 0; } @Override public int getLegacyDamage() { return 0; } @Override public int getBigDamage() { return 0; } @Nonnull @Override public BigInteger getHugeDamage() { return BigInteger.ZERO; } @Nonnull @Override public Serializable getPropertyValue(BlockProperties properties, String propertyName) { return properties.getValue(0, propertyName); } @Override public int getIntValue(BlockProperties properties, String propertyName) { return properties.getIntValue(0, propertyName); } @Override public boolean getBooleanValue(BlockProperties properties, String propertyName) { return properties.getBooleanValue(0, propertyName); } @Nonnull @Override public BlockState withBlockId(int blockId) { return BlockState.of(blockId); } @Nonnull @Override public BlockState withProperty(int blockId, BlockProperties properties, String propertyName, @Nullable Serializable value) { // TODO This can cause problems when setting a property that increases the bit size return BlockState.of(blockId, properties.setValue(0, propertyName, value)); } @Nonnull @Override public BlockState withPropertyString(int blockId, BlockProperties properties, String propertyName, String value) { // TODO This can cause problems when setting a property that increases the bit size return BlockState.of(blockId, properties.setPersistenceValue(0, propertyName, value)); } @Nonnull @Override public BlockState onlyWithProperties(BlockState currentState, List propertyNames) { return currentState; } @Nonnull @Override public BlockState onlyWithProperty(BlockState currentState, String name, Serializable value) { BlockProperties properties = currentState.getProperties(); if (!properties.contains(name)) { return currentState; } return BlockState.of(currentState.blockId, properties.setValue(0, name, value)); } @Override public void validate(BlockProperties properties) { // Meta 0 is always valid } @Override public boolean isDefaultState() { return true; } @Nonnull @Override public String getPersistenceValue(BlockProperties properties, String propertyName) { return properties.getPersistenceValue(0, propertyName); } @Override public String toString() { return "0"; } } private class ByteStorage implements Storage { private final byte data; @Getter private final int bitSize; public ByteStorage(byte data) { this.data = data; this.bitSize = NukkitMath.bitLength(data); } @Nonnull @Override public Number getNumber() { return data; } @Override public int getLegacyDamage() { return data & Block.DATA_MASK; } @Override public int getBigDamage() { return data; } @Nonnull @Override public BigInteger getHugeDamage() { return BigInteger.valueOf(data); } @Nonnull @Override public Serializable getPropertyValue(BlockProperties properties, String propertyName) { return properties.getValue(data, propertyName); } @Override public int getIntValue(BlockProperties properties, String propertyName) { return properties.getIntValue(data, propertyName); } @Override public boolean getBooleanValue(BlockProperties properties, String propertyName) { return properties.getBooleanValue(data, propertyName); } @Nonnull @Override public BlockState withBlockId(int blockId) { return BlockState.of(blockId, data); } @Nonnull @Override public BlockState withProperty(int blockId, BlockProperties properties, String propertyName, @Nullable Serializable value) { // TODO This can cause problems when setting a property that increases the bit size return BlockState.of(blockId, properties.setValue(data, propertyName, value)); } @Nonnull @Override public BlockState withPropertyString(int blockId, BlockProperties properties, String propertyName, String value) { // TODO This can cause problems when setting a property that increases the bit size return BlockState.of(blockId, properties.setPersistenceValue(data, propertyName, value)); } @Nonnull @Override public BlockState onlyWithProperties(BlockState currentState, List propertyNames) { return BlockState.of(blockId, getProperties().reduceInt(data, (property, offset, current) -> propertyNames.contains(property.getName())? current : property.setValue(current, offset, null) ) ); } @Nonnull @Override @SuppressWarnings({"unchecked", "java:S1905", "rawtypes"}) public BlockState onlyWithProperty(BlockState currentState, String name, Serializable value) { // TODO This can cause problems when setting a property that increases the bit size return BlockState.of(blockId, getProperties().reduceInt(data, (property, offset, current) -> ((BlockProperty)property).setValue(current, offset, name.equals(property.getName())? value : null) ) ); } @Override public void validate(BlockProperties properties) { properties.forEach((property, offset) -> property.validateMeta(data, offset)); } @Override public boolean isDefaultState() { return data == 0; } @Nonnull @Override public String getPersistenceValue(BlockProperties properties, String propertyName) { return properties.getPersistenceValue(data, propertyName); } @Override public String toString() { return Byte.toString(data); } } @ParametersAreNonnullByDefault private class IntStorage implements Storage { private static final long serialVersionUID = 4700387399339051513L; private final int data; @Getter private final int bitSize; public IntStorage(int data) { this.data = data; bitSize = NukkitMath.bitLength(data); } @Nonnull @Override public Number getNumber() { return getBigDamage(); } @Override public int getLegacyDamage() { return (data & Block.DATA_MASK); } @Override public int getBigDamage() { return data; } @Nonnull @Override public Serializable getPropertyValue(BlockProperties properties, String propertyName) { return properties.getValue(data, propertyName); } @Override public int getIntValue(BlockProperties properties, String propertyName) { return properties.getIntValue(data, propertyName); } @Override public boolean getBooleanValue(BlockProperties properties, String propertyName) { return properties.getBooleanValue(data, propertyName); } @Nonnull @Override public BlockState withBlockId(int blockId) { return BlockState.of(blockId, data); } @Nonnull @Override public BlockState withProperty(int blockId, BlockProperties properties, String propertyName, @Nullable Serializable value) { // TODO This can cause problems when setting a property that increases the bit size return BlockState.of(blockId, properties.setValue(data, propertyName, value)); } @Nonnull @Override public BlockState withPropertyString(int blockId, BlockProperties properties, String propertyName, String value) { // TODO This can cause problems when setting a property that increases the bit size return BlockState.of(blockId, properties.setPersistenceValue(data, propertyName, value)); } @Nonnull @Override public BlockState onlyWithProperties(BlockState currentState, List propertyNames) { return BlockState.of(blockId, getProperties().reduceInt(data, (property, offset, current) -> propertyNames.contains(property.getName())? current : property.setValue(current, offset, null) ) ); } @Nonnull @Override @SuppressWarnings({"unchecked", "java:S1905", "rawtypes"}) public BlockState onlyWithProperty(BlockState currentState, String name, Serializable value) { // TODO This can cause problems when setting a property that increases the bit size return BlockState.of(blockId, getProperties().reduceInt(data, (property, offset, current) -> ((BlockProperty)property).setValue(current, offset, name.equals(property.getName())? value : null) ) ); } @Override public void validate(BlockProperties properties) { properties.forEach((property, offset) -> property.validateMeta(data, offset)); } @Override public boolean isDefaultState() { return data == 0; } @Nonnull @Override public String getPersistenceValue(BlockProperties properties, String propertyName) { return properties.getPersistenceValue(data, propertyName); } @Nonnull @Override public BigInteger getHugeDamage() { return BigInteger.valueOf(data); } @Override public String toString() { return Integer.toString(data); } } @ParametersAreNonnullByDefault private class LongStorage implements Storage { private static final long serialVersionUID = -2633333569914851875L; private final long data; @Getter private final int bitSize; public LongStorage(long data) { this.data = data; bitSize = NukkitMath.bitLength(data); } @Nonnull @Override public Number getNumber() { return data; } @Override public int getLegacyDamage() { return (int)(data & Block.DATA_MASK); } @Override public int getBigDamage() { return (int)(data & BlockStateRegistry.BIG_META_MASK); } @Override public int getSignedBigDamage() { return (int)(data & Integer.MAX_VALUE); } @Nonnull @Override public Serializable getPropertyValue(BlockProperties properties, String propertyName) { return properties.getValue(data, propertyName); } @Override public int getIntValue(BlockProperties properties, String propertyName) { return properties.getIntValue(data, propertyName); } @Override public boolean getBooleanValue(BlockProperties properties, String propertyName) { return properties.getBooleanValue(data, propertyName); } @Nonnull @Override public BlockState withPropertyString(int blockId, BlockProperties properties, String propertyName, String value) { // TODO This can cause problems when setting a property that increases the bit size return BlockState.of(blockId, properties.setPersistenceValue(data, propertyName, value)); } @Nonnull @Override public BlockState withBlockId(int blockId) { return BlockState.of(blockId, data); } @Nonnull @Override public BlockState withProperty(int blockId, BlockProperties properties, String propertyName, @Nullable Serializable value) { return BlockState.of(blockId, properties.setValue(data, propertyName, value)); } @Nonnull @Override public BlockState onlyWithProperties(BlockState currentState, List propertyNames) { return BlockState.of(blockId, getProperties().reduceLong(data, (property, offset, current) -> propertyNames.contains(property.getName())? current : property.setValue(current, offset, null) ) ); } @Nonnull @Override @SuppressWarnings({"unchecked", "java:S1905", "rawtypes"}) public BlockState onlyWithProperty(BlockState currentState, String name, Serializable value) { // TODO This can cause problems when setting a property that increases the bit size return BlockState.of(blockId, getProperties().reduceLong(data, (property, offset, current) -> ((BlockProperty)property).setValue(current, offset, name.equals(property.getName())? value : null) ) ); } @Override public void validate(BlockProperties properties) { properties.forEach((property, offset) -> property.validateMeta(data, offset)); } @Override public boolean isDefaultState() { return data == 0; } @Nonnull @Override public String getPersistenceValue(BlockProperties properties, String propertyName) { return properties.getPersistenceValue(data, propertyName); } @Nonnull @Override public BigInteger getHugeDamage() { return BigInteger.valueOf(data); } @Override public String toString() { return Long.toString(data); } } @ParametersAreNonnullByDefault private class BigIntegerStorage implements Storage { private static final long serialVersionUID = 2504213066240296662L; private final BigInteger data; @Getter private final int bitSize; public BigIntegerStorage(BigInteger data) { this.data = data; bitSize = NukkitMath.bitLength(data); } @Nonnull @Override public Number getNumber() { return getHugeDamage(); } @Override public int getLegacyDamage() { return data.and(BigInteger.valueOf(Block.DATA_MASK)).intValue(); } @Override public int getBigDamage() { return data.and(BigInteger.valueOf(BlockStateRegistry.BIG_META_MASK)).intValue(); } @Override public int getSignedBigDamage() { return data.and(BigInteger.valueOf(Integer.MAX_VALUE)).intValue(); } @Nonnull @Override public Serializable getPropertyValue(BlockProperties properties, String propertyName) { return properties.getValue(data, propertyName); } @Override public int getIntValue(BlockProperties properties, String propertyName) { return properties.getIntValue(data, propertyName); } @Override public boolean getBooleanValue(BlockProperties properties, String propertyName) { return properties.getBooleanValue(data, propertyName); } @Nonnull @Override public BlockState withBlockId(int blockId) { return BlockState.of(blockId, data); } @Nonnull @Override public BlockState withProperty(int blockId, BlockProperties properties, String propertyName, @Nullable Serializable value) { return BlockState.of(blockId, properties.setValue(data, propertyName, value)); } @Nonnull @Override public BlockState withPropertyString(int blockId, BlockProperties properties, String propertyName, String value) { return BlockState.of(blockId, properties.setPersistenceValue(data, propertyName, value)); } @Nonnull @Override public BlockState onlyWithProperties(BlockState currentState, List propertyNames) { return BlockState.of(blockId, getProperties().reduce(data, (property, offset, current) -> propertyNames.contains(property.getName())? current : property.setValue(current, offset, null) ) ); } @Nonnull @Override @SuppressWarnings({"unchecked", "java:S1905", "rawtypes"}) public BlockState onlyWithProperty(BlockState currentState, String name, Serializable value) { return BlockState.of(blockId, getProperties().reduce(data, (property, offset, current) -> ((BlockProperty)property).setValue(current, offset, name.equals(property.getName())? value : null) ) ); } @Override public void validate(BlockProperties properties) { properties.forEach((property, offset) -> property.validateMeta(data, offset)); } @Override public boolean isDefaultState() { return data.equals(BigInteger.ZERO); } @Nonnull @Override public String getPersistenceValue(BlockProperties properties, String propertyName) { return properties.getPersistenceValue(data, propertyName); } @Nonnull @Override public BigInteger getHugeDamage() { return data; } @Override public String toString() { return data.toString(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy