Base blocks (WIP)
This commit is contained in:
parent
feb6c5172c
commit
c4a510bd2e
56 changed files with 4418 additions and 1 deletions
|
@ -8,7 +8,7 @@ yarn_mappings=6
|
||||||
loader_version=0.11.3
|
loader_version=0.11.3
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version = 0.1.2
|
mod_version = 0.1.3
|
||||||
maven_group = ru.bclib
|
maven_group = ru.bclib
|
||||||
archives_base_name = bclib
|
archives_base_name = bclib
|
||||||
|
|
||||||
|
|
75
src/main/java/ru/bclib/blocks/BaseAttachedBlock.java
Normal file
75
src/main/java/ru/bclib/blocks/BaseAttachedBlock.java
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.tags.BlockTags;
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.Mirror;
|
||||||
|
import net.minecraft.world.level.block.Rotation;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||||
|
import ru.bclib.util.BlocksHelper;
|
||||||
|
|
||||||
|
public abstract class BaseAttachedBlock extends BaseBlockNotFull {
|
||||||
|
public static final DirectionProperty FACING = BlockStateProperties.FACING;
|
||||||
|
|
||||||
|
public BaseAttachedBlock(Properties settings) {
|
||||||
|
super(settings);
|
||||||
|
this.registerDefaultState(this.defaultBlockState().setValue(FACING, Direction.UP));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> stateManager) {
|
||||||
|
stateManager.add(FACING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
|
||||||
|
BlockState blockState = this.defaultBlockState();
|
||||||
|
LevelReader worldView = ctx.getLevel();
|
||||||
|
BlockPos blockPos = ctx.getClickedPos();
|
||||||
|
Direction[] directions = ctx.getNearestLookingDirections();
|
||||||
|
for (Direction direction : directions) {
|
||||||
|
Direction direction2 = direction.getOpposite();
|
||||||
|
blockState = blockState.setValue(FACING, direction2);
|
||||||
|
if (blockState.canSurvive(worldView, blockPos)) {
|
||||||
|
return blockState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
Direction direction = (Direction) state.getValue(FACING);
|
||||||
|
BlockPos blockPos = pos.relative(direction.getOpposite());
|
||||||
|
return canSupportCenter(world, blockPos, direction) || world.getBlockState(blockPos).is(BlockTags.LEAVES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
if (!canSurvive(state, world, pos)) {
|
||||||
|
return Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, Rotation rotation) {
|
||||||
|
return BlocksHelper.rotateHorizontal(state, rotation, FACING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, Mirror mirror) {
|
||||||
|
return BlocksHelper.mirrorHorizontal(state, mirror, FACING);
|
||||||
|
}
|
||||||
|
}
|
24
src/main/java/ru/bclib/blocks/BaseBarkBlock.java
Normal file
24
src/main/java/ru/bclib/blocks/BaseBarkBlock.java
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class BarkBlock extends EndPillarBlock {
|
||||||
|
public BarkBlock(Properties settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Optional<String> createBlockPattern(ResourceLocation blockId) {
|
||||||
|
blockId = Registry.BLOCK.getKey(this);
|
||||||
|
return Patterns.createJson(Patterns.BLOCK_BASE, getName(blockId), blockId.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getName(ResourceLocation blockId) {
|
||||||
|
String name = blockId.getPath();
|
||||||
|
return name.replace("_bark", "_log_side");
|
||||||
|
}
|
||||||
|
}
|
28
src/main/java/ru/bclib/blocks/BaseBlock.java
Normal file
28
src/main/java/ru/bclib/blocks/BaseBlock.java
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.bclib.client.models.BlockModelProvider;
|
||||||
|
|
||||||
|
public class BaseBlock extends Block implements BlockModelProvider {
|
||||||
|
public BaseBlock(Properties settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
return getBlockModel(blockId, defaultBlockState());
|
||||||
|
}
|
||||||
|
}
|
25
src/main/java/ru/bclib/blocks/BaseBlockNotFull.java
Normal file
25
src/main/java/ru/bclib/blocks/BaseBlockNotFull.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
public class BaseBlockNotFull extends BaseBlock {
|
||||||
|
|
||||||
|
public BaseBlockNotFull(Properties settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canSuffocate(BlockState state, BlockGetter view, BlockPos pos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSimpleFullBlock(BlockState state, BlockGetter view, BlockPos pos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allowsSpawning(BlockState state, BlockGetter view, BlockPos pos, EntityType<?> type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
27
src/main/java/ru/bclib/blocks/BaseBlockWithEntity.java
Normal file
27
src/main/java/ru/bclib/blocks/BaseBlockWithEntity.java
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.block.BaseEntityBlock;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
|
||||||
|
public class BaseBlockWithEntity extends BaseEntityBlock {
|
||||||
|
public BaseBlockWithEntity(Properties settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockGetter world) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
}
|
122
src/main/java/ru/bclib/blocks/BaseCropBlock.java
Normal file
122
src/main/java/ru/bclib/blocks/BaseCropBlock.java
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.bclib.util.MHelper;
|
||||||
|
import ru.betterend.util.BlocksHelper;
|
||||||
|
|
||||||
|
public class BaseCropBlock extends BasePlantBlock {
|
||||||
|
private static final VoxelShape SHAPE = Block.box(2, 0, 2, 14, 14, 14);
|
||||||
|
public static final IntegerProperty AGE = IntegerProperty.create("age", 0, 3);
|
||||||
|
|
||||||
|
private final Block[] terrain;
|
||||||
|
private final Item drop;
|
||||||
|
|
||||||
|
public BaseCropBlock(Item drop, Block... terrain) {
|
||||||
|
super(FabricBlockSettings.of(Material.PLANT)
|
||||||
|
.breakByTool(FabricToolTags.HOES)
|
||||||
|
.breakByHand(true)
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.randomTicks()
|
||||||
|
.noCollission());
|
||||||
|
this.drop = drop;
|
||||||
|
this.terrain = terrain;
|
||||||
|
this.registerDefaultState(defaultBlockState().setValue(AGE, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> stateManager) {
|
||||||
|
stateManager.add(AGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isTerrain(BlockState state) {
|
||||||
|
for (Block block: terrain) {
|
||||||
|
if (state.is(block)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
if (state.getValue(AGE) < 3) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||||
|
if (tool != null && tool.isCorrectToolForDrops(state)) {
|
||||||
|
int enchantment = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.BLOCK_FORTUNE, tool);
|
||||||
|
if (enchantment > 0) {
|
||||||
|
int countSeeds = MHelper.randRange(Mth.clamp(1 + enchantment, 1, 3), 3, MHelper.RANDOM);
|
||||||
|
int countDrops = MHelper.randRange(Mth.clamp(1 + enchantment, 1, 2), 2, MHelper.RANDOM);
|
||||||
|
return Lists.newArrayList(new ItemStack(this, countSeeds), new ItemStack(drop, countDrops));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int countSeeds = MHelper.randRange(1, 3, MHelper.RANDOM);
|
||||||
|
int countDrops = MHelper.randRange(1, 2, MHelper.RANDOM);
|
||||||
|
return Lists.newArrayList(new ItemStack(this, countSeeds), new ItemStack(drop, countDrops));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockBehaviour.OffsetType getOffsetType() {
|
||||||
|
return BlockBehaviour.OffsetType.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performBonemeal(ServerLevel world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
int age = state.getValue(AGE);
|
||||||
|
if (age < 3) {
|
||||||
|
BlocksHelper.setWithUpdate(world, pos, state.setValue(AGE, age + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidBonemealTarget(BlockGetter world, BlockPos pos, BlockState state, boolean isClient) {
|
||||||
|
return state.getValue(AGE) < 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
return state.getValue(AGE) < 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||||
|
super.tick(state, world, pos, random);
|
||||||
|
if (isBonemealSuccess(world, random, pos, state) && random.nextInt(8) == 0) {
|
||||||
|
performBonemeal(world, random, pos, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
return SHAPE;
|
||||||
|
}
|
||||||
|
}
|
130
src/main/java/ru/bclib/blocks/BasePlantBlock.java
Normal file
130
src/main/java/ru/bclib/blocks/BasePlantBlock.java
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.BonemealableBlock;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.bclib.client.render.ERenderLayer;
|
||||||
|
import ru.bclib.interfaces.IRenderTypeable;
|
||||||
|
|
||||||
|
public class BasePlantBlock extends BaseBlockNotFull implements IRenderTypeable, BonemealableBlock {
|
||||||
|
private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12);
|
||||||
|
|
||||||
|
public BasePlantBlock() {
|
||||||
|
this(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasePlantBlock(int light) {
|
||||||
|
this(false, light);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasePlantBlock(boolean replaceable) {
|
||||||
|
super(FabricBlockSettings.of(replaceable ? Material.REPLACEABLE_PLANT : Material.PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasePlantBlock(boolean replaceable, int light) {
|
||||||
|
super(FabricBlockSettings.of(replaceable ? Material.REPLACEABLE_PLANT : Material.PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.luminance(light)
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasePlantBlock(Properties settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
Vec3 vec3d = state.getOffset(view, pos);
|
||||||
|
return SHAPE.move(vec3d.x, vec3d.y, vec3d.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockBehaviour.OffsetType getOffsetType() {
|
||||||
|
return BlockBehaviour.OffsetType.XZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
BlockState down = world.getBlockState(pos.below());
|
||||||
|
return isTerrain(down);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isTerrain(BlockState state) {
|
||||||
|
return state.is(EndTags.END_GROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
if (!canSurvive(state, world, pos)) {
|
||||||
|
return Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||||
|
if (tool != null && tool.getItem().is(FabricToolTags.SHEARS) || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0) {
|
||||||
|
return Lists.newArrayList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Lists.newArrayList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidBonemealTarget(BlockGetter world, BlockPos pos, BlockState state, boolean isClient) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performBonemeal(ServerLevel world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
ItemEntity item = new ItemEntity(world, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, new ItemStack(this));
|
||||||
|
world.addFreshEntity(item);
|
||||||
|
}
|
||||||
|
}
|
65
src/main/java/ru/bclib/blocks/BasePlantWithAgeBlock.java
Normal file
65
src/main/java/ru/bclib/blocks/BasePlantWithAgeBlock.java
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.WorldGenLevel;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import ru.betterend.blocks.BlockProperties;
|
||||||
|
|
||||||
|
public abstract class BasePlantWithAgeBlock extends BasePlantBlock {
|
||||||
|
public static final IntegerProperty AGE = BlockProperties.AGE;
|
||||||
|
|
||||||
|
public BasePlantWithAgeBlock() {
|
||||||
|
this(FabricBlockSettings.of(Material.PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.randomTicks()
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasePlantWithAgeBlock(Properties settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> stateManager) {
|
||||||
|
stateManager.add(AGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void growAdult(WorldGenLevel world, Random random, BlockPos pos);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performBonemeal(ServerLevel world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
int age = state.getValue(AGE);
|
||||||
|
if (age < 3) {
|
||||||
|
world.setBlockAndUpdate(pos, state.setValue(AGE, age + 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
growAdult(world, random, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||||
|
super.tick(state, world, pos, random);
|
||||||
|
if (random.nextInt(8) == 0) {
|
||||||
|
performBonemeal(world, random, pos, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
125
src/main/java/ru/bclib/blocks/BaseTerrainBlock.java
Normal file
125
src/main/java/ru/bclib/blocks/BaseTerrainBlock.java
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.SnowLayerBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.lighting.LayerLightEngine;
|
||||||
|
import net.minecraft.world.level.material.MaterialColor;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import ru.bclib.client.models.BasePatterns;
|
||||||
|
import ru.bclib.client.models.ModelsHelper;
|
||||||
|
import ru.bclib.client.models.PatternsHelper;
|
||||||
|
import ru.bclib.client.sound.BlockSounds;
|
||||||
|
|
||||||
|
public class BaseTerrainBlock extends BaseBlock {
|
||||||
|
private Block pathBlock;
|
||||||
|
|
||||||
|
public BaseTerrainBlock(MaterialColor color) {
|
||||||
|
super(FabricBlockSettings.copyOf(Blocks.END_STONE).materialColor(color).sound(BlockSounds.TERRAIN_SOUND).randomTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPathBlock(Block roadBlock) {
|
||||||
|
this.pathBlock = roadBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
|
if (pathBlock != null && player.getMainHandItem().getItem().is(FabricToolTags.SHOVELS)) {
|
||||||
|
world.playSound(player, pos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||||
|
if (!world.isClientSide) {
|
||||||
|
world.setBlockAndUpdate(pos, pathBlock.defaultBlockState());
|
||||||
|
if (!player.isCreative()) {
|
||||||
|
player.getMainHandItem().hurt(1, world.random, (ServerPlayer) player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||||
|
if (tool != null && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
return Collections.singletonList(new ItemStack(Blocks.END_STONE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||||
|
if (random.nextInt(16) == 0 && !canStay(state, world, pos)) {
|
||||||
|
world.setBlockAndUpdate(pos, Blocks.END_STONE.defaultBlockState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canStay(BlockState state, LevelReader worldView, BlockPos pos) {
|
||||||
|
BlockPos blockPos = pos.above();
|
||||||
|
BlockState blockState = worldView.getBlockState(blockPos);
|
||||||
|
if (blockState.is(Blocks.SNOW) && (Integer) blockState.getValue(SnowLayerBlock.LAYERS) == 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (blockState.getFluidState().getAmount() == 8) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int i = LayerLightEngine.getLightBlockInto(worldView, state, pos, blockState, blockPos, Direction.UP, blockState.getLightBlock(worldView, blockPos));
|
||||||
|
return i < 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
return getBlockModel(blockId, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
String name = resourceLocation.getPath();
|
||||||
|
Map<String, String> textures = Maps.newHashMap();
|
||||||
|
textures.put("%top%", "betterend:block/" + name + "_top");
|
||||||
|
textures.put("%side%", "betterend:block/" + name + "_side");
|
||||||
|
textures.put("%bottom%", "minecraft:block/end_stone");
|
||||||
|
Optional<String> pattern = PatternsHelper.createJson(BasePatterns.BLOCK_TOP_SIDE_BOTTOM, textures);
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(), "block/" + stateId.getPath());
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
return ModelsHelper.createRandomTopModel(modelId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.LiquidBlockContainer;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.level.material.Fluids;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
|
||||||
|
public class BaseUnderwaterWallPlantBlock extends BaseWallPlantBlock implements LiquidBlockContainer {
|
||||||
|
|
||||||
|
public BaseUnderwaterWallPlantBlock() {
|
||||||
|
super(FabricBlockSettings.of(Material.WATER_PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.sound(SoundType.WET_GRASS)
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseUnderwaterWallPlantBlock(int light) {
|
||||||
|
super(FabricBlockSettings.of(Material.WATER_PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.luminance(light)
|
||||||
|
.sound(SoundType.WET_GRASS)
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseUnderwaterWallPlantBlock(Properties settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlaceLiquid(BlockGetter world, BlockPos pos, BlockState state, Fluid fluid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean placeLiquid(LevelAccessor world, BlockPos pos, BlockState state, FluidState fluidState) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidState getFluidState(BlockState state) {
|
||||||
|
return Fluids.WATER.getSource(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
return world.getFluidState(pos).getType() == Fluids.WATER && super.canSurvive(state, world, pos);
|
||||||
|
}
|
||||||
|
}
|
125
src/main/java/ru/bclib/blocks/BaseWallPlantBlock.java
Normal file
125
src/main/java/ru/bclib/blocks/BaseWallPlantBlock.java
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.EnumMap;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||||
|
import net.minecraft.world.level.block.Mirror;
|
||||||
|
import net.minecraft.world.level.block.Rotation;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.bclib.util.BlocksHelper;
|
||||||
|
|
||||||
|
public class BaseWallPlantBlock extends BasePlantBlock {
|
||||||
|
private static final EnumMap<Direction, VoxelShape> SHAPES = Maps.newEnumMap(ImmutableMap.of(
|
||||||
|
Direction.NORTH, Block.box(1, 1, 8, 15, 15, 16),
|
||||||
|
Direction.SOUTH, Block.box(1, 1, 0, 15, 15, 8),
|
||||||
|
Direction.WEST, Block.box(8, 1, 1, 16, 15, 15),
|
||||||
|
Direction.EAST, Block.box(0, 1, 1, 8, 15, 15)));
|
||||||
|
public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING;
|
||||||
|
|
||||||
|
public BaseWallPlantBlock() {
|
||||||
|
this(FabricBlockSettings.of(Material.PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseWallPlantBlock(int light) {
|
||||||
|
this(FabricBlockSettings.of(Material.PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.luminance(light)
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseWallPlantBlock(Properties settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> stateManager) {
|
||||||
|
stateManager.add(FACING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
return SHAPES.get(state.getValue(FACING));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockBehaviour.OffsetType getOffsetType() {
|
||||||
|
return BlockBehaviour.OffsetType.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
Direction direction = (Direction) state.getValue(FACING);
|
||||||
|
BlockPos blockPos = pos.relative(direction.getOpposite());
|
||||||
|
BlockState blockState = world.getBlockState(blockPos);
|
||||||
|
return isSupport(world, blockPos, blockState, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSupport(LevelReader world, BlockPos pos, BlockState blockState, Direction direction) {
|
||||||
|
return blockState.getMaterial().isSolid() && blockState.isFaceSturdy(world, pos, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
|
||||||
|
BlockState blockState = this.defaultBlockState();
|
||||||
|
LevelReader worldView = ctx.getLevel();
|
||||||
|
BlockPos blockPos = ctx.getClickedPos();
|
||||||
|
Direction[] directions = ctx.getNearestLookingDirections();
|
||||||
|
for (int i = 0; i < directions.length; ++i) {
|
||||||
|
Direction direction = directions[i];
|
||||||
|
if (direction.getAxis().isHorizontal()) {
|
||||||
|
Direction direction2 = direction.getOpposite();
|
||||||
|
blockState = blockState.setValue(FACING, direction2);
|
||||||
|
if (blockState.canSurvive(worldView, blockPos)) {
|
||||||
|
return blockState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
if (!canSurvive(state, world, pos)) {
|
||||||
|
return Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, Rotation rotation) {
|
||||||
|
return BlocksHelper.rotateHorizontal(state, rotation, FACING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, Mirror mirror) {
|
||||||
|
return BlocksHelper.mirrorHorizontal(state, mirror, FACING);
|
||||||
|
}
|
||||||
|
}
|
153
src/main/java/ru/bclib/blocks/DoublePlantBlock.java
Normal file
153
src/main/java/ru/bclib/blocks/DoublePlantBlock.java
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.BonemealableBlock;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||||
|
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.betterend.blocks.BlockProperties;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
import ru.betterend.registry.EndTags;
|
||||||
|
import ru.betterend.util.BlocksHelper;
|
||||||
|
|
||||||
|
public class DoublePlantBlock extends BlockBaseNotFull implements IRenderTypeable, BonemealableBlock {
|
||||||
|
private static final VoxelShape SHAPE = Block.box(4, 2, 4, 12, 16, 12);
|
||||||
|
public static final IntegerProperty ROTATION = BlockProperties.ROTATION;
|
||||||
|
public static final BooleanProperty TOP = BooleanProperty.create("top");
|
||||||
|
|
||||||
|
public DoublePlantBlock() {
|
||||||
|
super(FabricBlockSettings.of(Material.PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.sound(SoundType.WET_GRASS)
|
||||||
|
.noCollission());
|
||||||
|
this.registerDefaultState(this.stateDefinition.any().setValue(TOP, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoublePlantBlock(int light) {
|
||||||
|
super(FabricBlockSettings.of(Material.PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.sound(SoundType.WET_GRASS)
|
||||||
|
.lightLevel((state) -> state.getValue(TOP) ? light : 0)
|
||||||
|
.noCollission());
|
||||||
|
this.registerDefaultState(this.stateDefinition.any().setValue(TOP, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> stateManager) {
|
||||||
|
stateManager.add(TOP, ROTATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
Vec3 vec3d = state.getOffset(view, pos);
|
||||||
|
return SHAPE.move(vec3d.x, vec3d.y, vec3d.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockBehaviour.OffsetType getOffsetType() {
|
||||||
|
return BlockBehaviour.OffsetType.XZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
BlockState down = world.getBlockState(pos.below());
|
||||||
|
BlockState up = world.getBlockState(pos.above());
|
||||||
|
return state.getValue(TOP) ? down.getBlock() == this : isTerrain(down) && (up.getMaterial().isReplaceable());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canStayAt(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
BlockState down = world.getBlockState(pos.below());
|
||||||
|
BlockState up = world.getBlockState(pos.above());
|
||||||
|
return state.getValue(TOP) ? down.getBlock() == this : isTerrain(down) && (up.getBlock() == this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isTerrain(BlockState state) {
|
||||||
|
return state.is(EndTags.END_GROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
if (!canStayAt(state, world, pos)) {
|
||||||
|
return Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
if (state.getValue(TOP)) {
|
||||||
|
return Lists.newArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||||
|
if (tool != null && tool.getItem().is(FabricToolTags.SHEARS) || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0) {
|
||||||
|
return Lists.newArrayList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Lists.newArrayList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidBonemealTarget(BlockGetter world, BlockPos pos, BlockState state, boolean isClient) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performBonemeal(ServerLevel world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
ItemEntity item = new ItemEntity(world, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, new ItemStack(this));
|
||||||
|
world.addFreshEntity(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) {
|
||||||
|
int rot = world.random.nextInt(4);
|
||||||
|
BlockState bs = this.defaultBlockState().setValue(ROTATION, rot);
|
||||||
|
BlocksHelper.setWithoutUpdate(world, pos, bs);
|
||||||
|
BlocksHelper.setWithoutUpdate(world, pos.above(), bs.setValue(TOP, true));
|
||||||
|
}
|
||||||
|
}
|
96
src/main/java/ru/bclib/blocks/EndAnvilBlock.java
Normal file
96
src/main/java/ru/bclib/blocks/EndAnvilBlock.java
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.AnvilBlock;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||||
|
import net.minecraft.world.level.material.MaterialColor;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.blocks.BlockProperties;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndAnvilBlock extends AnvilBlock implements BlockModelProvider {
|
||||||
|
private static final IntegerProperty DESTRUCTION = BlockProperties.DESTRUCTION;
|
||||||
|
protected final int level;
|
||||||
|
|
||||||
|
public EndAnvilBlock(MaterialColor color, int level) {
|
||||||
|
super(FabricBlockSettings.copyOf(Blocks.ANVIL).materialColor(color));
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||||
|
super.createBlockStateDefinition(builder);
|
||||||
|
builder.add(getDestructionProperty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegerProperty getDestructionProperty() {
|
||||||
|
return DESTRUCTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCraftingLevel() {
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
ItemStack stack = new ItemStack(this);
|
||||||
|
int level = state.getValue(getDestructionProperty());
|
||||||
|
stack.getOrCreateTag().putInt("level", level);
|
||||||
|
return Collections.singletonList(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getTop(ResourceLocation blockId, String block) {
|
||||||
|
if (block.contains("item")) {
|
||||||
|
return blockId.getPath() + "_top_0";
|
||||||
|
}
|
||||||
|
char last = block.charAt(block.length() - 1);
|
||||||
|
return blockId.getPath() + "_top_" + last;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
return getBlockModel(blockId, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
IntegerProperty destructionProperty = getDestructionProperty();
|
||||||
|
int destruction = blockState.getValue(destructionProperty);
|
||||||
|
String name = blockId.getPath();
|
||||||
|
Map<String, String> textures = Maps.newHashMap();
|
||||||
|
textures.put("%anvil%", name);
|
||||||
|
textures.put("%top%", name + "_top_" + destruction);
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.BLOCK_ANVIL, textures);
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
IntegerProperty destructionProperty = getDestructionProperty();
|
||||||
|
int destruction = blockState.getValue(destructionProperty);
|
||||||
|
String modId = stateId.getNamespace();
|
||||||
|
String modelId = "block/" + stateId.getPath() + "_top_" + destruction;
|
||||||
|
ResourceLocation modelLocation = new ResourceLocation(modId, modelId);
|
||||||
|
registerBlockModel(stateId, modelLocation, blockState, modelCache);
|
||||||
|
return ModelsHelper.createFacingModel(modelLocation, blockState.getValue(FACING), false, false);
|
||||||
|
}
|
||||||
|
}
|
133
src/main/java/ru/bclib/blocks/EndBarrelBlock.java
Normal file
133
src/main/java/ru/bclib/blocks/EndBarrelBlock.java
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.stats.Stats;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.monster.piglin.PiglinAi;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.BarrelBlock;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.RenderShape;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import ru.betterend.blocks.entities.EBarrelBlockEntity;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
import ru.betterend.registry.EndBlockEntities;
|
||||||
|
|
||||||
|
public class EndBarrelBlock extends BarrelBlock implements BlockModelProvider {
|
||||||
|
public EndBarrelBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source).noOcclusion());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockGetter world) {
|
||||||
|
return EndBlockEntities.BARREL.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
List<ItemStack> drop = super.getDrops(state, builder);
|
||||||
|
drop.add(new ItemStack(this.asItem()));
|
||||||
|
return drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand,
|
||||||
|
BlockHitResult hit) {
|
||||||
|
if (world.isClientSide) {
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
} else {
|
||||||
|
BlockEntity blockEntity = world.getBlockEntity(pos);
|
||||||
|
if (blockEntity instanceof EBarrelBlockEntity) {
|
||||||
|
player.openMenu((EBarrelBlockEntity) blockEntity);
|
||||||
|
player.awardStat(Stats.OPEN_BARREL);
|
||||||
|
PiglinAi.angerNearbyPiglins(player, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return InteractionResult.CONSUME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||||
|
BlockEntity blockEntity = world.getBlockEntity(pos);
|
||||||
|
if (blockEntity instanceof EBarrelBlockEntity) {
|
||||||
|
((EBarrelBlockEntity) blockEntity).tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RenderShape getRenderShape(BlockState state) {
|
||||||
|
return RenderShape.MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer,
|
||||||
|
ItemStack itemStack) {
|
||||||
|
if (itemStack.hasCustomHoverName()) {
|
||||||
|
BlockEntity blockEntity = world.getBlockEntity(pos);
|
||||||
|
if (blockEntity instanceof EBarrelBlockEntity) {
|
||||||
|
((EBarrelBlockEntity) blockEntity).setCustomName(itemStack.getHoverName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
return getBlockModel(blockId, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
String texture = blockId.getPath();
|
||||||
|
Optional<String> pattern;
|
||||||
|
if (blockState.getValue(OPEN)) {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_BARREL_OPEN, texture, texture);
|
||||||
|
} else {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_BOTTOM_TOP, texture, texture);
|
||||||
|
}
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
String open = blockState.getValue(OPEN) ? "_open" : "";
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + open);
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
Direction facing = blockState.getValue(FACING);
|
||||||
|
BlockModelRotation rotation = BlockModelRotation.X0_Y0;
|
||||||
|
switch (facing) {
|
||||||
|
case NORTH: rotation = BlockModelRotation.X90_Y0; break;
|
||||||
|
case EAST: rotation = BlockModelRotation.X90_Y90; break;
|
||||||
|
case SOUTH: rotation = BlockModelRotation.X90_Y180; break;
|
||||||
|
case WEST: rotation = BlockModelRotation.X90_Y270; break;
|
||||||
|
case DOWN:
|
||||||
|
default: rotation = BlockModelRotation.X180_Y0; break;
|
||||||
|
}
|
||||||
|
return ModelsHelper.createMultiVariant(modelId, rotation.getRotation(), false);
|
||||||
|
}
|
||||||
|
}
|
41
src/main/java/ru/bclib/blocks/EndBlockStripableLogLog.java
Normal file
41
src/main/java/ru/bclib/blocks/EndBlockStripableLogLog.java
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.RotatedPillarBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.material.MaterialColor;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
|
||||||
|
public class EndBlockStripableLogLog extends EndPillarBlock {
|
||||||
|
private final Block striped;
|
||||||
|
|
||||||
|
public EndBlockStripableLogLog(MaterialColor color, Block striped) {
|
||||||
|
super(FabricBlockSettings.copyOf(striped).materialColor(color));
|
||||||
|
this.striped = striped;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
|
if (player.getMainHandItem().getItem().is(FabricToolTags.AXES)) {
|
||||||
|
world.playSound(player, pos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||||
|
if (!world.isClientSide) {
|
||||||
|
world.setBlock(pos, striped.defaultBlockState().setValue(RotatedPillarBlock.AXIS, state.getValue(RotatedPillarBlock.AXIS)), 11);
|
||||||
|
if (player != null && !player.isCreative()) {
|
||||||
|
player.getMainHandItem().hurt(1, world.random, (ServerPlayer) player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
}
|
51
src/main/java/ru/bclib/blocks/EndBookshelfBlock.java
Normal file
51
src/main/java/ru/bclib/blocks/EndBookshelfBlock.java
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndBookshelfBlock extends BlockBase {
|
||||||
|
public EndBookshelfBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||||
|
if (tool != null && tool.isCorrectToolForDrops(state)) {
|
||||||
|
int silk = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool);
|
||||||
|
if (silk > 0) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.singletonList(new ItemStack(Items.BOOK, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.BLOCK_BOOKSHELF,
|
||||||
|
getName(blockId), blockId.getPath());
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getName(ResourceLocation blockId) {
|
||||||
|
String name = blockId.getPath();
|
||||||
|
return name.replace("_bookshelf", "");
|
||||||
|
}
|
||||||
|
}
|
80
src/main/java/ru/bclib/blocks/EndButtonBlock.java
Normal file
80
src/main/java/ru/bclib/blocks/EndButtonBlock.java
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.ButtonBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.AttachFace;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public abstract class EndButtonBlock extends ButtonBlock implements BlockModelProvider {
|
||||||
|
|
||||||
|
private final Block parent;
|
||||||
|
|
||||||
|
protected EndButtonBlock(Block parent, Properties properties, boolean sensitive) {
|
||||||
|
super(sensitive, properties);
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.ITEM_BUTTON, parentId.getPath(), blockId.getPath());
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
ResourceLocation blockId = Registry.BLOCK.getKey(this);
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
Optional<String> pattern = blockState.getValue(POWERED) ?
|
||||||
|
Patterns.createJson(Patterns.BLOCK_BUTTON_PRESSED, parentId.getPath(), blockId.getPath()) :
|
||||||
|
Patterns.createJson(Patterns.BLOCK_BUTTON, parentId.getPath(), blockId.getPath());
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
String powered = blockState.getValue(POWERED) ? "_powered" : "";
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + powered);
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
AttachFace face = blockState.getValue(FACE);
|
||||||
|
boolean isCeiling = face == AttachFace.CEILING;
|
||||||
|
int x = 0, y = 0;
|
||||||
|
switch (face) {
|
||||||
|
case CEILING: x = 180; break;
|
||||||
|
case WALL:
|
||||||
|
default: x = 90; break;
|
||||||
|
}
|
||||||
|
switch (blockState.getValue(FACING)) {
|
||||||
|
case NORTH: if (isCeiling) { y = 180; } break;
|
||||||
|
case EAST: y = isCeiling ? 270 : 90; break;
|
||||||
|
case SOUTH: if(!isCeiling) { y = 180; } break;
|
||||||
|
case WEST:
|
||||||
|
default: y = isCeiling ? 90 : 270; break;
|
||||||
|
}
|
||||||
|
BlockModelRotation rotation = BlockModelRotation.by(x, y);
|
||||||
|
return ModelsHelper.createMultiVariant(modelId, rotation.getRotation(), face == AttachFace.WALL);
|
||||||
|
}
|
||||||
|
}
|
62
src/main/java/ru/bclib/blocks/EndChainBlock.java
Normal file
62
src/main/java/ru/bclib/blocks/EndChainBlock.java
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.ChainBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.material.MaterialColor;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
|
||||||
|
public class EndChainBlock extends ChainBlock implements BlockModelProvider, IRenderTypeable {
|
||||||
|
public EndChainBlock(MaterialColor color) {
|
||||||
|
super(FabricBlockSettings.copyOf(Blocks.CHAIN).materialColor(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
return ModelsHelper.createItemModel(blockId.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
String name = blockId.getPath();
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.BLOCK_CHAIN, name, name);
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
Direction.Axis axis = blockState.getValue(AXIS);
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath());
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
return ModelsHelper.createRotatedModel(modelId, axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
}
|
57
src/main/java/ru/bclib/blocks/EndChestBlock.java
Normal file
57
src/main/java/ru/bclib/blocks/EndChestBlock.java
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.ChestBlock;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
import ru.betterend.registry.EndBlockEntities;
|
||||||
|
|
||||||
|
public class EndChestBlock extends ChestBlock implements BlockModelProvider {
|
||||||
|
private final Block parent;
|
||||||
|
|
||||||
|
public EndChestBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source).noOcclusion(), () -> EndBlockEntities.CHEST);
|
||||||
|
this.parent = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockGetter world)
|
||||||
|
{
|
||||||
|
return EndBlockEntities.CHEST.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder)
|
||||||
|
{
|
||||||
|
List<ItemStack> drop = super.getDrops(state, builder);
|
||||||
|
drop.add(new ItemStack(this.asItem()));
|
||||||
|
return drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.ITEM_CHEST, blockId.getPath());
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
return ModelsHelper.createBlockEmpty(parentId);
|
||||||
|
}
|
||||||
|
}
|
66
src/main/java/ru/bclib/blocks/EndComposterBlock.java
Normal file
66
src/main/java/ru/bclib/blocks/EndComposterBlock.java
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.ComposterBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.ModelsHelper.MultiPartBuilder;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndComposterBlock extends ComposterBlock implements BlockModelProvider {
|
||||||
|
public EndComposterBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this.asItem()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return getBlockModel(resourceLocation, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.BLOCK_COMPOSTER, blockId.getPath());
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(), "block/" + stateId.getPath());
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
|
||||||
|
MultiPartBuilder builder = MultiPartBuilder.create(stateDefinition);
|
||||||
|
LEVEL.getPossibleValues().forEach(level -> {
|
||||||
|
if (level > 0) {
|
||||||
|
ResourceLocation contentId;
|
||||||
|
if (level > 7) {
|
||||||
|
contentId = new ResourceLocation("block/composter_contents_ready");
|
||||||
|
} else {
|
||||||
|
contentId = new ResourceLocation("block/composter_contents" + level);
|
||||||
|
}
|
||||||
|
builder.part(contentId).setCondition(state -> state.getValue(LEVEL).equals(level)).add();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.part(modelId).add();
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
}
|
54
src/main/java/ru/bclib/blocks/EndCraftingTableBlock.java
Normal file
54
src/main/java/ru/bclib/blocks/EndCraftingTableBlock.java
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.CraftingTableBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndCraftingTableBlock extends CraftingTableBlock implements BlockModelProvider {
|
||||||
|
public EndCraftingTableBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this.asItem()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return getBlockModel(resourceLocation, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
String blockName = blockId.getPath();
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.BLOCK_SIDED, new HashMap<String, String>() {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
{
|
||||||
|
put("%particle%", blockName + "_front");
|
||||||
|
put("%down%", blockName + "_bottom");
|
||||||
|
put("%up%", blockName + "_top");
|
||||||
|
put("%north%", blockName + "_front");
|
||||||
|
put("%south%", blockName + "_side");
|
||||||
|
put("%west%", blockName + "_front");
|
||||||
|
put("%east%", blockName + "_side");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
}
|
159
src/main/java/ru/bclib/blocks/EndDoorBlock.java
Normal file
159
src/main/java/ru/bclib/blocks/EndDoorBlock.java
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.StringRepresentable;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.DoorBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.DoorHingeSide;
|
||||||
|
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
|
||||||
|
public class EndDoorBlock extends DoorBlock implements IRenderTypeable, BlockModelProvider {
|
||||||
|
public EndDoorBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source).strength(3F, 3F).noOcclusion());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
if (state.getValue(HALF) == DoubleBlockHalf.LOWER)
|
||||||
|
return Collections.singletonList(new ItemStack(this.asItem()));
|
||||||
|
else
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
String blockName = resourceLocation.getPath();
|
||||||
|
DoorType doorType = getDoorType(blockState);
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.BLOCK_DOOR_BOTTOM, blockName, blockName);
|
||||||
|
switch (doorType) {
|
||||||
|
case TOP_HINGE:
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_DOOR_TOP_HINGE, blockName, blockName);
|
||||||
|
break;
|
||||||
|
case BOTTOM_HINGE:
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_DOOR_BOTTOM_HINGE, blockName, blockName);
|
||||||
|
break;
|
||||||
|
case TOP:
|
||||||
|
default:
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_DOOR_TOP, blockName, blockName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
Direction facing = blockState.getValue(FACING);
|
||||||
|
DoorType doorType = getDoorType(blockState);
|
||||||
|
boolean open = blockState.getValue(OPEN);
|
||||||
|
boolean hinge = doorType.isHinge();
|
||||||
|
BlockModelRotation rotation = BlockModelRotation.X0_Y0;
|
||||||
|
switch (facing) {
|
||||||
|
case EAST:
|
||||||
|
if (hinge && open) {
|
||||||
|
rotation = BlockModelRotation.X0_Y90;
|
||||||
|
} else if (open) {
|
||||||
|
rotation = BlockModelRotation.X0_Y270;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SOUTH:
|
||||||
|
if (!hinge && !open || hinge && !open) {
|
||||||
|
rotation = BlockModelRotation.X0_Y90;
|
||||||
|
} else if (hinge) {
|
||||||
|
rotation = BlockModelRotation.X0_Y180;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WEST:
|
||||||
|
if (!hinge && !open || hinge && !open) {
|
||||||
|
rotation = BlockModelRotation.X0_Y180;
|
||||||
|
} else if (hinge) {
|
||||||
|
rotation = BlockModelRotation.X0_Y270;
|
||||||
|
} else {
|
||||||
|
rotation = BlockModelRotation.X0_Y90;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NORTH:
|
||||||
|
default:
|
||||||
|
if (!hinge && !open || hinge && !open) {
|
||||||
|
rotation = BlockModelRotation.X0_Y270;
|
||||||
|
} else if (!hinge) {
|
||||||
|
rotation = BlockModelRotation.X0_Y180;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + "_" + doorType);
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
return ModelsHelper.createMultiVariant(modelId, rotation.getRotation(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DoorType getDoorType(BlockState blockState) {
|
||||||
|
boolean isHinge = isHinge(blockState.getValue(HINGE), blockState.getValue(OPEN));
|
||||||
|
switch (blockState.getValue(HALF)) {
|
||||||
|
case UPPER: {
|
||||||
|
return isHinge ? DoorType.TOP_HINGE : DoorType.TOP;
|
||||||
|
}
|
||||||
|
case LOWER: {
|
||||||
|
return isHinge ? DoorType.BOTTOM_HINGE : DoorType.BOTTOM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DoorType.BOTTOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHinge(DoorHingeSide hingeSide, boolean open) {
|
||||||
|
boolean isHinge = hingeSide == DoorHingeSide.RIGHT;
|
||||||
|
return isHinge && !open || !isHinge && open;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected enum DoorType implements StringRepresentable {
|
||||||
|
BOTTOM_HINGE("bottom_hinge"),
|
||||||
|
TOP_HINGE("top_hinge"),
|
||||||
|
BOTTOM("bottom"),
|
||||||
|
TOP("top");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
DoorType(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHinge() {
|
||||||
|
return this == BOTTOM_HINGE ||
|
||||||
|
this == TOP_HINGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getSerializedName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSerializedName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
81
src/main/java/ru/bclib/blocks/EndFenceBlock.java
Normal file
81
src/main/java/ru/bclib/blocks/EndFenceBlock.java
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.FenceBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.ModelsHelper.MultiPartBuilder;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndFenceBlock extends FenceBlock implements BlockModelProvider {
|
||||||
|
private final Block parent;
|
||||||
|
|
||||||
|
public EndFenceBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source).noOcclusion());
|
||||||
|
this.parent = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.ITEM_FENCE, parentId.getPath(), blockId.getPath());
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
String path = blockId.getPath();
|
||||||
|
Optional<String> pattern = Optional.empty();
|
||||||
|
if (path.endsWith("_post")) {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_FENCE_POST, parentId.getPath(), blockId.getPath());
|
||||||
|
}
|
||||||
|
if (path.endsWith("_side")) {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_FENCE_SIDE, parentId.getPath(), blockId.getPath());
|
||||||
|
}
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
ResourceLocation postId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + "_post");
|
||||||
|
ResourceLocation sideId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + "_side");
|
||||||
|
registerBlockModel(postId, postId, blockState, modelCache);
|
||||||
|
registerBlockModel(sideId, sideId, blockState, modelCache);
|
||||||
|
|
||||||
|
MultiPartBuilder builder = MultiPartBuilder.create(stateDefinition);
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(NORTH)).setUVLock(true).add();
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(EAST))
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y90.getRotation()).setUVLock(true).add();
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(SOUTH))
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y180.getRotation()).setUVLock(true).add();
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(WEST))
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y270.getRotation()).setUVLock(true).add();
|
||||||
|
builder.part(postId).add();
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
}
|
104
src/main/java/ru/bclib/blocks/EndFurnaceBlock.java
Normal file
104
src/main/java/ru/bclib/blocks/EndFurnaceBlock.java
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.stats.Stats;
|
||||||
|
import net.minecraft.world.MenuProvider;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.FurnaceBlock;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import ru.betterend.blocks.entities.EFurnaceBlockEntity;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
|
||||||
|
public class EndFurnaceBlock extends FurnaceBlock implements BlockModelProvider, IRenderTypeable {
|
||||||
|
public EndFurnaceBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source).luminance(state -> state.getValue(LIT) ? 13 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockGetter world) {
|
||||||
|
return new EFurnaceBlockEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void openContainer(Level world, BlockPos pos, Player player) {
|
||||||
|
BlockEntity blockEntity = world.getBlockEntity(pos);
|
||||||
|
if (blockEntity instanceof EFurnaceBlockEntity) {
|
||||||
|
player.openMenu((MenuProvider) blockEntity);
|
||||||
|
player.awardStat(Stats.INTERACT_WITH_FURNACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
String blockName = blockId.getPath();
|
||||||
|
Map<String, String> textures = Maps.newHashMap();
|
||||||
|
textures.put("%top%", blockName + "_top");
|
||||||
|
textures.put("%side%", blockName + "_side");
|
||||||
|
Optional<String> pattern;
|
||||||
|
if (blockState.getValue(LIT)) {
|
||||||
|
textures.put("%front%", blockName + "_front_on");
|
||||||
|
textures.put("%glow%", blockName + "_glow");
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_FURNACE_LIT, textures);
|
||||||
|
} else {
|
||||||
|
textures.put("%front%", blockName + "_front");
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_FURNACE, textures);
|
||||||
|
}
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return getBlockModel(resourceLocation, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
String lit = blockState.getValue(LIT) ? "_lit" : "";
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + lit);
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
return ModelsHelper.createFacingModel(modelId, blockState.getValue(FACING), false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
List<ItemStack> drop = Lists.newArrayList(new ItemStack(this));
|
||||||
|
BlockEntity blockEntity = builder.getOptionalParameter(LootContextParams.BLOCK_ENTITY);
|
||||||
|
if (blockEntity instanceof EFurnaceBlockEntity) {
|
||||||
|
EFurnaceBlockEntity entity = (EFurnaceBlockEntity) blockEntity;
|
||||||
|
for (int i = 0; i < entity.getContainerSize(); i++) {
|
||||||
|
drop.add(entity.getItem(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return drop;
|
||||||
|
}
|
||||||
|
}
|
68
src/main/java/ru/bclib/blocks/EndGateBlock.java
Normal file
68
src/main/java/ru/bclib/blocks/EndGateBlock.java
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.FenceGateBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndGateBlock extends FenceGateBlock implements BlockModelProvider {
|
||||||
|
private final Block parent;
|
||||||
|
|
||||||
|
public EndGateBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source).noOcclusion());
|
||||||
|
this.parent = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return getBlockModel(resourceLocation, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
boolean inWall = blockState.getValue(IN_WALL);
|
||||||
|
boolean isOpen = blockState.getValue(OPEN);
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
Optional<String> pattern;
|
||||||
|
if (inWall) {
|
||||||
|
pattern = isOpen ? Patterns.createJson(Patterns.BLOCK_GATE_OPEN_WALL, parentId.getPath(), blockId.getPath()) :
|
||||||
|
Patterns.createJson(Patterns.BLOCK_GATE_CLOSED_WALL, parentId.getPath(), blockId.getPath());
|
||||||
|
} else {
|
||||||
|
pattern = isOpen ? Patterns.createJson(Patterns.BLOCK_GATE_OPEN, parentId.getPath(), blockId.getPath()) :
|
||||||
|
Patterns.createJson(Patterns.BLOCK_GATE_CLOSED, parentId.getPath(), blockId.getPath());
|
||||||
|
}
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
boolean inWall = blockState.getValue(IN_WALL);
|
||||||
|
boolean isOpen = blockState.getValue(OPEN);
|
||||||
|
String state = "" + (inWall ? "_wall" : "") + (isOpen ? "_open" : "_closed");
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + state);
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
return ModelsHelper.createFacingModel(modelId, blockState.getValue(FACING), true, false);
|
||||||
|
}
|
||||||
|
}
|
161
src/main/java/ru/bclib/blocks/EndLadderBlock.java
Normal file
161
src/main/java/ru/bclib/blocks/EndLadderBlock.java
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||||
|
import net.minecraft.world.level.block.Mirror;
|
||||||
|
import net.minecraft.world.level.block.Rotation;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||||
|
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.level.material.Fluids;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.bclib.client.render.ERenderLayer;
|
||||||
|
import ru.bclib.client.models.BasePatterns;
|
||||||
|
import ru.bclib.client.models.BlockModelProvider;
|
||||||
|
import ru.bclib.client.models.ModelsHelper;
|
||||||
|
import ru.bclib.client.models.PatternsHelper;
|
||||||
|
import ru.bclib.interfaces.IRenderTypeable;
|
||||||
|
import ru.bclib.util.BlocksHelper;
|
||||||
|
|
||||||
|
public class EndLadderBlock extends BaseBlockNotFull implements IRenderTypeable, BlockModelProvider {
|
||||||
|
public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING;
|
||||||
|
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
|
||||||
|
protected static final VoxelShape EAST_SHAPE = Block.box(0.0D, 0.0D, 0.0D, 3.0D, 16.0D, 16.0D);
|
||||||
|
protected static final VoxelShape WEST_SHAPE = Block.box(13.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D);
|
||||||
|
protected static final VoxelShape SOUTH_SHAPE = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 3.0D);
|
||||||
|
protected static final VoxelShape NORTH_SHAPE = Block.box(0.0D, 0.0D, 13.0D, 16.0D, 16.0D, 16.0D);
|
||||||
|
|
||||||
|
public EndLadderBlock(Block block) {
|
||||||
|
super(FabricBlockSettings.copyOf(block).noOcclusion());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> stateManager) {
|
||||||
|
stateManager.add(FACING);
|
||||||
|
stateManager.add(WATERLOGGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
switch (state.getValue(FACING)) {
|
||||||
|
case SOUTH:
|
||||||
|
return SOUTH_SHAPE;
|
||||||
|
case WEST:
|
||||||
|
return WEST_SHAPE;
|
||||||
|
case EAST:
|
||||||
|
return EAST_SHAPE;
|
||||||
|
default:
|
||||||
|
return NORTH_SHAPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canPlaceOn(BlockGetter world, BlockPos pos, Direction side) {
|
||||||
|
BlockState blockState = world.getBlockState(pos);
|
||||||
|
return !blockState.isSignalSource() && blockState.isFaceSturdy(world, pos, side);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
Direction direction = (Direction) state.getValue(FACING);
|
||||||
|
return this.canPlaceOn(world, pos.relative(direction.getOpposite()), direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState,
|
||||||
|
LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
if (facing.getOpposite() == state.getValue(FACING) && !state.canSurvive(world, pos)) {
|
||||||
|
return Blocks.AIR.defaultBlockState();
|
||||||
|
} else {
|
||||||
|
if ((Boolean) state.getValue(WATERLOGGED)) {
|
||||||
|
world.getLiquidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.updateShape(state, facing, neighborState, world, pos, neighborPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
|
||||||
|
BlockState blockState;
|
||||||
|
if (!ctx.replacingClickedOnBlock()) {
|
||||||
|
blockState = ctx.getLevel().getBlockState(ctx.getClickedPos().relative(ctx.getClickedFace().getOpposite()));
|
||||||
|
if (blockState.getBlock() == this && blockState.getValue(FACING) == ctx.getClickedFace()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blockState = defaultBlockState();
|
||||||
|
LevelReader worldView = ctx.getLevel();
|
||||||
|
BlockPos blockPos = ctx.getClickedPos();
|
||||||
|
FluidState fluidState = ctx.getLevel().getFluidState(ctx.getClickedPos());
|
||||||
|
Direction[] directions = ctx.getNearestLookingDirections();
|
||||||
|
|
||||||
|
for (Direction direction : directions) {
|
||||||
|
if (direction.getAxis().isHorizontal()) {
|
||||||
|
blockState = blockState.setValue(FACING, direction.getOpposite());
|
||||||
|
if (blockState.canSurvive(worldView, blockPos)) {
|
||||||
|
return blockState.setValue(WATERLOGGED, fluidState.getType() == Fluids.WATER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, Rotation rotation) {
|
||||||
|
return BlocksHelper.rotateHorizontal(state, rotation, FACING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, Mirror mirror) {
|
||||||
|
return BlocksHelper.mirrorHorizontal(state, mirror, FACING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidState getFluidState(BlockState state) {
|
||||||
|
return (Boolean) state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
return ModelsHelper.createBlockItem(blockId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
Optional<String> pattern = PatternsHelper.createJson(BasePatterns.BLOCK_LADDER, blockId);
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(), "block/" + stateId.getPath());
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
return ModelsHelper.createFacingModel(modelId, blockState.getValue(FACING), false, true);
|
||||||
|
}
|
||||||
|
}
|
79
src/main/java/ru/bclib/blocks/EndLeavesBlock.java
Normal file
79
src/main/java/ru/bclib/blocks/EndLeavesBlock.java
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.LeavesBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.material.MaterialColor;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import ru.bclib.util.MHelper;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
|
||||||
|
public class EndLeavesBlock extends LeavesBlock implements BlockModelProvider, IRenderTypeable {
|
||||||
|
private final Block sapling;
|
||||||
|
|
||||||
|
public EndLeavesBlock(Block sapling, MaterialColor color) {
|
||||||
|
super(FabricBlockSettings.copyOf(Blocks.OAK_LEAVES)
|
||||||
|
.materialColor(color)
|
||||||
|
.breakByTool(FabricToolTags.HOES)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.isValidSpawn((state, world, pos, type) -> false)
|
||||||
|
.isSuffocating((state, world, pos) -> false)
|
||||||
|
.isViewBlocking((state, world, pos) -> false));
|
||||||
|
this.sapling = sapling;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EndLeavesBlock(Block sapling, MaterialColor color, int light) {
|
||||||
|
super(FabricBlockSettings.copyOf(Blocks.OAK_LEAVES)
|
||||||
|
.materialColor(color)
|
||||||
|
.luminance(light)
|
||||||
|
.breakByTool(FabricToolTags.HOES)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.isValidSpawn((state, world, pos, type) -> false)
|
||||||
|
.isSuffocating((state, world, pos) -> false)
|
||||||
|
.isViewBlocking((state, world, pos) -> false));
|
||||||
|
this.sapling = sapling;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||||
|
if (tool != null) {
|
||||||
|
if (tool.getItem().is(FabricToolTags.SHEARS) || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
int fortune = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.BLOCK_FORTUNE, tool);
|
||||||
|
if (MHelper.RANDOM.nextInt(16) <= fortune) {
|
||||||
|
return Lists.newArrayList(new ItemStack(sapling));
|
||||||
|
}
|
||||||
|
return Lists.newArrayList();
|
||||||
|
}
|
||||||
|
return MHelper.RANDOM.nextInt(16) == 0 ? Lists.newArrayList(new ItemStack(sapling)) : Lists.newArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return getBlockModel(resourceLocation, defaultBlockState());
|
||||||
|
}
|
||||||
|
}
|
108
src/main/java/ru/bclib/blocks/EndMetalPaneBlock.java
Normal file
108
src/main/java/ru/bclib/blocks/EndMetalPaneBlock.java
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.IronBarsBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
|
||||||
|
public class EndMetalPaneBlock extends IronBarsBlock implements BlockModelProvider, IRenderTypeable {
|
||||||
|
public EndMetalPaneBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source).strength(5.0F, 6.0F).noOcclusion());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> getModelString(String block) {
|
||||||
|
ResourceLocation blockId = Registry.BLOCK.getKey(this);
|
||||||
|
if (block.contains("item")) {
|
||||||
|
return Patterns.createJson(Patterns.ITEM_BLOCK, blockId.getPath());
|
||||||
|
}
|
||||||
|
if (block.contains("post")) {
|
||||||
|
return Patterns.createJson(Patterns.BLOCK_BARS_POST, blockId.getPath(), blockId.getPath());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Patterns.createJson(Patterns.BLOCK_BARS_SIDE, blockId.getPath(), blockId.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return ModelsHelper.createBlockItem(resourceLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
ResourceLocation thisId = Registry.BLOCK.getKey(this);
|
||||||
|
String path = blockId.getPath();
|
||||||
|
Optional<String> pattern = Optional.empty();
|
||||||
|
if (path.endsWith("_post")) {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_BARS_POST, thisId.getPath(), thisId.getPath());
|
||||||
|
}
|
||||||
|
if (path.endsWith("_side")) {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_BARS_SIDE, thisId.getPath(), thisId.getPath());
|
||||||
|
}
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
ResourceLocation postId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + "_post");
|
||||||
|
ResourceLocation sideId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + "_side");
|
||||||
|
registerBlockModel(postId, postId, blockState, modelCache);
|
||||||
|
registerBlockModel(sideId, sideId, blockState, modelCache);
|
||||||
|
|
||||||
|
ModelsHelper.MultiPartBuilder builder = ModelsHelper.MultiPartBuilder.create(stateDefinition);
|
||||||
|
builder.part(postId).setCondition(state ->
|
||||||
|
!state.getValue(NORTH) && !state.getValue(EAST) &&
|
||||||
|
!state.getValue(SOUTH) && !state.getValue(WEST)).add();
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(NORTH)).setUVLock(true).add();
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(EAST))
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y90.getRotation()).setUVLock(true).add();
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(SOUTH))
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y180.getRotation()).setUVLock(true).add();
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(WEST))
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y270.getRotation()).setUVLock(true).add();
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public boolean skipRendering(BlockState state, BlockState stateFrom, Direction direction) {
|
||||||
|
if (direction.getAxis().isVertical() && stateFrom.getBlock().is(this) && !stateFrom.equals(state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return super.skipRendering(state, stateFrom, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
}
|
76
src/main/java/ru/bclib/blocks/EndOreBlock.java
Normal file
76
src/main/java/ru/bclib/blocks/EndOreBlock.java
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
|
import net.minecraft.world.level.block.OreBlock;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import net.minecraft.world.level.material.MaterialColor;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import ru.bclib.util.MHelper;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
|
||||||
|
public class EndOreBlock extends OreBlock implements BlockModelProvider {
|
||||||
|
private final Item dropItem;
|
||||||
|
private final int minCount;
|
||||||
|
private final int maxCount;
|
||||||
|
private final int experience;
|
||||||
|
|
||||||
|
public EndOreBlock(Item drop, int minCount, int maxCount, int experience) {
|
||||||
|
super(FabricBlockSettings.of(Material.STONE, MaterialColor.SAND)
|
||||||
|
.hardness(3F)
|
||||||
|
.resistance(9F)
|
||||||
|
.requiresCorrectToolForDrops()
|
||||||
|
.sound(SoundType.STONE));
|
||||||
|
this.dropItem = drop;
|
||||||
|
this.minCount = minCount;
|
||||||
|
this.maxCount = maxCount;
|
||||||
|
this.experience = experience;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int xpOnDrop(Random random) {
|
||||||
|
return this.experience > 0 ? random.nextInt(experience) + 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||||
|
if (tool != null && tool.isCorrectToolForDrops(state)) {
|
||||||
|
if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
int count = 0;
|
||||||
|
int enchantment = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.BLOCK_FORTUNE, tool);
|
||||||
|
if (enchantment > 0) {
|
||||||
|
int min = Mth.clamp(minCount + enchantment, minCount, maxCount);
|
||||||
|
int max = maxCount + (enchantment / Enchantments.BLOCK_FORTUNE.getMaxLevel());
|
||||||
|
if (min == max) {
|
||||||
|
return Collections.singletonList(new ItemStack(dropItem, max));
|
||||||
|
}
|
||||||
|
count = MHelper.randRange(min, max, MHelper.RANDOM);
|
||||||
|
} else {
|
||||||
|
count = MHelper.randRange(minCount, maxCount, MHelper.RANDOM);
|
||||||
|
}
|
||||||
|
return Collections.singletonList(new ItemStack(dropItem, count));
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return getBlockModel(resourceLocation, defaultBlockState());
|
||||||
|
}
|
||||||
|
}
|
82
src/main/java/ru/bclib/blocks/EndPathBlock.java
Normal file
82
src/main/java/ru/bclib/blocks/EndPathBlock.java
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndPathBlock extends BlockBaseNotFull {
|
||||||
|
private static final VoxelShape SHAPE = Block.box(0, 0, 0, 16, 15, 16);
|
||||||
|
|
||||||
|
public EndPathBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source).isValidSpawn((state, world, pos, type) -> { return false; }));
|
||||||
|
if (source instanceof BaseTerrainBlock) {
|
||||||
|
BaseTerrainBlock terrain = (BaseTerrainBlock) source;
|
||||||
|
terrain.setPathBlock(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||||
|
if (tool != null && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
return Collections.singletonList(new ItemStack(Blocks.END_STONE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
return SHAPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
return SHAPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
return getBlockModel(blockId, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
String name = resourceLocation.getPath();
|
||||||
|
Map<String, String> textures = Maps.newHashMap();
|
||||||
|
textures.put("%top%", name + "_top");
|
||||||
|
textures.put("%side%", name.replace("_path", "") + "_side");
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.BLOCK_PATH, textures);
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(), "block/" + stateId.getPath());
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
return ModelsHelper.createRandomTopModel(modelId);
|
||||||
|
}
|
||||||
|
}
|
59
src/main/java/ru/bclib/blocks/EndPillarBlock.java
Normal file
59
src/main/java/ru/bclib/blocks/EndPillarBlock.java
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.RotatedPillarBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndPillarBlock extends RotatedPillarBlock implements BlockModelProvider {
|
||||||
|
public EndPillarBlock(Properties settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EndPillarBlock(Block block) {
|
||||||
|
super(FabricBlockSettings.copyOf(block));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
return getBlockModel(blockId, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
Optional<String> pattern = createBlockPattern(blockId);
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath());
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
return ModelsHelper.createRotatedModel(modelId, blockState.getValue(AXIS));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Optional<String> createBlockPattern(ResourceLocation blockId) {
|
||||||
|
return Patterns.createBlockPillar(blockId.getPath());
|
||||||
|
}
|
||||||
|
}
|
62
src/main/java/ru/bclib/blocks/EndPlateBlock.java
Normal file
62
src/main/java/ru/bclib/blocks/EndPlateBlock.java
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.PressurePlateBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndPlateBlock extends PressurePlateBlock implements BlockModelProvider {
|
||||||
|
private final Block parent;
|
||||||
|
|
||||||
|
public EndPlateBlock(Sensitivity rule, Block source) {
|
||||||
|
super(rule, FabricBlockSettings.copyOf(source).noCollission().noOcclusion().strength(0.5F));
|
||||||
|
this.parent = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return getBlockModel(resourceLocation, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
Optional<String> pattern;
|
||||||
|
if (blockState.getValue(POWERED)) {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_PLATE_DOWN, parentId.getPath(), resourceLocation.getPath());
|
||||||
|
} else {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_PLATE_UP, parentId.getPath(), resourceLocation.getPath());
|
||||||
|
}
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
String state = blockState.getValue(POWERED) ? "_down" : "_up";
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + state);
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
return ModelsHelper.createBlockSimple(modelId);
|
||||||
|
}
|
||||||
|
}
|
197
src/main/java/ru/bclib/blocks/EndSignBlock.java
Normal file
197
src/main/java/ru/bclib/blocks/EndSignBlock.java
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundOpenSignEditorPacket;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.Mirror;
|
||||||
|
import net.minecraft.world.level.block.Rotation;
|
||||||
|
import net.minecraft.world.level.block.SignBlock;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||||
|
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||||
|
import net.minecraft.world.level.block.state.properties.WoodType;
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.level.material.Fluids;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.betterend.blocks.entities.ESignBlockEntity;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.interfaces.ISpetialItem;
|
||||||
|
import ru.betterend.util.BlocksHelper;
|
||||||
|
|
||||||
|
public class EndSignBlock extends SignBlock implements BlockModelProvider, ISpetialItem {
|
||||||
|
public static final IntegerProperty ROTATION = BlockStateProperties.ROTATION_16;
|
||||||
|
public static final BooleanProperty FLOOR = BooleanProperty.create("floor");
|
||||||
|
private static final VoxelShape[] WALL_SHAPES = new VoxelShape[] {
|
||||||
|
Block.box(0.0D, 4.5D, 14.0D, 16.0D, 12.5D, 16.0D),
|
||||||
|
Block.box(0.0D, 4.5D, 0.0D, 2.0D, 12.5D, 16.0D),
|
||||||
|
Block.box(0.0D, 4.5D, 0.0D, 16.0D, 12.5D, 2.0D),
|
||||||
|
Block.box(14.0D, 4.5D, 0.0D, 16.0D, 12.5D, 16.0D)
|
||||||
|
};
|
||||||
|
|
||||||
|
private final Block parent;
|
||||||
|
|
||||||
|
public EndSignBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source).strength(1.0F, 1.0F).noCollission().noOcclusion(), WoodType.OAK);
|
||||||
|
this.registerDefaultState(this.stateDefinition.any().setValue(ROTATION, 0).setValue(FLOOR, false).setValue(WATERLOGGED, false));
|
||||||
|
this.parent = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||||
|
builder.add(ROTATION, FLOOR, WATERLOGGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
return state.getValue(FLOOR) ? SHAPE : WALL_SHAPES[state.getValue(ROTATION) >> 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockGetter world) {
|
||||||
|
return new ESignBlockEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) {
|
||||||
|
if (placer instanceof Player) {
|
||||||
|
ESignBlockEntity sign = (ESignBlockEntity) world.getBlockEntity(pos);
|
||||||
|
if (sign != null) {
|
||||||
|
if (!world.isClientSide) {
|
||||||
|
sign.setAllowedPlayerEditor((Player) placer);
|
||||||
|
((ServerPlayer) placer).connection.send(new ClientboundOpenSignEditorPacket(pos));
|
||||||
|
} else {
|
||||||
|
sign.setEditable(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
if ((Boolean) state.getValue(WATERLOGGED)) {
|
||||||
|
world.getLiquidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
|
||||||
|
}
|
||||||
|
if (!canSurvive(state, world, pos)) {
|
||||||
|
return state.getValue(WATERLOGGED) ? state.getFluidState().createLegacyBlock() : Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
return super.updateShape(state, facing, neighborState, world, pos, neighborPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
if (!state.getValue(FLOOR)) {
|
||||||
|
int index = (((state.getValue(ROTATION) >> 2) + 2)) & 3;
|
||||||
|
return world.getBlockState(pos.relative(BlocksHelper.HORIZONTAL[index])).getMaterial().isSolid();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return world.getBlockState(pos.below()).getMaterial().isSolid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
|
||||||
|
if (ctx.getClickedFace() == Direction.UP) {
|
||||||
|
FluidState fluidState = ctx.getLevel().getFluidState(ctx.getClickedPos());
|
||||||
|
return this.defaultBlockState().setValue(FLOOR, true)
|
||||||
|
.setValue(ROTATION, Mth.floor((180.0 + ctx.getRotation() * 16.0 / 360.0) + 0.5 - 12) & 15)
|
||||||
|
.setValue(WATERLOGGED, fluidState.getType() == Fluids.WATER);
|
||||||
|
}
|
||||||
|
else if (ctx.getClickedFace() != Direction.DOWN) {
|
||||||
|
BlockState blockState = this.defaultBlockState();
|
||||||
|
FluidState fluidState = ctx.getLevel().getFluidState(ctx.getClickedPos());
|
||||||
|
LevelReader worldView = ctx.getLevel();
|
||||||
|
BlockPos blockPos = ctx.getClickedPos();
|
||||||
|
Direction[] directions = ctx.getNearestLookingDirections();
|
||||||
|
|
||||||
|
for (Direction direction : directions) {
|
||||||
|
if (direction.getAxis().isHorizontal()) {
|
||||||
|
Direction dir = direction.getOpposite();
|
||||||
|
int rot = Mth.floor((180.0 + dir.toYRot() * 16.0 / 360.0) + 0.5 + 4) & 15;
|
||||||
|
blockState = blockState.setValue(ROTATION, rot);
|
||||||
|
if (blockState.canSurvive(worldView, blockPos)) {
|
||||||
|
return blockState.setValue(FLOOR, false).setValue(WATERLOGGED, fluidState.getType() == Fluids.WATER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
return ModelsHelper.createBlockEmpty(parentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, Rotation rotation) {
|
||||||
|
return (BlockState) state.setValue(ROTATION, rotation.rotate((Integer) state.getValue(ROTATION), 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, Mirror mirror) {
|
||||||
|
return (BlockState) state.setValue(ROTATION, mirror.mirror((Integer) state.getValue(ROTATION), 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Fluid takeLiquid(LevelAccessor world, BlockPos pos, BlockState state) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlaceLiquid(BlockGetter world, BlockPos pos, BlockState state, Fluid fluid) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean placeLiquid(LevelAccessor world, BlockPos pos, BlockState state, FluidState fluidState) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStackSize() {
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlaceOnWater() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
62
src/main/java/ru/bclib/blocks/EndSlabBlock.java
Normal file
62
src/main/java/ru/bclib/blocks/EndSlabBlock.java
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.SlabBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.SlabType;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndSlabBlock extends SlabBlock implements BlockModelProvider {
|
||||||
|
private final Block parent;
|
||||||
|
|
||||||
|
public EndSlabBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source));
|
||||||
|
this.parent = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return getBlockModel(resourceLocation, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.BLOCK_SLAB, parentId.getPath(), blockId.getPath());
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
SlabType type = blockState.getValue(TYPE);
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + "_" + type);
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
if (type == SlabType.TOP) {
|
||||||
|
return ModelsHelper.createMultiVariant(modelId, BlockModelRotation.X180_Y0.getRotation(), true);
|
||||||
|
}
|
||||||
|
return ModelsHelper.createBlockSimple(modelId);
|
||||||
|
}
|
||||||
|
}
|
110
src/main/java/ru/bclib/blocks/EndStairsBlock.java
Normal file
110
src/main/java/ru/bclib/blocks/EndStairsBlock.java
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.StairBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.Half;
|
||||||
|
import net.minecraft.world.level.block.state.properties.StairsShape;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndStairsBlock extends StairBlock implements BlockModelProvider {
|
||||||
|
|
||||||
|
private final Block parent;
|
||||||
|
|
||||||
|
public EndStairsBlock(Block source) {
|
||||||
|
super(source.defaultBlockState(), FabricBlockSettings.copyOf(source));
|
||||||
|
this.parent = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return getBlockModel(resourceLocation, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
Optional<String> pattern = Optional.empty();
|
||||||
|
switch (blockState.getValue(SHAPE)) {
|
||||||
|
case STRAIGHT:
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_STAIR, parentId.getPath(), blockId.getPath());
|
||||||
|
break;
|
||||||
|
case INNER_LEFT:
|
||||||
|
case INNER_RIGHT:
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_STAIR_INNER, parentId.getPath(), blockId.getPath());
|
||||||
|
break;
|
||||||
|
case OUTER_LEFT:
|
||||||
|
case OUTER_RIGHT:
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_STAIR_OUTER, parentId.getPath(), blockId.getPath());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
String state = "";
|
||||||
|
StairsShape shape = blockState.getValue(SHAPE);
|
||||||
|
switch (shape) {
|
||||||
|
case INNER_LEFT:
|
||||||
|
case INNER_RIGHT:
|
||||||
|
state = "_inner"; break;
|
||||||
|
case OUTER_LEFT:
|
||||||
|
case OUTER_RIGHT:
|
||||||
|
default:
|
||||||
|
state = "_outer"; break;
|
||||||
|
}
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(), "block/" + stateId.getPath() + state);
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
|
||||||
|
boolean isTop = blockState.getValue(HALF) == Half.TOP;
|
||||||
|
boolean isLeft = shape == StairsShape.INNER_LEFT ||
|
||||||
|
shape == StairsShape.OUTER_LEFT;
|
||||||
|
boolean isRight = shape == StairsShape.INNER_RIGHT ||
|
||||||
|
shape == StairsShape.OUTER_RIGHT;
|
||||||
|
int y = 0;
|
||||||
|
int x = isTop ? 180 : 0;
|
||||||
|
switch (blockState.getValue(FACING)) {
|
||||||
|
case NORTH:
|
||||||
|
if (isTop && !isRight) y = 270;
|
||||||
|
else if (!isTop) y = isLeft ? 180 : 270;
|
||||||
|
break;
|
||||||
|
case EAST:
|
||||||
|
if (isTop && isRight) y = 90;
|
||||||
|
else if (!isTop && isLeft) y = 270;
|
||||||
|
break;
|
||||||
|
case SOUTH:
|
||||||
|
if (isTop) y = isRight ? 180 : 90;
|
||||||
|
else if (!isLeft) y = 90;
|
||||||
|
break;
|
||||||
|
case WEST:
|
||||||
|
default:
|
||||||
|
y = (isTop && isRight) ? 270 : (!isTop && isLeft) ? 90 : 180;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BlockModelRotation rotation = BlockModelRotation.by(x, y);
|
||||||
|
return ModelsHelper.createMultiVariant(modelId, rotation.getRotation(), true);
|
||||||
|
}
|
||||||
|
}
|
18
src/main/java/ru/bclib/blocks/EndStoneButtonBlock.java
Normal file
18
src/main/java/ru/bclib/blocks/EndStoneButtonBlock.java
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
|
public class EndStoneButtonBlock extends EndButtonBlock {
|
||||||
|
|
||||||
|
public EndStoneButtonBlock(Block source) {
|
||||||
|
super(source, FabricBlockSettings.copyOf(source).noOcclusion(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent getSound(boolean clicked) {
|
||||||
|
return clicked ? SoundEvents.STONE_BUTTON_CLICK_ON : SoundEvents.STONE_BUTTON_CLICK_OFF;
|
||||||
|
}
|
||||||
|
}
|
9
src/main/java/ru/bclib/blocks/EndStonePlateBlock.java
Normal file
9
src/main/java/ru/bclib/blocks/EndStonePlateBlock.java
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
|
public class EndStonePlateBlock extends EndPlateBlock {
|
||||||
|
public EndStonePlateBlock(Block source) {
|
||||||
|
super(Sensitivity.MOBS, source);
|
||||||
|
}
|
||||||
|
}
|
87
src/main/java/ru/bclib/blocks/EndTrapdoorBlock.java
Normal file
87
src/main/java/ru/bclib/blocks/EndTrapdoorBlock.java
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.TrapDoorBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.Half;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
|
||||||
|
public class EndTrapdoorBlock extends TrapDoorBlock implements IRenderTypeable, BlockModelProvider {
|
||||||
|
public EndTrapdoorBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source).strength(3.0F, 3.0F).noOcclusion());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return getBlockModel(resourceLocation, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
String name = resourceLocation.getPath();
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.BLOCK_TRAPDOOR, new HashMap<String, String>() {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
{
|
||||||
|
put("%block%", name);
|
||||||
|
put("%texture%", name.replace("trapdoor", "door_side"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(), "block/" + stateId.getPath());
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
boolean isTop = blockState.getValue(HALF) == Half.TOP;
|
||||||
|
boolean isOpen = blockState.getValue(OPEN);
|
||||||
|
int y = 0;
|
||||||
|
int x = (isTop && isOpen) ? 270 : isTop ? 180 : isOpen ? 90 : 0;
|
||||||
|
switch (blockState.getValue(FACING)) {
|
||||||
|
case EAST:
|
||||||
|
y = (isTop && isOpen) ? 270 : 90;
|
||||||
|
break;
|
||||||
|
case NORTH:
|
||||||
|
if (isTop && isOpen) y = 180;
|
||||||
|
break;
|
||||||
|
case SOUTH:
|
||||||
|
y = (isTop && isOpen) ? 0 : 180;
|
||||||
|
break;
|
||||||
|
case WEST:
|
||||||
|
default:
|
||||||
|
y = (isTop && isOpen) ? 90 : 270;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BlockModelRotation rotation = BlockModelRotation.by(x, y);
|
||||||
|
return ModelsHelper.createMultiVariant(modelId, rotation.getRotation(), false);
|
||||||
|
}
|
||||||
|
}
|
95
src/main/java/ru/bclib/blocks/EndWallBlock.java
Normal file
95
src/main/java/ru/bclib/blocks/EndWallBlock.java
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.WallBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.WallSide;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndWallBlock extends WallBlock implements BlockModelProvider {
|
||||||
|
|
||||||
|
private final Block parent;
|
||||||
|
|
||||||
|
public EndWallBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copyOf(source).noOcclusion());
|
||||||
|
this.parent = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.ITEM_WALL, parentId.getPath(), blockId.getPath());
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) {
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
String path = blockId.getPath();
|
||||||
|
Optional<String> pattern = Optional.empty();
|
||||||
|
if (path.endsWith("_post")) {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_WALL_POST, parentId.getPath(), blockId.getPath());
|
||||||
|
}
|
||||||
|
if (path.endsWith("_side")) {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_WALL_SIDE, parentId.getPath(), blockId.getPath());
|
||||||
|
}
|
||||||
|
if (path.endsWith("_side_tall")) {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_WALL_SIDE_TALL, parentId.getPath(), blockId.getPath());
|
||||||
|
}
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
ResourceLocation postId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + "_post");
|
||||||
|
ResourceLocation sideId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + "_side");
|
||||||
|
ResourceLocation sideTallId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + "_side_tall");
|
||||||
|
registerBlockModel(postId, postId, blockState, modelCache);
|
||||||
|
registerBlockModel(sideId, sideId, blockState, modelCache);
|
||||||
|
registerBlockModel(sideTallId, sideTallId, blockState, modelCache);
|
||||||
|
|
||||||
|
ModelsHelper.MultiPartBuilder builder = ModelsHelper.MultiPartBuilder.create(stateDefinition);
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(NORTH_WALL) == WallSide.LOW).setUVLock(true).add();
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(EAST_WALL) == WallSide.LOW)
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y90.getRotation()).setUVLock(true).add();
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(SOUTH_WALL) == WallSide.LOW)
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y180.getRotation()).setUVLock(true).add();
|
||||||
|
builder.part(sideId).setCondition(state -> state.getValue(WEST_WALL) == WallSide.LOW)
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y270.getRotation()).setUVLock(true).add();
|
||||||
|
builder.part(sideTallId).setCondition(state -> state.getValue(NORTH_WALL) == WallSide.TALL).setUVLock(true).add();
|
||||||
|
builder.part(sideTallId).setCondition(state -> state.getValue(EAST_WALL) == WallSide.TALL)
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y90.getRotation()).setUVLock(true).add();
|
||||||
|
builder.part(sideTallId).setCondition(state -> state.getValue(SOUTH_WALL) == WallSide.TALL)
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y180.getRotation()).setUVLock(true).add();
|
||||||
|
builder.part(sideTallId).setCondition(state -> state.getValue(WEST_WALL) == WallSide.TALL)
|
||||||
|
.setTransformation(BlockModelRotation.X0_Y270.getRotation()).setUVLock(true).add();
|
||||||
|
builder.part(postId).setCondition(state -> state.getValue(UP)).add();
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
}
|
62
src/main/java/ru/bclib/blocks/EndWeightedPlateBlock.java
Normal file
62
src/main/java/ru/bclib/blocks/EndWeightedPlateBlock.java
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.WeightedPressurePlateBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class EndWeightedPlateBlock extends WeightedPressurePlateBlock implements BlockModelProvider {
|
||||||
|
private final Block parent;
|
||||||
|
|
||||||
|
public EndWeightedPlateBlock(Block source) {
|
||||||
|
super(15, FabricBlockSettings.copyOf(source).noCollission().noOcclusion().requiresCorrectToolForDrops().strength(0.5F));
|
||||||
|
this.parent = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return getBlockModel(resourceLocation, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
ResourceLocation parentId = Registry.BLOCK.getKey(parent);
|
||||||
|
Optional<String> pattern;
|
||||||
|
if (blockState.getValue(POWER) > 0) {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_PLATE_DOWN, parentId.getPath(), resourceLocation.getPath());
|
||||||
|
} else {
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_PLATE_UP, parentId.getPath(), resourceLocation.getPath());
|
||||||
|
}
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
String state = blockState.getValue(POWER) > 0 ? "_down" : "_up";
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + state);
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
return ModelsHelper.createBlockSimple(modelId);
|
||||||
|
}
|
||||||
|
}
|
18
src/main/java/ru/bclib/blocks/EndWoodenButtonBlock.java
Normal file
18
src/main/java/ru/bclib/blocks/EndWoodenButtonBlock.java
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
|
public class EndWoodenButtonBlock extends EndButtonBlock {
|
||||||
|
|
||||||
|
public EndWoodenButtonBlock(Block source) {
|
||||||
|
super(source, FabricBlockSettings.copyOf(source).strength(0.5F, 0.5F).noOcclusion(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent getSound(boolean clicked) {
|
||||||
|
return clicked ? SoundEvents.WOODEN_BUTTON_CLICK_ON : SoundEvents.WOODEN_BUTTON_CLICK_OFF;
|
||||||
|
}
|
||||||
|
}
|
9
src/main/java/ru/bclib/blocks/EndWoodenPlateBlock.java
Normal file
9
src/main/java/ru/bclib/blocks/EndWoodenPlateBlock.java
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
|
public class EndWoodenPlateBlock extends EndPlateBlock {
|
||||||
|
public EndWoodenPlateBlock(Block source) {
|
||||||
|
super(Sensitivity.EVERYTHING, source);
|
||||||
|
}
|
||||||
|
}
|
123
src/main/java/ru/bclib/blocks/FeatureSaplingBlock.java
Normal file
123
src/main/java/ru/bclib/blocks/FeatureSaplingBlock.java
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.SaplingBlock;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.betterend.client.models.BlockModelProvider;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
import ru.betterend.registry.EndTags;
|
||||||
|
|
||||||
|
public abstract class FeatureSaplingBlock extends SaplingBlock implements IRenderTypeable, BlockModelProvider {
|
||||||
|
private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12);
|
||||||
|
|
||||||
|
public FeatureSaplingBlock() {
|
||||||
|
super(null, FabricBlockSettings.of(Material.PLANT)
|
||||||
|
.breakByHand(true)
|
||||||
|
.collidable(false)
|
||||||
|
.instabreak()
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.randomTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
public FeatureSaplingBlock(int light) {
|
||||||
|
super(null, FabricBlockSettings.of(Material.PLANT)
|
||||||
|
.breakByHand(true)
|
||||||
|
.collidable(false)
|
||||||
|
.luminance(light)
|
||||||
|
.instabreak()
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.randomTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Feature<?> getFeature();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Collections.singletonList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
return SHAPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
return world.getBlockState(pos.below()).is(EndTags.END_GROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
if (!canSurvive(state, world, pos))
|
||||||
|
return Blocks.AIR.defaultBlockState();
|
||||||
|
else
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
return random.nextInt(16) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void advanceTree(ServerLevel world, BlockPos pos, BlockState blockState, Random random) {
|
||||||
|
getFeature().place(world, world.getChunkSource().getGenerator(), random, pos, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||||
|
this.tick(state, world, pos, random);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||||
|
super.tick(state, world, pos, random);
|
||||||
|
if (isBonemealSuccess(world, random, pos, state)) {
|
||||||
|
performBonemeal(world, random, pos, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||||
|
return ModelsHelper.createBlockItem(resourceLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.BLOCK_CROSS, resourceLocation.getPath());
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
}
|
38
src/main/java/ru/bclib/blocks/SimpleLeavesBlock.java
Normal file
38
src/main/java/ru/bclib/blocks/SimpleLeavesBlock.java
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import net.minecraft.world.level.material.MaterialColor;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
|
||||||
|
public class SimpleLeavesBlock extends BlockBaseNotFull implements IRenderTypeable {
|
||||||
|
public SimpleLeavesBlock(MaterialColor color) {
|
||||||
|
super(FabricBlockSettings.of(Material.LEAVES)
|
||||||
|
.strength(0.2F)
|
||||||
|
.materialColor(color)
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.noOcclusion()
|
||||||
|
.isValidSpawn((state, world, pos, type) -> false)
|
||||||
|
.isSuffocating((state, world, pos) -> false)
|
||||||
|
.isViewBlocking((state, world, pos) -> false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleLeavesBlock(MaterialColor color, int light) {
|
||||||
|
super(FabricBlockSettings.of(Material.LEAVES)
|
||||||
|
.luminance(light)
|
||||||
|
.materialColor(color)
|
||||||
|
.strength(0.2F)
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.noOcclusion()
|
||||||
|
.isValidSpawn((state, world, pos, type) -> false)
|
||||||
|
.isSuffocating((state, world, pos) -> false)
|
||||||
|
.isViewBlocking((state, world, pos) -> false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
}
|
247
src/main/java/ru/bclib/blocks/StalactiteBlock.java
Normal file
247
src/main/java/ru/bclib/blocks/StalactiteBlock.java
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.BlockPos.MutableBlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.LiquidBlockContainer;
|
||||||
|
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||||
|
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.level.material.Fluids;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.bclib.interfaces.IRenderTypeable;
|
||||||
|
import ru.betterend.blocks.BlockProperties;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
|
||||||
|
public class StalactiteBlock extends BaseBlockNotFull implements SimpleWaterloggedBlock, LiquidBlockContainer, IRenderTypeable {
|
||||||
|
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
|
||||||
|
public static final BooleanProperty IS_FLOOR = BlockProperties.IS_FLOOR;
|
||||||
|
public static final IntegerProperty SIZE = BlockProperties.SIZE;
|
||||||
|
private static final VoxelShape[] SHAPES;
|
||||||
|
|
||||||
|
public StalactiteBlock(Block source) {
|
||||||
|
super(FabricBlockSettings.copy(source).noOcclusion());
|
||||||
|
this.registerDefaultState(getStateDefinition().any().setValue(SIZE, 0).setValue(IS_FLOOR, true).setValue(WATERLOGGED, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> stateManager) {
|
||||||
|
stateManager.add(WATERLOGGED, IS_FLOOR, SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
return SHAPES[state.getValue(SIZE)];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
|
||||||
|
LevelReader world = ctx.getLevel();
|
||||||
|
BlockPos pos = ctx.getClickedPos();
|
||||||
|
Direction dir = ctx.getClickedFace();
|
||||||
|
boolean water = world.getFluidState(pos).getType() == Fluids.WATER;
|
||||||
|
|
||||||
|
if (dir == Direction.DOWN) {
|
||||||
|
if (isThis(world, pos.above()) || canSupportCenter(world, pos.above(), Direction.DOWN)) {
|
||||||
|
return defaultBlockState().setValue(IS_FLOOR, false).setValue(WATERLOGGED, water);
|
||||||
|
}
|
||||||
|
else if (isThis(world, pos.below()) || canSupportCenter(world, pos.below(), Direction.UP)) {
|
||||||
|
return defaultBlockState().setValue(IS_FLOOR, true).setValue(WATERLOGGED, water);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (isThis(world, pos.below()) || canSupportCenter(world, pos.below(), Direction.UP)) {
|
||||||
|
return defaultBlockState().setValue(IS_FLOOR, true).setValue(WATERLOGGED, water);
|
||||||
|
}
|
||||||
|
else if (isThis(world, pos.above()) || canSupportCenter(world, pos.above(), Direction.DOWN)) {
|
||||||
|
return defaultBlockState().setValue(IS_FLOOR, false).setValue(WATERLOGGED, water);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) {
|
||||||
|
boolean hasUp = isThis(world, pos.above());
|
||||||
|
boolean hasDown = isThis(world, pos.below());
|
||||||
|
MutableBlockPos mut = new MutableBlockPos();
|
||||||
|
if (hasUp && hasDown) {
|
||||||
|
boolean floor = state.getValue(IS_FLOOR);
|
||||||
|
BlockPos second = floor ? pos.above() : pos.below();
|
||||||
|
BlockState bState = world.getBlockState(second);
|
||||||
|
world.setBlockAndUpdate(pos, state.setValue(SIZE, 1).setValue(IS_FLOOR, floor));
|
||||||
|
world.setBlockAndUpdate(second, bState.setValue(SIZE, 1).setValue(IS_FLOOR, !floor));
|
||||||
|
|
||||||
|
bState = state;
|
||||||
|
int startSize = floor ? 1 : 2;
|
||||||
|
mut.set(pos.getX(), pos.getY() + 1, pos.getZ());
|
||||||
|
for (int i = 0; i < 8 && isThis(bState); i++) {
|
||||||
|
world.setBlockAndUpdate(mut, bState.setValue(SIZE, startSize++).setValue(IS_FLOOR, false));
|
||||||
|
mut.setY(mut.getY() + 1);
|
||||||
|
bState = world.getBlockState(mut);
|
||||||
|
}
|
||||||
|
|
||||||
|
bState = state;
|
||||||
|
startSize = floor ? 2 : 1;
|
||||||
|
mut.set(pos.getX(), pos.getY() - 1, pos.getZ());
|
||||||
|
for (int i = 0; i < 8 && isThis(bState); i++) {
|
||||||
|
world.setBlockAndUpdate(mut, bState.setValue(SIZE, startSize++).setValue(IS_FLOOR, true));
|
||||||
|
mut.setY(mut.getY() - 1);
|
||||||
|
bState = world.getBlockState(mut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (hasDown) {
|
||||||
|
mut.setX(pos.getX());
|
||||||
|
mut.setZ(pos.getZ());
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
mut.setY(pos.getY() - i);
|
||||||
|
if (isThis(world, mut)) {
|
||||||
|
BlockState state2 = world.getBlockState(mut);
|
||||||
|
int size = state2.getValue(SIZE);
|
||||||
|
if (size < i) {
|
||||||
|
world.setBlockAndUpdate(mut, state2.setValue(SIZE, i).setValue(IS_FLOOR, true));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (hasUp) {
|
||||||
|
mut.setX(pos.getX());
|
||||||
|
mut.setZ(pos.getZ());
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
mut.setY(pos.getY() + i);
|
||||||
|
if (isThis(world, mut)) {
|
||||||
|
BlockState state2 = world.getBlockState(mut);
|
||||||
|
int size = state2.getValue(SIZE);
|
||||||
|
if (size < i) {
|
||||||
|
world.setBlockAndUpdate(mut, state2.setValue(SIZE, i).setValue(IS_FLOOR, false));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isThis(LevelReader world, BlockPos pos) {
|
||||||
|
return isThis(world.getBlockState(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isThis(BlockState state) {
|
||||||
|
return state.getBlock() instanceof StalactiteBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
if (!canSurvive(state, world, pos)) {
|
||||||
|
return Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
int size = state.getValue(SIZE);
|
||||||
|
return checkUp(world, pos, size) || checkDown(world, pos, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkUp(BlockGetter world, BlockPos pos, int size) {
|
||||||
|
BlockPos p = pos.above();
|
||||||
|
BlockState state = world.getBlockState(p);
|
||||||
|
return (isThis(state) && state.getValue(SIZE) >= size) || state.isCollisionShapeFullBlock(world, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkDown(BlockGetter world, BlockPos pos, int size) {
|
||||||
|
BlockPos p = pos.below();
|
||||||
|
BlockState state = world.getBlockState(p);
|
||||||
|
return (isThis(state) && state.getValue(SIZE) >= size) || state.isCollisionShapeFullBlock(world, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
Optional<String> pattern = Patterns.createJson(Patterns.BLOCK_CROSS_SHADED, resourceLocation.getPath());
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
BlockModelRotation rotation = blockState.getValue(IS_FLOOR) ? BlockModelRotation.X0_Y0 : BlockModelRotation.X180_Y0;
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
stateId.getPath() + "_" + blockState.getValue(SIZE));
|
||||||
|
registerBlockModel(modelId, modelId, blockState, modelCache);
|
||||||
|
return ModelsHelper.createMultiVariant(modelId, rotation.getRotation(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlaceLiquid(BlockGetter world, BlockPos pos, BlockState state, Fluid fluid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean placeLiquid(LevelAccessor world, BlockPos pos, BlockState state, FluidState fluidState) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidState getFluidState(BlockState state) {
|
||||||
|
return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : Fluids.EMPTY.defaultFluidState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
float end = 2F / 8F;
|
||||||
|
float start = 5F / 8F;
|
||||||
|
SHAPES = new VoxelShape[8];
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
int side = Mth.floor(Mth.lerp(i / 7F, start, end) * 8F + 0.5F);
|
||||||
|
SHAPES[i] = Block.box(side, 0, side, 16 - side, 16, 16 - side);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
src/main/java/ru/bclib/blocks/StrippableBarkBlock.java
Normal file
41
src/main/java/ru/bclib/blocks/StrippableBarkBlock.java
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.RotatedPillarBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.material.MaterialColor;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
|
||||||
|
public class StrippableBarkBlock extends BarkBlock {
|
||||||
|
private final Block striped;
|
||||||
|
|
||||||
|
public StrippableBarkBlock(MaterialColor color, Block striped) {
|
||||||
|
super(FabricBlockSettings.copyOf(striped).materialColor(color));
|
||||||
|
this.striped = striped;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
|
if (player.getMainHandItem().getItem().is(FabricToolTags.AXES)) {
|
||||||
|
world.playSound(player, pos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||||
|
if (!world.isClientSide) {
|
||||||
|
world.setBlock(pos, striped.defaultBlockState().setValue(RotatedPillarBlock.AXIS, state.getValue(RotatedPillarBlock.AXIS)), 11);
|
||||||
|
if (!player.isCreative()) {
|
||||||
|
player.getMainHandItem().hurt(1, world.random, (ServerPlayer) player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
}
|
154
src/main/java/ru/bclib/blocks/TripleTerrainBlock.java
Normal file
154
src/main/java/ru/bclib/blocks/TripleTerrainBlock.java
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||||
|
import net.minecraft.client.renderer.block.model.MultiVariant;
|
||||||
|
import net.minecraft.client.renderer.block.model.Variant;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.UnbakedModel;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||||
|
import net.minecraft.world.level.material.MaterialColor;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import ru.betterend.blocks.BlockProperties;
|
||||||
|
import ru.betterend.blocks.BlockProperties.TripleShape;
|
||||||
|
import ru.betterend.client.models.ModelsHelper;
|
||||||
|
import ru.betterend.client.models.Patterns;
|
||||||
|
|
||||||
|
public class TripleTerrainBlock extends BaseTerrainBlock {
|
||||||
|
public static final EnumProperty<TripleShape> SHAPE = BlockProperties.TRIPLE_SHAPE;
|
||||||
|
|
||||||
|
public TripleTerrainBlock(MaterialColor color) {
|
||||||
|
super(color);
|
||||||
|
this.registerDefaultState(this.defaultBlockState().setValue(SHAPE, TripleShape.BOTTOM));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> stateManager) {
|
||||||
|
stateManager.add(SHAPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
|
||||||
|
Direction dir = ctx.getClickedFace();
|
||||||
|
TripleShape shape = dir == Direction.UP ? TripleShape.BOTTOM : dir == Direction.DOWN ? TripleShape.TOP : TripleShape.MIDDLE;
|
||||||
|
return this.defaultBlockState().setValue(SHAPE, shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
|
TripleShape shape = state.getValue(SHAPE);
|
||||||
|
if (shape == TripleShape.BOTTOM) {
|
||||||
|
return super.use(state, world, pos, player, hand, hit);
|
||||||
|
}
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||||
|
TripleShape shape = state.getValue(SHAPE);
|
||||||
|
if (shape == TripleShape.BOTTOM) {
|
||||||
|
super.randomTick(state, world, pos, random);
|
||||||
|
} else if (random.nextInt(16) == 0) {
|
||||||
|
boolean bottom = canStayBottom(world, pos);
|
||||||
|
if (shape == TripleShape.TOP) {
|
||||||
|
if (!bottom) {
|
||||||
|
world.setBlockAndUpdate(pos, Blocks.END_STONE.defaultBlockState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
boolean top = canStay(state, world, pos) || isMiddle(world.getBlockState(pos.above()));
|
||||||
|
if (!top && !bottom) {
|
||||||
|
world.setBlockAndUpdate(pos, Blocks.END_STONE.defaultBlockState());
|
||||||
|
} else if (top && !bottom) {
|
||||||
|
world.setBlockAndUpdate(pos, state.setValue(SHAPE, TripleShape.BOTTOM));
|
||||||
|
} else if (!top) {
|
||||||
|
world.setBlockAndUpdate(pos, state.setValue(SHAPE, TripleShape.TOP));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean canStayBottom(LevelReader world, BlockPos pos) {
|
||||||
|
BlockPos blockPos = pos.below();
|
||||||
|
BlockState blockState = world.getBlockState(blockPos);
|
||||||
|
if (isMiddle(blockState)) {
|
||||||
|
return true;
|
||||||
|
} else if (blockState.getFluidState().getAmount() == 8) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return !blockState.isFaceSturdy(world, blockPos, Direction.UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockModel getItemModel(ResourceLocation blockId) {
|
||||||
|
return getBlockModel(blockId, defaultBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||||
|
String name = resourceLocation.getPath();
|
||||||
|
Optional<String> pattern;
|
||||||
|
if (isMiddle(blockState)) {
|
||||||
|
pattern = Patterns.createBlockSimple(name + "_top");
|
||||||
|
} else {
|
||||||
|
Map<String, String> textures = Maps.newHashMap();
|
||||||
|
textures.put("%top%", "betterend:block/" + name + "_top");
|
||||||
|
textures.put("%side%", "betterend:block/" + name + "_side");
|
||||||
|
textures.put("%bottom%", "minecraft:block/end_stone");
|
||||||
|
pattern = Patterns.createJson(Patterns.BLOCK_TOP_SIDE_BOTTOM, textures);
|
||||||
|
}
|
||||||
|
return ModelsHelper.fromPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map<ResourceLocation, UnbakedModel> modelCache) {
|
||||||
|
boolean isMiddle = isMiddle(blockState);
|
||||||
|
String middle = isMiddle ? "_middle" : "";
|
||||||
|
ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(),
|
||||||
|
"block/" + stateId.getPath() + middle);
|
||||||
|
registerBlockModel(stateId, modelId, blockState, modelCache);
|
||||||
|
if (isMiddle) {
|
||||||
|
List<Variant> variants = Lists.newArrayList();
|
||||||
|
for (BlockModelRotation rotation : BlockModelRotation.values()) {
|
||||||
|
variants.add(new Variant(modelId, rotation.getRotation(), false, 1));
|
||||||
|
}
|
||||||
|
return new MultiVariant(variants);
|
||||||
|
} else if (blockState.getValue(SHAPE) == TripleShape.TOP) {
|
||||||
|
return new MultiVariant(Lists.newArrayList(
|
||||||
|
new Variant(modelId, BlockModelRotation.X180_Y0.getRotation(), false, 1),
|
||||||
|
new Variant(modelId, BlockModelRotation.X180_Y90.getRotation(), false, 1),
|
||||||
|
new Variant(modelId, BlockModelRotation.X180_Y180.getRotation(), false, 1),
|
||||||
|
new Variant(modelId, BlockModelRotation.X180_Y270.getRotation(), false, 1)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return ModelsHelper.createRandomTopModel(modelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isMiddle(BlockState blockState) {
|
||||||
|
return blockState.is(this) && blockState.getValue(SHAPE) == TripleShape.MIDDLE;
|
||||||
|
}
|
||||||
|
}
|
145
src/main/java/ru/bclib/blocks/UnderwaterPlantBlock.java
Normal file
145
src/main/java/ru/bclib/blocks/UnderwaterPlantBlock.java
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.BonemealableBlock;
|
||||||
|
import net.minecraft.world.level.block.LiquidBlockContainer;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.level.material.Fluids;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
import ru.betterend.registry.EndBlocks;
|
||||||
|
import ru.betterend.registry.EndTags;
|
||||||
|
|
||||||
|
public class UnderwaterPlantBlock extends BlockBaseNotFull implements IRenderTypeable, BonemealableBlock, LiquidBlockContainer {
|
||||||
|
private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12);
|
||||||
|
|
||||||
|
public UnderwaterPlantBlock() {
|
||||||
|
super(FabricBlockSettings.of(Material.WATER_PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.sound(SoundType.WET_GRASS)
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnderwaterPlantBlock(int light) {
|
||||||
|
super(FabricBlockSettings.of(Material.WATER_PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.luminance(light)
|
||||||
|
.sound(SoundType.WET_GRASS)
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnderwaterPlantBlock(Properties settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
Vec3 vec3d = state.getOffset(view, pos);
|
||||||
|
return SHAPE.move(vec3d.x, vec3d.y, vec3d.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockBehaviour.OffsetType getOffsetType() {
|
||||||
|
return BlockBehaviour.OffsetType.XZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
BlockState down = world.getBlockState(pos.below());
|
||||||
|
state = world.getBlockState(pos);
|
||||||
|
return isTerrain(down) && state.getFluidState().getType().equals(Fluids.WATER.getSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isTerrain(BlockState state) {
|
||||||
|
return state.is(EndTags.END_GROUND) || state.getBlock() == EndBlocks.ENDSTONE_DUST;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
if (!canSurvive(state, world, pos)) {
|
||||||
|
world.destroyBlock(pos, true);
|
||||||
|
return Blocks.WATER.defaultBlockState();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||||
|
if (tool != null && tool.getItem().is(FabricToolTags.SHEARS) || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0) {
|
||||||
|
return Lists.newArrayList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Lists.newArrayList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidBonemealTarget(BlockGetter world, BlockPos pos, BlockState state, boolean isClient) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performBonemeal(ServerLevel world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
ItemEntity item = new ItemEntity(world, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, new ItemStack(this));
|
||||||
|
world.addFreshEntity(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlaceLiquid(BlockGetter world, BlockPos pos, BlockState state, Fluid fluid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean placeLiquid(LevelAccessor world, BlockPos pos, BlockState state, FluidState fluidState) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidState getFluidState(BlockState state) {
|
||||||
|
return Fluids.WATER.getSource(false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.WorldGenLevel;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import ru.betterend.blocks.BlockProperties;
|
||||||
|
|
||||||
|
public abstract class UnderwaterPlantWithAgeBlock extends UnderwaterPlantBlock {
|
||||||
|
public static final IntegerProperty AGE = BlockProperties.AGE;
|
||||||
|
|
||||||
|
public UnderwaterPlantWithAgeBlock() {
|
||||||
|
super(FabricBlockSettings.of(Material.WATER_PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.sound(SoundType.WET_GRASS)
|
||||||
|
.randomTicks()
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> stateManager) {
|
||||||
|
stateManager.add(AGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void grow(WorldGenLevel world, Random random, BlockPos pos);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performBonemeal(ServerLevel world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
if (random.nextInt(4) == 0) {
|
||||||
|
int age = state.getValue(AGE);
|
||||||
|
if (age < 3) {
|
||||||
|
world.setBlockAndUpdate(pos, state.setValue(AGE, age + 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
grow(world, random, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||||
|
super.tick(state, world, pos, random);
|
||||||
|
if (isBonemealSuccess(world, random, pos, state)) {
|
||||||
|
performBonemeal(world, random, pos, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
src/main/java/ru/bclib/blocks/UpDownPlantBlock.java
Normal file
95
src/main/java/ru/bclib/blocks/UpDownPlantBlock.java
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
import ru.betterend.registry.EndTags;
|
||||||
|
|
||||||
|
public class UpDownPlantBlock extends BlockBaseNotFull implements IRenderTypeable {
|
||||||
|
private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 16, 12);
|
||||||
|
|
||||||
|
public UpDownPlantBlock() {
|
||||||
|
super(FabricBlockSettings.of(Material.PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
return SHAPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
BlockState down = world.getBlockState(pos.below());
|
||||||
|
BlockState up = world.getBlockState(pos.above());
|
||||||
|
return (isTerrain(down) || down.getBlock() == this) && (isSupport(up, world, pos) || up.getBlock() == this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isTerrain(BlockState state) {
|
||||||
|
return state.is(EndTags.END_GROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isSupport(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
return canSupportCenter(world, pos.above(), Direction.UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
if (!canSurvive(state, world, pos)) {
|
||||||
|
return Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||||
|
if (tool != null && tool.getItem().is(FabricToolTags.SHEARS) || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0) {
|
||||||
|
return Lists.newArrayList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Lists.newArrayList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, BlockEntity blockEntity, ItemStack stack) {
|
||||||
|
super.playerDestroy(world, player, pos, state, blockEntity, stack);
|
||||||
|
world.neighborChanged(pos, Blocks.AIR, pos.below());
|
||||||
|
}
|
||||||
|
}
|
147
src/main/java/ru/bclib/blocks/VineBlock.java
Normal file
147
src/main/java/ru/bclib/blocks/VineBlock.java
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.tags.BlockTags;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.BonemealableBlock;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import ru.betterend.blocks.BlockProperties;
|
||||||
|
import ru.betterend.blocks.BlockProperties.TripleShape;
|
||||||
|
import ru.betterend.client.render.ERenderLayer;
|
||||||
|
import ru.betterend.interfaces.IRenderTypeable;
|
||||||
|
import ru.betterend.util.BlocksHelper;
|
||||||
|
|
||||||
|
public class VineBlock extends BlockBaseNotFull implements IRenderTypeable, BonemealableBlock {
|
||||||
|
public static final EnumProperty<TripleShape> SHAPE = BlockProperties.TRIPLE_SHAPE;
|
||||||
|
private static final VoxelShape VOXEL_SHAPE = Block.box(2, 0, 2, 14, 16, 14);
|
||||||
|
|
||||||
|
public VineBlock() {
|
||||||
|
this(0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VineBlock(int light) {
|
||||||
|
this(light, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VineBlock(int light, boolean bottomOnly) {
|
||||||
|
super(FabricBlockSettings.of(Material.PLANT)
|
||||||
|
.breakByTool(FabricToolTags.SHEARS)
|
||||||
|
.breakByHand(true)
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.lightLevel((state) -> bottomOnly ? state.getValue(SHAPE) == TripleShape.BOTTOM ? light : 0 : light)
|
||||||
|
.noCollission());
|
||||||
|
this.registerDefaultState(this.stateDefinition.any().setValue(SHAPE, TripleShape.BOTTOM));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> stateManager) {
|
||||||
|
stateManager.add(SHAPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||||
|
Vec3 vec3d = state.getOffset(view, pos);
|
||||||
|
return VOXEL_SHAPE.move(vec3d.x, vec3d.y, vec3d.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockBehaviour.OffsetType getOffsetType() {
|
||||||
|
return BlockBehaviour.OffsetType.XZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canGenerate(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
return isSupport(state, world, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
return isSupport(state, world, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isSupport(BlockState state, LevelReader world, BlockPos pos) {
|
||||||
|
BlockState up = world.getBlockState(pos.above());
|
||||||
|
return up.is(this) || up.is(BlockTags.LEAVES) || canSupportCenter(world, pos.above(), Direction.DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
if (!canSurvive(state, world, pos)) {
|
||||||
|
return Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (world.getBlockState(pos.below()).getBlock() != this)
|
||||||
|
return state.setValue(SHAPE, TripleShape.BOTTOM);
|
||||||
|
else if (world.getBlockState(pos.above()).getBlock() != this)
|
||||||
|
return state.setValue(SHAPE, TripleShape.TOP);
|
||||||
|
return state.setValue(SHAPE, TripleShape.MIDDLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||||
|
if (tool != null && tool.getItem().is(FabricToolTags.SHEARS) || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0) {
|
||||||
|
return Lists.newArrayList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Lists.newArrayList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ERenderLayer getRenderLayer() {
|
||||||
|
return ERenderLayer.CUTOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidBonemealTarget(BlockGetter world, BlockPos pos, BlockState state, boolean isClient) {
|
||||||
|
while (world.getBlockState(pos).getBlock() == this) {
|
||||||
|
pos = pos.below();
|
||||||
|
}
|
||||||
|
return world.getBlockState(pos).isAir();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
while (world.getBlockState(pos).getBlock() == this) {
|
||||||
|
pos = pos.below();
|
||||||
|
}
|
||||||
|
return world.isEmptyBlock(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performBonemeal(ServerLevel world, Random random, BlockPos pos, BlockState state) {
|
||||||
|
while (world.getBlockState(pos).getBlock() == this) {
|
||||||
|
pos = pos.below();
|
||||||
|
}
|
||||||
|
world.setBlockAndUpdate(pos, defaultBlockState());
|
||||||
|
BlocksHelper.setWithoutUpdate(world, pos, defaultBlockState());
|
||||||
|
}
|
||||||
|
}
|
39
src/main/java/ru/bclib/blocks/WallMushroomBlock.java
Normal file
39
src/main/java/ru/bclib/blocks/WallMushroomBlock.java
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package ru.bclib.blocks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||||
|
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.material.Material;
|
||||||
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
|
|
||||||
|
public class WallMushroomBlock extends BaseWallPlantBlock {
|
||||||
|
public WallMushroomBlock(int light) {
|
||||||
|
super(FabricBlockSettings.of(Material.PLANT)
|
||||||
|
.breakByTool(FabricToolTags.AXES)
|
||||||
|
.breakByHand(true)
|
||||||
|
.luminance(light)
|
||||||
|
.hardness(0.2F)
|
||||||
|
.sound(SoundType.GRASS)
|
||||||
|
.sound(SoundType.WOOD)
|
||||||
|
.noCollission());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||||
|
return Lists.newArrayList(new ItemStack(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSupport(LevelReader world, BlockPos pos, BlockState blockState, Direction direction) {
|
||||||
|
return blockState.getMaterial().isSolid() && blockState.isFaceSturdy(world, pos, direction);
|
||||||
|
}
|
||||||
|
}
|
6
src/main/java/ru/bclib/client/render/ERenderLayer.java
Normal file
6
src/main/java/ru/bclib/client/render/ERenderLayer.java
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.bclib.client.render;
|
||||||
|
|
||||||
|
public enum ERenderLayer {
|
||||||
|
CUTOUT,
|
||||||
|
TRANSLUCENT;
|
||||||
|
}
|
13
src/main/java/ru/bclib/client/sound/BlockSounds.java
Normal file
13
src/main/java/ru/bclib/client/sound/BlockSounds.java
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package ru.bclib.client.sound;
|
||||||
|
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.world.level.block.SoundType;
|
||||||
|
|
||||||
|
public class BlockSounds {
|
||||||
|
public static final SoundType TERRAIN_SOUND = new SoundType(1.0F, 1.0F,
|
||||||
|
SoundEvents.STONE_BREAK,
|
||||||
|
SoundEvents.WART_BLOCK_STEP,
|
||||||
|
SoundEvents.STONE_PLACE,
|
||||||
|
SoundEvents.STONE_HIT,
|
||||||
|
SoundEvents.STONE_FALL);
|
||||||
|
}
|
8
src/main/java/ru/bclib/interfaces/IRenderTypeable.java
Normal file
8
src/main/java/ru/bclib/interfaces/IRenderTypeable.java
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package ru.bclib.interfaces;
|
||||||
|
|
||||||
|
import ru.bclib.client.render.ERenderLayer;
|
||||||
|
|
||||||
|
public interface IRenderTypeable
|
||||||
|
{
|
||||||
|
public ERenderLayer getRenderLayer();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue