- Версия(и) Minecraft
- 1.12.2
Многоблочная структура
В прошлой статье я рассказывал, как сделать хитбокс для блока, а в этот раз мы будем делать полноценную многоблочную структуру. Во время написания кода интерпретатор будет говорить об ошибках, но не стоит волноваться, в конце всё будет по фэншую.
Сначала, как всегда основной класс
Как вы уже поняли в этот раз мы будем делать стол (заранее скажу, что он будет четырёхблочный).
Регистрация свойства
Теперь наше свойство PART надо зарегистрировать.
Дальше надо осуществить перевод свойства в мету и наоборот.
Теперь программа может установить следующие соответствия:
0 = FOOT_LEFT
1 = FOOT_RIGHT
2 = HEAD_LEFT
3 = HEAD_RIGHT
После этого можно приступать к связке блоков в одну структуру.
Создание полноценной структуры
В этой части кода сделали установку уничтожение фантомных блоков. А теперь надо сделать и установку.
EventHandler
Создаём класс EventHandler.
Мета
Наши модели
Blockstate
Создадим json файл по пути
Локализация блока
Финал. Регистрация
BlocksRegister
В прошлой статье я рассказывал, как сделать хитбокс для блока, а в этот раз мы будем делать полноценную многоблочную структуру. Во время написания кода интерпретатор будет говорить об ошибках, но не стоит волноваться, в конце всё будет по фэншую.
Сначала, как всегда основной класс
Java:
public class BlockTable extends BlockHorizontal {
public static final PropertyEnum<BlockTable.EnumPartType> PART = PropertyEnum.create("part", BlockTable.EnumPartType.class);
protected static final AxisAlignedBB TABLE_AABB = new AxisAlignedBB(0.0, 0.0, 0.0, 1.0 ,0.5625, 1.0);
public BlockTable(String name) {
super(Material.WOOD);
this.setRegistryName(name);
this.setUnlocalizedName(name);
this.setHardness(0.01f);
this.setCreativeTab(CreativeTabs.BUILDING_BLOCKS);
this.setDefaultState(this.blockState.getBaseState().withProperty(PART, EnumPartType.FOOT_LEFT));
@Override
public boolean isFullCube(IBlockState state) {
return false;
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos)
{
return TABLE_AABB;
}
}
}
Как вы уже поняли в этот раз мы будем делать стол (заранее скажу, что он будет четырёхблочный).
PropertyEnum<BlockTable.EnumPartType>
- это свойство, которое будет говорить, какой частью стола является блок.setHardness
- это твёрдость нашего блока, я её сделал минимальной, чтобы имитировать перенос стола с места на место, а не его разрушение, как со всеми блоками в minecraft.setDefaultState
- это мы делаем значение части по умолчанию левой нижней.Регистрация свойства
Теперь наше свойство PART надо зарегистрировать.
Java:
@Override
protected BlockStateContainer createBlockState()
{
return new BlockStateContainer(this, new IProperty[] {PART});
}
public static enum EnumPartType implements IStringSerializable
{
HEAD_RIGHT("head_right"),
HEAD_LEFT("head_left"),
FOOT_RIGHT("foot_right"),
FOOT_LEFT("foot_left");
private final String name;
private EnumPartType(String name)
{
this.name = name;
}
public String toString()
{
return this.name;
}
public String getName()
{
return this.name;
}
}
BlockStateContainer createBlockState()
- регистрация нашего свойства, привязка его к блоку.public static enum EnumPartType
- это класс, который перечисляет наши части. implements IStringSerializable
- дословный перевод "принадлежит строковому свойству объекта" и означает, что наше свойство будет передавать текстовые значения.Дальше надо осуществить перевод свойства в мету и наоборот.
Java:
@Override
public IBlockState getStateFromMeta(int meta)
{
if (meta == 0) {
return this.getDefaultState().withProperty(PART, EnumPartType.FOOT_LEFT);
}
if (meta == 1) {
return this.getDefaultState().withProperty(PART, EnumPartType.FOOT_RIGHT);
}
if (meta == 2) {
return this.getDefaultState().withProperty(PART, EnumPartType.HEAD_LEFT);
}
return this.getDefaultState().withProperty(PART, EnumPartType.HEAD_RIGHT);
}
@Override
public int getMetaFromState(IBlockState state)
{
int i = 0;
if (state.getValue(PART) == EnumPartType.FOOT_RIGHT)
{
i = 1;
}
if (state.getValue(PART) == EnumPartType.HEAD_LEFT)
{
i = 2;
}
if (state.getValue(PART) == EnumPartType.HEAD_RIGHT)
{
i = 3;
}
return i;
}
Теперь программа может установить следующие соответствия:
0 = FOOT_LEFT
1 = FOOT_RIGHT
2 = HEAD_LEFT
3 = HEAD_RIGHT
После этого можно приступать к связке блоков в одну структуру.
Создание полноценной структуры
Java:
@Override
public void onBlockHarvested(World worldIn, BlockPos pos, IBlockState state, EntityPlayer player) {
if (state.getValue(PART) == EnumPartType.FOOT_RIGHT) {
worldIn.setBlockState(pos.north(1), Blocks.AIR.getDefaultState());
worldIn.setBlockState(pos.west(1), Blocks.AIR.getDefaultState());
worldIn.setBlockState(pos.north(1).west(1), Blocks.AIR.getDefaultState());
}
else if (state.getValue(PART) == EnumPartType.HEAD_RIGHT) {
worldIn.setBlockState(pos.south(1), Blocks.AIR.getDefaultState());
worldIn.setBlockState(pos.west(1), Blocks.AIR.getDefaultState());
worldIn.setBlockState(pos.south(1).west(1), Blocks.AIR.getDefaultState());
}
else if (state.getValue(PART) == EnumPartType.HEAD_LEFT) {
worldIn.setBlockState(pos.south(1), Blocks.AIR.getDefaultState());
worldIn.setBlockState(pos.east(1), Blocks.AIR.getDefaultState());
worldIn.setBlockState(pos.south(1).east(1), Blocks.AIR.getDefaultState());
}
else {
worldIn.setBlockState(pos.north(1), Blocks.AIR.getDefaultState());
worldIn.setBlockState(pos.east(1), Blocks.AIR.getDefaultState());
worldIn.setBlockState(pos.north(1).east(1), Blocks.AIR.getDefaultState());
}
}
onBlockHarvested
- это событие, срабатывает после того, как блок был сломан.setBlockState
- установка блока.up(), down(), north(), south(), west(), east()
- меняет позицию на указанное направление, по указанному числу блоков (по умолчанию 1 блок).В этой части кода сделали установку уничтожение фантомных блоков. А теперь надо сделать и установку.
EventHandler
Создаём класс EventHandler.
Java:
public class EventHandler
{
@SubscribeEvent
public void onSetTable(PlayerInteractEvent.RightClickBlock event)
{
if (event.getEntity() instanceof EntityPlayer)
{
EntityPlayer player = (EntityPlayer) event.getEntity();
World worldIn = player.world;
BlockPos pos = event.getPos().up();
if (player.getHeldItem(EnumHand.MAIN_HAND).getItem() == Item.getItemFromBlock(BlocksRegister.Table)) {
if (worldIn.isAirBlock(pos) && worldIn.isAirBlock(pos.north(1)) && worldIn.isAirBlock(pos.east(1)) && worldIn.isAirBlock(pos.north(1).east(1))) {
worldIn.setBlockState(pos.north(1), BlocksRegister.Table.getDefaultState().withProperty(PART, BlockTable.EnumPartType.HEAD_LEFT));
worldIn.setBlockState(pos.east(1), BlocksRegister.Table.getDefaultState().withProperty(PART, BlockTable.EnumPartType.FOOT_RIGHT));
worldIn.setBlockState(pos.north(1).east(1), BlocksRegister.Table.getDefaultState().withProperty(PART, BlockTable.EnumPartType.HEAD_RIGHT));
}
else {
event.setCanceled(true);
}
}
}
}
}
isAirBlock
- проверка, является ли блок воздухом.setCanceled
- отменяем событие.Мета
Наши модели
JSON:
{
"textures": {
"0": "minecraft:blocks/log_oak",
"particle": "minecraft:blocks/log_oak"
},
"elements": [
{
"from": [ 0.0, 0.0, 14.0 ],
"to": [ 2.0, 9.0, 16.0 ],
"faces": {
"north": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"east": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"south": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"west": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"up": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 2.0 ] },
"down": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }
}
},
{
"from": [ 0.0, 9.0, 0.0 ],
"to": [ 16.0, 10.0, 16.0 ],
"faces": {
"north": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"east": { "texture": "#0", "uv": [ 0.0, 0.0, 15.0, 1.0 ] },
"south": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"west": { "texture": "#0", "uv": [ 0.0, 0.0, 15.0, 1.0 ] },
"up": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 15.0 ] },
"down": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 15.0 ] }
}
}
]
}
JSON:
{
"textures": {
"0": "minecraft:blocks/log_oak",
"particle": "minecraft:blocks/log_oak"
},
"elements": [
{
"from": [ 14.0, 0.0, 14.0 ],
"to": [ 16.0, 9.0, 16.0 ],
"faces": {
"north": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"east": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"south": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"west": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"up": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 2.0 ] },
"down": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }
}
},
{
"from": [ 0.0, 9.0, 0.0 ],
"to": [ 16.0, 10.0, 16.0 ],
"faces": {
"north": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"east": { "texture": "#0", "uv": [ 0.0, 0.0, 15.0, 1.0 ] },
"south": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"west": { "texture": "#0", "uv": [ 0.0, 0.0, 15.0, 1.0 ] },
"up": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 15.0 ] },
"down": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 15.0 ] }
}
}
]
}
JSON:
{
"textures": {
"0": "minecraft:blocks/log_oak",
"particle": "minecraft:blocks/log_oak"
},
"elements": [
{
"from": [ 0.0, 0.0, 0.0 ],
"to": [ 2.0, 9.0, 2.0 ],
"faces": {
"north": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"east": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"south": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"west": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"up": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 2.0 ] },
"down": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }
}
},
{
"from": [ 0.0, 9.0, 0.0 ],
"to": [ 16.0, 10.0, 16.0 ],
"faces": {
"north": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"east": { "texture": "#0", "uv": [ 0.0, 0.0, 15.0, 1.0 ] },
"south": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"west": { "texture": "#0", "uv": [ 0.0, 0.0, 15.0, 1.0 ] },
"up": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 15.0 ] },
"down": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 15.0 ] }
}
}
]
}
JSON:
{
"textures": {
"0": "minecraft:blocks/log_oak",
"particle": "minecraft:blocks/log_oak"
},
"elements": [
{
"from": [ 14.0, 0.0, 0.0 ],
"to": [ 16.0, 9.0, 2.0 ],
"faces": {
"north": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"east": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"south": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"west": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 15.0 ] },
"up": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 2.0 ] },
"down": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }
}
},
{
"from": [ 0.0, 9.0, 0.0 ],
"to": [ 16.0, 10.0, 16.0 ],
"faces": {
"north": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"east": { "texture": "#0", "uv": [ 0.0, 0.0, 15.0, 1.0 ] },
"south": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"west": { "texture": "#0", "uv": [ 0.0, 0.0, 15.0, 1.0 ] },
"up": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 15.0 ] },
"down": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 15.0 ] }
}
}
]
}
Blockstate
JSON:
{
"variants": {
"part=foot_right": { "model": "tutmod:foot_right" },
"part=foot_left": { "model": "tutmod:foot_left" },
"part=head_right": { "model": "tutmod:head_right" },
"part=head_left": { "model": "tutmod:head_left" }
}
}
Создадим json файл по пути
tutmod/main/resources/models/item/table.json
Java:
{
"parent": "item/generated",
"textures": {
"layer0":"tutmod:items/table"
}
}
Локализация блока
tile.table.name=Стол
Финал. Регистрация
BlocksRegister
Java:
public static final Block Table = new BlockTable("table");
public static void register()
{
setRegister(Table);
}
public static void registerRender()
{
setRender(Table);
}
private static void setRegister(Block block)
{
ForgeRegistries.BLOCKS.register(block);
ForgeRegistries.ITEMS.register(new ItemBlock(block).setRegistryName(block.getRegistryName()));
}
private static void setRender(Block block)
{
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(Item.getItemFromBlock(block), 0, new ModelResourceLocation(block.getRegistryName(), "inventory"));
}
}