diff --git a/src/main/java/ru/betterend/blocks/basis/BlockUnderwaterPlant.java b/src/main/java/ru/betterend/blocks/basis/BlockUnderwaterPlant.java new file mode 100644 index 00000000..ff1c1721 --- /dev/null +++ b/src/main/java/ru/betterend/blocks/basis/BlockUnderwaterPlant.java @@ -0,0 +1,139 @@ +package ru.betterend.blocks.basis; + +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.block.AbstractBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.Fertilizable; +import net.minecraft.block.FluidFillable; +import net.minecraft.block.Material; +import net.minecraft.block.ShapeContext; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.enchantment.Enchantments; +import net.minecraft.entity.ItemEntity; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.FluidState; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.ItemStack; +import net.minecraft.loot.context.LootContext; +import net.minecraft.loot.context.LootContextParameters; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.BlockSoundGroup; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import net.minecraft.world.WorldView; +import ru.betterend.client.ERenderLayer; +import ru.betterend.client.IRenderTypeable; +import ru.betterend.registry.BlockRegistry; +import ru.betterend.registry.BlockTagRegistry; + +public class BlockUnderwaterPlant extends BlockBaseNotFull implements IRenderTypeable, Fertilizable, FluidFillable { + private static final VoxelShape SHAPE = Block.createCuboidShape(4, 0, 4, 12, 14, 12); + + public BlockUnderwaterPlant() { + super(FabricBlockSettings.of(Material.UNDERWATER_PLANT) + .breakByTool(FabricToolTags.SHEARS) + .sounds(BlockSoundGroup.WET_GRASS) + .breakByHand(true) + .noCollision()); + } + + public BlockUnderwaterPlant(int light) { + super(FabricBlockSettings.of(Material.UNDERWATER_PLANT) + .breakByTool(FabricToolTags.SHEARS) + .sounds(BlockSoundGroup.WET_GRASS) + .lightLevel(light) + .breakByHand(true) + .noCollision()); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ePos) { + Vec3d vec3d = state.getModelOffset(view, pos); + return SHAPE.offset(vec3d.x, vec3d.y, vec3d.z); + } + + @Override + public AbstractBlock.OffsetType getOffsetType() { + return AbstractBlock.OffsetType.XZ; + } + + @Override + public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) { + BlockState down = world.getBlockState(pos.down()); + return isTerrain(down); + } + + protected boolean isTerrain(BlockState state) { + return state.isIn(BlockTagRegistry.END_GROUND) || state.getBlock() == BlockRegistry.ENDSTONE_DUST; + } + + @Override + public BlockState getStateForNeighborUpdate(BlockState state, Direction facing, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) { + if (!canPlaceAt(state, world, pos)) { + return Blocks.AIR.getDefaultState(); + } + else { + return state; + } + } + + @Override + public List getDroppedStacks(BlockState state, LootContext.Builder builder) { + ItemStack tool = builder.get(LootContextParameters.TOOL); + if (tool != null && tool.getItem().isIn(FabricToolTags.SHEARS) || EnchantmentHelper.getLevel(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 isFertilizable(BlockView world, BlockPos pos, BlockState state, boolean isClient) { + return true; + } + + @Override + public boolean canGrow(World world, Random random, BlockPos pos, BlockState state) { + return true; + } + + @Override + public void grow(ServerWorld 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.spawnEntity(item); + } + + @Override + public boolean canFillWithFluid(BlockView world, BlockPos pos, BlockState state, Fluid fluid) { + return false; + } + + @Override + public boolean tryFillWithFluid(WorldAccess world, BlockPos pos, BlockState state, FluidState fluidState) { + return false; + } + + @Override + public FluidState getFluidState(BlockState state) { + return Fluids.WATER.getStill(false); + } +} diff --git a/src/main/java/ru/betterend/mixin/common/BoneMealItemMixin.java b/src/main/java/ru/betterend/mixin/common/BoneMealItemMixin.java new file mode 100644 index 00000000..caa3cac0 --- /dev/null +++ b/src/main/java/ru/betterend/mixin/common/BoneMealItemMixin.java @@ -0,0 +1,107 @@ +package ru.betterend.mixin.common; + +import java.util.Random; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.item.BoneMealItem; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.util.ActionResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockPos.Mutable; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import ru.betterend.registry.BlockRegistry; +import ru.betterend.registry.BlockTagRegistry; +import ru.betterend.util.BlocksHelper; + +@Mixin(BoneMealItem.class) +public class BoneMealItemMixin { + private static final Direction[] DIR = BlocksHelper.makeHorizontal(); + private static final Mutable POS = new Mutable(); + + @Inject(method = "useOnBlock", at = @At("HEAD"), cancellable = true) + private void onUse(ItemUsageContext context, CallbackInfoReturnable info) { + World world = context.getWorld(); + BlockPos blockPos = context.getBlockPos(); + if (!world.isClient) { + if (world.getBlockState(blockPos).isIn(BlockTagRegistry.END_GROUND)) { + boolean consume = false; + if (world.getBlockState(blockPos).getBlock() == Blocks.END_STONE) { + BlockState nylium = getNylium(world, blockPos); + if (nylium != null) { + BlocksHelper.setWithoutUpdate(world, blockPos, nylium); + consume = true; + } + } else { + consume = growGrass(world, blockPos); + } + if (consume) { + if (!context.getPlayer().isCreative()) + context.getStack().decrement(1); + world.syncWorldEvent(2005, blockPos, 0); + info.setReturnValue(ActionResult.SUCCESS); + info.cancel(); + } + } + } + } + + private boolean growGrass(World world, BlockPos pos) { + int y1 = pos.getY() + 3; + int y2 = pos.getY() - 3; + boolean result = false; + for (int i = 0; i < 64; i++) { + int x = (int) (pos.getX() + world.random.nextGaussian() * 2); + int z = (int) (pos.getZ() + world.random.nextGaussian() * 2); + POS.setX(x); + POS.setZ(z); + for (int y = y1; y >= y2; y--) { + POS.setY(y); + BlockPos down = POS.down(); + if (world.isAir(POS) && !world.isAir(down)) { + BlockState grass = getGrassState(world, down); + if (grass != null) { + BlocksHelper.setWithoutUpdate(world, POS, grass); + result = true; + } + break; + } + } + } + return result; + } + + private BlockState getGrassState(World world, BlockPos pos) { + BlockState state = world.getBlockState(pos); + Block block = state.getBlock(); + if (block == BlockRegistry.END_MOSS || block == BlockRegistry.END_MYCELIUM) + return world.random.nextBoolean() ? BlockRegistry.CREEPING_MOSS.getDefaultState() : BlockRegistry.UMBRELLA_MOSS.getDefaultState(); + return null; + } + + private void shuffle(Random random) { + for (int i = 0; i < 4; i++) { + int j = random.nextInt(4); + Direction d = DIR[i]; + DIR[i] = DIR[j]; + DIR[j] = d; + } + } + + private BlockState getNylium(World world, BlockPos pos) { + shuffle(world.random); + for (Direction dir : DIR) { + BlockState state = world.getBlockState(pos.offset(dir)); + if (BlocksHelper.isEndNylium(state)) + return state; + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/ru/betterend/registry/BlockRegistry.java b/src/main/java/ru/betterend/registry/BlockRegistry.java index 9c1b1273..f250e441 100644 --- a/src/main/java/ru/betterend/registry/BlockRegistry.java +++ b/src/main/java/ru/betterend/registry/BlockRegistry.java @@ -26,6 +26,7 @@ import ru.betterend.blocks.EndStoneSmelter; import ru.betterend.blocks.EnderBlock; import ru.betterend.blocks.TerminiteBlock; import ru.betterend.blocks.basis.BlockGlowingFur; +import ru.betterend.blocks.basis.BlockUnderwaterPlant; import ru.betterend.blocks.basis.BlockVine; import ru.betterend.blocks.complex.WoodenMaterial; import ru.betterend.tab.CreativeTab; @@ -58,6 +59,8 @@ public class BlockRegistry { public static final Block BLUE_VINE_LANTERN = registerBlock("blue_vine_lantern", new BlockBlueVineLantern()); public static final Block BLUE_VINE_FUR = registerBlock("blue_vine_fur", new BlockGlowingFur(BLUE_VINE_SEED, 3)); + public static final Block BUBBLE_CORAL = registerBlock("bubble_coral", new BlockUnderwaterPlant(12)); + // Vines // public static final Block DENSE_VINE = registerBlock("dense_vine", new BlockVine(15, true)); diff --git a/src/main/resources/assets/betterend/blockstates/bubble_coral.json b/src/main/resources/assets/betterend/blockstates/bubble_coral.json new file mode 100644 index 00000000..55b158b5 --- /dev/null +++ b/src/main/resources/assets/betterend/blockstates/bubble_coral.json @@ -0,0 +1,8 @@ +{ + "variants": { + "": [ + { "model": "betterend:block/bubble_coral" }, + { "model": "betterend:block/bubble_coral_2" } + ] + } +} diff --git a/src/main/resources/assets/betterend/models/block/bubble_coral.json b/src/main/resources/assets/betterend/models/block/bubble_coral.json new file mode 100644 index 00000000..36a1f954 --- /dev/null +++ b/src/main/resources/assets/betterend/models/block/bubble_coral.json @@ -0,0 +1,6 @@ +{ + "parent": "betterend:block/crop_block", + "textures": { + "texture": "betterend:block/bubble_coral" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/betterend/models/block/bubble_coral_2.json b/src/main/resources/assets/betterend/models/block/bubble_coral_2.json new file mode 100644 index 00000000..1e4483f1 --- /dev/null +++ b/src/main/resources/assets/betterend/models/block/bubble_coral_2.json @@ -0,0 +1,6 @@ +{ + "parent": "betterend:block/crop_block_inverted", + "textures": { + "texture": "betterend:block/bubble_coral" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/betterend/models/item/bubble_coral.json b/src/main/resources/assets/betterend/models/item/bubble_coral.json new file mode 100644 index 00000000..2c283b30 --- /dev/null +++ b/src/main/resources/assets/betterend/models/item/bubble_coral.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "betterend:block/bubble_coral" + } +} diff --git a/src/main/resources/assets/betterend/textures/block/bubble_coral.png b/src/main/resources/assets/betterend/textures/block/bubble_coral.png new file mode 100644 index 00000000..02175a2a Binary files /dev/null and b/src/main/resources/assets/betterend/textures/block/bubble_coral.png differ