User Tools

Site Tools


ru:tutorial:blockstate

This is an old revision of the document!


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

Каждый тип блока в 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 есть пара важных частей:

  • "variants" определяет, какую модель следует использовать для каждого возможного состояния блока. Мы немного подробнее рассмотрим варианты.
    • Вариант с именем "" (пустая строка) будет применяться к каждой перестановке состояния блока. If you have a "" variant, you shouldn't have any other variants in the JSON, or Minecraft will get upset.
    • The object assigned to the "" variant can have various properties added to it like rotation or texture manipulation. Check out the linked Model page below for more documentation on what properties can be added. All variants must contain a "model" property.
  • The "model" property is always passed an ID of a model. In this case, the game will look at the location src/main/resources/assets/tutorial/models/block/chargeable_block.json. The ID here can be anything. It doesn't need to be the same as your block's ID, but if you only have one variant, it probably should. Block models have their own setup, which is documented very well on the Minecraft wiki page linked below. You can either write the JSON by hand or use a program like Blockbench to generate it more easily.

If you want to have different models for each blockstate, you should add multiple variants. For the same src/main/resources/assets/tutorial/blockstates/chargeable_block.json location we used above, your model file would probably look like such:

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

In this JSON, there are two variants, one for each possibility of the CHARGED property we defined above. Since we gave the property the string name of charged in the Java, that's what we use here. Booleans only have two states, but if you use properties based on integers or enums, you'll have more variants.

Variants are based on possible permutations of the properties added to your block. A property can be totally ignored in the blockstate JSON if you want, like in the first blockstate JSON where we ignored the charged property, but if you want to include a property in one variant, it must be included in all variants. If tutorial:chargeable_block also had a boolean property called glowing, and you wanted to change the model based on whether it was glowing and based on whether it was charged, you would need four variants: charged off and glowing off, charged on and glowing off, charged off and glowing on, and charged on and glowing on. The same model can be assigned to multiple variants if you need it to be.

This is only a simple introduction to blockstate JSONs. All of the tricks you can do with blockstate and model JSONs are documented on the Minecraft wiki, along with examples of how the features are used in vanilla. Best of luck!

A note about performance

Every possible state of a block is registered at the start of the game. This means that if you have 14 boolean properties, the block has 2^14 = 16384 different states and 2^14 states are registered. For this reason blocks should not contain too many blockstate properties. Rather, blockstates should be mostly reserved for visuals, and Block Entities should be used for more advanced state.

ru/tutorial/blockstate.1648477317.txt.gz · Last modified: 2022/03/28 14:21 by furnygo