Table of Contents

Состояния блока

Каждый тип блока в Minecraft представлен единственным экземпляром Block. Это делает невозможным изменение состояния определенного блока простым изменением состояния экземпляра Block, так как это повлияет на любой другой блок этого типа! Но что, если вы действительно хотите задать единственное состояние блока, чтобы оно могло изменяться в зависимости от некоторого условия? Вот для чего нужны BlockState. Допустим, нам нужен блок, который может вызывать молнию, но только при зарядке.

Сначала мы определяем логическое свойство блока - независимо от того, заряжено оно или нет (будьте осторожны, чтобы не импортировать неправильное BooleanProperty!):

public class ChargeableBlock extends Block {
    public static final BooleanProperty CHARGED = BooleanProperty.of("charged");
 
    // Экземпляр блока. Вы можете разместить его где угодно.
    public static final ChargeableBlock CHARGEABLE_BLOCK = Registry.register(
        Registry.BLOCK,
        new Identifier("tutorial", "chargeable_block"),
        new ChargeableBlock( /* напишите здесь что-нибудь подходящее */ ));
}

Затем нам нужно зарегистрировать свойства блока, переопределив appendProperties, а затем добавить свойство CHARGED:

public class ChargeableBlock extends Block {
    [...]
    @Override
    protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
        builder.add(CHARGED);
    }
 
}

Затем нам нужно установить состояние нашего свойства по умолчанию в конструкторе блока (чтобы задать несколько свойств, выполните вызовы цепочки with()):

public class ChargeableBlock extends Block {
    [...]
    public ChargeableBlock(Settings settings) {
        super(settings);
        setDefaultState(getStateManager().getDefaultState().with(CHARGED, false));
    }
 
}

NТеперь нам нужно иметь возможность заряжать блок с помощью метода onUse, вызывая внутри него метод world.setBlockState() (playSound совершенно необязателен, но он помогает нам узнать, что блок заряжен).

public class ChargeableBlock extends Block {
    [...]
    @Override
    public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
        player.playSound(SoundEvents.BLOCK_RESPAWN_ANCHOR_CHARGE, 1, 1);
        world.setBlockState(pos, state.with(CHARGED, true));
        return ActionResult.SUCCESS;
    }
}

И, наконец, чтобы использовать свойство CHARGED, мы вызываем onSteppedOn с world.getBlockState(pos).get(CHARGED) внутри него:

public class ChargeableBlock extends Block {
    [...]
    @Override
    public void onSteppedOn(World world, BlockPos pos, BlockState state, Entity entity) {
        if (world.getBlockState(pos).get(CHARGED)){
            // Вызов молнии в блоке
            LightningEntity lightningEntity = (LightningEntity) EntityType.LIGHTNING_BOLT.create(world);
            lightningEntity.refreshPositionAfterTeleport(Vec3d.ofBottomCenter(pos));
            world.spawnEntity(lightningEntity);
        }
 
        world.setBlockState(pos, state.with(CHARGED, false));
        super.onSteppedOn(world, pos, state, entity);
    }
}

Добавление моделей для состояний блока

Вы также можете изменить текстуру и модель вашего блока в зависимости от состояния. Это делается с помощью файла JSON, называемого “JSON состояний блока(blockstate JSON)”. Всем блокам нужен этот JSON, независимо от того, имеют они несколько состояний или нет, но содержимое JSON может быть таким простым или сложным, как вам нравится. Если вы хотите изменить текстуры вашего блока в зависимости от состояния, вам понадобится несколько моделей.

Допустим, вы регистрируете экземпляр Chargeable с идентификатором tutorial:chargeable_block. Minecraft будет искать файл по пути src/main/resources/assets/tutorial/blockstates/chargeable_block.json для загрузки состояния. Если вы не хотите, чтобы ваш блок менял модели между состояниями, JSON файл может быть очень простым. Это выглядело бы примерно так:

resources/assets/tutorial/blockstates/chargeable_block.json
{
    "variants": {
        "": { "model": "tutorial:block/chargeable_block" }
    }
}

Давайте разберем этот простой пример. В этом JSON есть пара важных частей:

Если вы хотите иметь разные модели для каждого состояния блока, вам следует добавить несколько вариантов. Для того же расположения src/main/resources/assets/tutorial/blockstates/chargeable_block.json, которое мы использовали выше, ваш файл модели, вероятно, будет выглядеть следующим образом:

resources/assets/tutorial/blockstates/chargeable_block.json
{
    "variants": {
        "charged=false": { "model": "tutorial:block/chargeable_block" },
        "charged=true": { "model": "tutorial:block/chargeable_block_charged" }
    }
}

В этом JSON есть два варианта, по одному для каждой возможности свойства CHARGED, которое мы определили выше. Поскольку мы присвоили свойству строковое имя charged в Java, это то, что мы используем здесь. Логические значения имеют только два состояния, но если вы используете свойства, основанные на целых числах или перечислениях, у вас будет больше вариантов.

Варианты основаны на возможных перестановках свойств, добавленных в ваш блок. Свойство может быть полностью проигнорировано в JSON файле состояний, если вы хотите, как в первом JSON файле состояний, где мы проигнорировали свойство charged, но если вы хотите включить свойство в один вариант, оно должно быть включено во все комбинации. Если бы у tutorial:chargeable_block также было логическое свойство с именем glowing, и вы хотели изменить модель в зависимости от того, светилась ли она и была ли она заряжена, вам понадобились бы четыре варианта: не заряженный и не светящийся, заряженный и не светящийся, не заряженный и светящийся, и заряженный и светящийся. Одна и та же модель может быть назначена нескольким вариантам, если вам это нужно.

Это всего лишь простое введение в JSON файл состояний блока. Все трюки, которые вы можете выполнять с помощью этих JSON, задокументированы на Майнкрафт википедии (англ.), , а также примеры того, как функции используются в ваниле. Желаю удачи!

Примечание о производительности

Каждое возможное состояние блока регистрируется в начале игры. Это означает, что если у вас есть 14 логических свойств, блок имеет 2 ^ 14 = 16384 различных состояния и зарегистрировано 2 ^ 14 состояний. По этой причине блоки не должны содержать слишком много свойств состояний блока. Скорее, состояния блоков должны быть в основном зарезервированы для визуальных элементов, а Сущность блока следует использовать для более продвинутого состояния.