diff --git a/common/src/main/java/com/craisinlord/antarchy/content/block/BigBushBlock.java b/common/src/main/java/com/craisinlord/antarchy/content/block/BigBushBlock.java new file mode 100644 index 00000000..a2ce8ee8 --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/content/block/BigBushBlock.java @@ -0,0 +1,255 @@ +package com.craisinlord.antarchy.content.block; + +import com.craisinlord.antarchy.Antarchy; +import com.mojang.serialization.MapCodec; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +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.BushBlock; +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.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Multiblock bush grown with bonemeal. The origin block (this one) carries the + * loot/age; the rest of the footprint is filled with invisible + * {@link BigBushPartBlock}s. + * + * age 0: single block (1x1x1) + * age 1: 2x2x2 footprint; FACING + FACING.getClockWise() pick the horizontal quadrant + * age 2: 3x3x3 footprint centered on the origin column + * + * Grown stages require a sturdy support block under every column of their + * footprint. Growing from 2x2 to 3x3 may relocate the origin to any of the four + * occupied columns to find room. + */ +public class BigBushBlock extends BushBlock implements BonemealableBlock { + public static final MapCodec CODEC = Block.simpleCodec(BigBushBlock::new); + + public static final IntegerProperty AGE = BlockStateProperties.AGE_2; + public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; + + private static final VoxelShape SMALL_SHAPE = Block.box(2.0, 0.0, 2.0, 14.0, 13.0, 14.0); + + public BigBushBlock(BlockBehaviour.Properties properties) { + super(properties); + this.registerDefaultState(this.stateDefinition.any() + .setValue(AGE, 0) + .setValue(FACING, Direction.EAST)); + } + + @Override + public MapCodec codec() { + return CODEC; + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(AGE, FACING); + } + + @Override + protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + return state.getValue(AGE) == 0 ? SMALL_SHAPE : Shapes.block(); + } + + /** All part positions belonging to a bush with the given origin state/pos (origin itself excluded). */ + public static List partPositions(BlockState state, BlockPos origin) { + List positions = new ArrayList<>(); + int age = state.getValue(AGE); + if (age == 1) { + Direction forward = state.getValue(FACING); + Direction side = forward.getClockWise(); + for (int dy = 0; dy <= 1; dy++) { + for (BlockPos column : new BlockPos[]{ + origin, origin.relative(forward), origin.relative(side), origin.relative(forward).relative(side)}) { + BlockPos pos = column.above(dy); + if (!pos.equals(origin)) { + positions.add(pos); + } + } + } + } else if (age == 2) { + for (int dx = -1; dx <= 1; dx++) { + for (int dy = 0; dy <= 2; dy++) { + for (int dz = -1; dz <= 1; dz++) { + if (dx == 0 && dy == 0 && dz == 0) { + continue; + } + positions.add(origin.offset(dx, dy, dz)); + } + } + } + } + return positions; + } + + /** Ground-level columns of the footprint; each needs a sturdy block below it. */ + public static List supportColumns(BlockState state, BlockPos origin) { + List columns = new ArrayList<>(); + int age = state.getValue(AGE); + if (age == 1) { + Direction forward = state.getValue(FACING); + Direction side = forward.getClockWise(); + columns.add(origin); + columns.add(origin.relative(forward)); + columns.add(origin.relative(side)); + columns.add(origin.relative(forward).relative(side)); + } else if (age == 2) { + for (int dx = -1; dx <= 1; dx++) { + for (int dz = -1; dz <= 1; dz++) { + columns.add(origin.offset(dx, 0, dz)); + } + } + } else { + columns.add(origin); + } + return columns; + } + + public static boolean hasFullSupport(BlockState state, LevelReader level, BlockPos origin) { + for (BlockPos column : supportColumns(state, origin)) { + BlockPos below = column.below(); + if (!level.getBlockState(below).isFaceSturdy(level, below, Direction.UP)) { + return false; + } + } + return true; + } + + @Override + protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) { + if (state.getValue(AGE) == 0) { + return super.canSurvive(state, level, pos); + } + return hasFullSupport(state, level, pos); + } + + private static Block partBlock() { + return BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "big_bush_part")); + } + + private record GrowthTarget(BlockPos origin, BlockState state) {} + + @Nullable + private GrowthTarget findGrowthTarget(LevelReader level, BlockPos pos, BlockState state, RandomSource random) { + int age = state.getValue(AGE); + if (age == 0) { + List facings = new ArrayList<>(Direction.Plane.HORIZONTAL.stream().toList()); + for (int i = facings.size() - 1; i > 0; i--) { + Direction swap = facings.set(random.nextInt(i + 1), facings.get(i)); + facings.set(i, swap); + } + for (Direction facing : facings) { + BlockState grown = state.setValue(AGE, 1).setValue(FACING, facing); + if (canGrowTo(level, pos, grown, Set.of(pos))) { + return new GrowthTarget(pos, grown); + } + } + return null; + } + if (age == 1) { + Direction forward = state.getValue(FACING); + Direction side = forward.getClockWise(); + Set owned = new HashSet<>(partPositions(state, pos)); + owned.add(pos); + BlockState grown = state.setValue(AGE, 2); + // Any of the four occupied columns can become the new center of the 3x3. + for (BlockPos candidate : new BlockPos[]{ + pos, pos.relative(forward).relative(side), pos.relative(forward), pos.relative(side)}) { + if (canGrowTo(level, candidate, grown, owned)) { + return new GrowthTarget(candidate, grown); + } + } + } + return null; + } + + private boolean canGrowTo(LevelReader level, BlockPos newOrigin, BlockState grownState, Set owned) { + if (!hasFullSupport(grownState, level, newOrigin)) { + return false; + } + List positions = new ArrayList<>(partPositions(grownState, newOrigin)); + positions.add(newOrigin); + for (BlockPos pos : positions) { + if (owned.contains(pos)) { + continue; + } + if (!level.getBlockState(pos).canBeReplaced()) { + return false; + } + } + return true; + } + + public static void placeBushBlocks(LevelAccessor level, BlockPos origin, BlockState grownState, int flags) { + level.setBlock(origin, grownState, flags); + Block part = partBlock(); + BlockPos capPos = grownState.getValue(AGE) == 2 ? origin.above(2) : null; + for (BlockPos pos : partPositions(grownState, origin)) { + level.setBlock(pos, part.defaultBlockState() + .setValue(BigBushPartBlock.CAP, pos.equals(capPos)), flags); + } + } + + private void placeStage(ServerLevel level, BlockPos origin, BlockState grownState) { + placeBushBlocks(level, origin, grownState, 3); + } + + @Override + protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { + if (!state.is(newState.getBlock())) { + for (BlockPos partPos : partPositions(state, pos)) { + if (level.getBlockState(partPos).getBlock() instanceof BigBushPartBlock) { + level.setBlock(partPos, Blocks.AIR.defaultBlockState(), 35); + } + } + } + super.onRemove(state, level, pos, newState, movedByPiston); + } + + @Override + public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) { + return state.getValue(AGE) < 2; + } + + @Override + public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) { + return findGrowthTarget(level, pos, state, random) != null; + } + + @Override + public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { + GrowthTarget target = findGrowthTarget(level, pos, state, random); + if (target == null) { + return; + } + if (!target.origin().equals(pos)) { + // Relocating the origin: removing it cascades and clears the old parts. + level.removeBlock(pos, false); + } + placeStage(level, target.origin(), target.state()); + } +} diff --git a/common/src/main/java/com/craisinlord/antarchy/content/block/BigBushPartBlock.java b/common/src/main/java/com/craisinlord/antarchy/content/block/BigBushPartBlock.java new file mode 100644 index 00000000..51ea6e3b --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/content/block/BigBushPartBlock.java @@ -0,0 +1,132 @@ +package com.craisinlord.antarchy.content.block; + +import com.mojang.serialization.MapCodec; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +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.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +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.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.Nullable; + +/** + * Invisible filler block for the grown {@link BigBushBlock} footprint. Breaking a + * part destroys the whole bush (drops come from the origin's loot table). The one + * part directly two above the origin of a stage-3 bush renders the top slice of + * the oversized cross model (CAP=true). + */ +public class BigBushPartBlock extends Block { + public static final MapCodec CODEC = Block.simpleCodec(BigBushPartBlock::new); + + public static final BooleanProperty CAP = BooleanProperty.create("cap"); + + public BigBushPartBlock(BlockBehaviour.Properties properties) { + super(properties); + this.registerDefaultState(this.stateDefinition.any().setValue(CAP, false)); + } + + @Override + public MapCodec codec() { + return CODEC; + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(CAP); + } + + @Override + protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + return Shapes.block(); + } + + /** Finds the origin bush this part belongs to, or null if orphaned. */ + @Nullable + public static BlockPos findOrigin(LevelReader level, BlockPos partPos) { + for (int dx = -1; dx <= 1; dx++) { + for (int dy = -2; dy <= 0; dy++) { + for (int dz = -1; dz <= 1; dz++) { + if (dx == 0 && dy == 0 && dz == 0) { + continue; + } + BlockPos candidate = partPos.offset(dx, dy, dz); + BlockState state = level.getBlockState(candidate); + if (state.getBlock() instanceof BigBushBlock + && BigBushBlock.partPositions(state, candidate).contains(partPos)) { + return candidate; + } + } + } + } + return null; + } + + @Override + public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state, Player player) { + if (!level.isClientSide) { + BlockPos origin = findOrigin(level, pos); + if (origin != null) { + BlockState originState = level.getBlockState(origin); + if (!player.getAbilities().instabuild) { + Block.dropResources(originState, level, origin, null, player, player.getMainHandItem()); + } + level.destroyBlock(origin, false); + } + } + return super.playerWillDestroy(level, pos, state, player); + } + + @Override + protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { + if (!state.is(newState.getBlock()) && !level.isClientSide) { + BlockPos origin = findOrigin(level, pos); + if (origin != null) { + level.destroyBlock(origin, true); + } + } + super.onRemove(state, level, pos, newState, movedByPiston); + } + + @Override + protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, + LevelAccessor level, BlockPos pos, BlockPos neighborPos) { + level.scheduleTick(pos, this, 1); + return super.updateShape(state, direction, neighborState, level, pos, neighborPos); + } + + @Override + protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + BlockPos origin = findOrigin(level, pos); + if (origin == null) { + level.removeBlock(pos, false); + return; + } + // Grown bushes need sturdy support under the whole footprint; break with + // drops if any of it is gone (mirrors plants popping when their dirt breaks). + BlockState originState = level.getBlockState(origin); + if (!originState.canSurvive(level, origin)) { + level.destroyBlock(origin, true); + } + } + + @Override + public ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState state) { + BlockPos origin = findOrigin(level, pos); + if (origin != null) { + return new ItemStack(level.getBlockState(origin).getBlock()); + } + return ItemStack.EMPTY; + } +} diff --git a/common/src/main/java/com/craisinlord/antarchy/content/block/VeryShortGrassBlock.java b/common/src/main/java/com/craisinlord/antarchy/content/block/VeryShortGrassBlock.java new file mode 100644 index 00000000..eca0a8e4 --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/content/block/VeryShortGrassBlock.java @@ -0,0 +1,52 @@ +package com.craisinlord.antarchy.content.block; + +import com.mojang.serialization.MapCodec; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockGetter; +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.BonemealableBlock; +import net.minecraft.world.level.block.BushBlock; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class VeryShortGrassBlock extends BushBlock implements BonemealableBlock { + public static final MapCodec CODEC = Block.simpleCodec(VeryShortGrassBlock::new); + + private static final VoxelShape SHAPE = Block.box(2.0, 0.0, 2.0, 14.0, 8.0, 14.0); + + public VeryShortGrassBlock(BlockBehaviour.Properties properties) { + super(properties); + } + + @Override + public MapCodec codec() { + return CODEC; + } + + @Override + protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + return SHAPE; + } + + @Override + public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) { + return true; + } + + @Override + public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) { + return true; + } + + @Override + public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { + level.setBlock(pos, Blocks.SHORT_GRASS.defaultBlockState(), 3); + } +} diff --git a/common/src/main/java/com/craisinlord/antarchy/content/client/BigBushCameraHider.java b/common/src/main/java/com/craisinlord/antarchy/content/client/BigBushCameraHider.java new file mode 100644 index 00000000..b91991b9 --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/content/client/BigBushCameraHider.java @@ -0,0 +1,56 @@ +package com.craisinlord.antarchy.content.client; + +import com.craisinlord.antarchy.content.block.BigBushBlock; +import com.craisinlord.antarchy.content.block.BigBushPartBlock; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +import java.util.Objects; + +public final class BigBushCameraHider { + private static BlockPos hiddenOrigin; + + private BigBushCameraHider() { + } + + public static void update(Minecraft mc) { + BlockPos newOrigin = null; + if (mc.level != null && mc.player != null) { + Vec3 cameraPos = mc.gameRenderer.getMainCamera().getPosition(); + BlockPos pos = BlockPos.containing(cameraPos); + BlockState state = mc.level.getBlockState(pos); + if (state.getBlock() instanceof BigBushBlock && state.getValue(BigBushBlock.AGE) > 0) { + newOrigin = pos; + } else if (state.getBlock() instanceof BigBushPartBlock) { + newOrigin = BigBushPartBlock.findOrigin(mc.level, pos); + } + } + if (!Objects.equals(newOrigin, hiddenOrigin)) { + BlockPos previous = hiddenOrigin; + hiddenOrigin = newOrigin; + markDirty(mc, previous); + markDirty(mc, newOrigin); + } + } + + private static void markDirty(Minecraft mc, BlockPos origin) { + if (origin != null && mc.levelRenderer != null) { + mc.levelRenderer.setBlocksDirty( + origin.getX() - 2, origin.getY() - 1, origin.getZ() - 2, + origin.getX() + 2, origin.getY() + 3, origin.getZ() + 2); + } + } + + public static boolean shouldFade(BlockPos pos) { + BlockPos origin = hiddenOrigin; + if (origin == null) { + return false; + } + return Math.abs(pos.getX() - origin.getX()) <= 1 + && Math.abs(pos.getZ() - origin.getZ()) <= 1 + && pos.getY() >= origin.getY() + && pos.getY() <= origin.getY() + 2; + } +} diff --git a/common/src/main/java/com/craisinlord/antarchy/content/client/BigBushRenderHelper.java b/common/src/main/java/com/craisinlord/antarchy/content/client/BigBushRenderHelper.java new file mode 100644 index 00000000..8a7f1aca --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/content/client/BigBushRenderHelper.java @@ -0,0 +1,26 @@ +package com.craisinlord.antarchy.content.client; + +import com.craisinlord.antarchy.content.block.BigBushBlock; +import com.craisinlord.antarchy.content.block.BigBushPartBlock; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public final class BigBushRenderHelper { + private BigBushRenderHelper() { + } + + public static boolean isInsideBigBush(LivingEntity entity) { + Level level = entity.level(); + return isBush(level, entity.blockPosition()) || isBush(level, BlockPos.containing(entity.getEyePosition())); + } + + private static boolean isBush(Level level, BlockPos pos) { + BlockState state = level.getBlockState(pos); + if (state.getBlock() instanceof BigBushPartBlock) { + return true; + } + return state.getBlock() instanceof BigBushBlock && state.getValue(BigBushBlock.AGE) > 0; + } +} diff --git a/common/src/main/java/com/craisinlord/antarchy/content/item/BigBushBlockItem.java b/common/src/main/java/com/craisinlord/antarchy/content/item/BigBushBlockItem.java new file mode 100644 index 00000000..f26a2c10 --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/content/item/BigBushBlockItem.java @@ -0,0 +1,23 @@ +package com.craisinlord.antarchy.content.item; + +import java.util.List; + +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.block.Block; + +public class BigBushBlockItem extends BlockItem { + public BigBushBlockItem(Block block, Properties properties) { + super(block, properties); + } + + @Override + public void appendHoverText(ItemStack stack, Item.TooltipContext context, List tooltipComponents, TooltipFlag tooltipFlag) { + tooltipComponents.add(Component.translatable("item.antarchy.big_bush.tooltip").withStyle(ChatFormatting.GRAY)); + super.appendHoverText(stack, context, tooltipComponents, tooltipFlag); + } +} diff --git a/common/src/main/java/com/craisinlord/antarchy/mixins/client/BlockRenderDispatcherBigBushMixin.java b/common/src/main/java/com/craisinlord/antarchy/mixins/client/BlockRenderDispatcherBigBushMixin.java new file mode 100644 index 00000000..3b948189 --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/mixins/client/BlockRenderDispatcherBigBushMixin.java @@ -0,0 +1,25 @@ +package com.craisinlord.antarchy.mixins.client; + +import com.craisinlord.antarchy.content.block.BigBushBlock; +import com.craisinlord.antarchy.content.block.BigBushPartBlock; +import com.craisinlord.antarchy.content.client.AlphaVertexConsumerProxy; +import com.craisinlord.antarchy.content.client.BigBushCameraHider; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(BlockRenderDispatcher.class) +public abstract class BlockRenderDispatcherBigBushMixin { + @ModifyVariable(method = "renderBatched", at = @At("HEAD"), argsOnly = true) + private VertexConsumer antarchy$fadeBigBushAroundCamera(VertexConsumer consumer, BlockState state, BlockPos pos) { + if ((state.getBlock() instanceof BigBushBlock || state.getBlock() instanceof BigBushPartBlock) + && BigBushCameraHider.shouldFade(pos)) { + return AlphaVertexConsumerProxy.wrap(consumer, 0.35F); + } + return consumer; + } +} diff --git a/common/src/main/java/com/craisinlord/antarchy/mixins/client/LivingEntityRendererBigBushMixin.java b/common/src/main/java/com/craisinlord/antarchy/mixins/client/LivingEntityRendererBigBushMixin.java new file mode 100644 index 00000000..926c1a78 --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/mixins/client/LivingEntityRendererBigBushMixin.java @@ -0,0 +1,54 @@ +package com.craisinlord.antarchy.mixins.client; + +import com.craisinlord.antarchy.content.client.BigBushRenderHelper; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.LivingEntityRenderer; +import net.minecraft.world.entity.LivingEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(LivingEntityRenderer.class) +public abstract class LivingEntityRendererBigBushMixin { + @Unique + private boolean antarchy$inBigBush; + + @Inject( + method = "render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", + at = @At("HEAD") + ) + private void antarchy$checkBigBush(LivingEntity entity, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource buffer, int packedLight, CallbackInfo ci) { + this.antarchy$inBigBush = BigBushRenderHelper.isInsideBigBush(entity); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Inject(method = "getRenderType", at = @At("HEAD"), cancellable = true) + private void antarchy$bigBushRenderType(LivingEntity entity, boolean bodyVisible, boolean translucent, boolean glowing, CallbackInfoReturnable cir) { + if (bodyVisible && !translucent && !glowing && BigBushRenderHelper.isInsideBigBush(entity)) { + cir.setReturnValue(RenderType.itemEntityTranslucentCull(((EntityRenderer) (Object) this).getTextureLocation(entity))); + } + } + + @Inject(method = "shouldShowName(Lnet/minecraft/world/entity/LivingEntity;)Z", at = @At("HEAD"), cancellable = true) + private void antarchy$hideBigBushNameTag(LivingEntity entity, CallbackInfoReturnable cir) { + if (BigBushRenderHelper.isInsideBigBush(entity)) { + cir.setReturnValue(false); + } + } + + @ModifyArg( + method = "render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/EntityModel;renderToBuffer(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;III)V"), + index = 4 + ) + private int antarchy$bigBushAlpha(int color) { + return this.antarchy$inBigBush && color == -1 ? 0x99FFFFFF : color; + } +} diff --git a/common/src/main/resources/assets/antarchy/blockstates/big_bush.json b/common/src/main/resources/assets/antarchy/blockstates/big_bush.json new file mode 100644 index 00000000..7ea0c8aa --- /dev/null +++ b/common/src/main/resources/assets/antarchy/blockstates/big_bush.json @@ -0,0 +1,16 @@ +{ + "variants": { + "age=0,facing=north": { "model": "antarchy:block/big_bush_stage1" }, + "age=0,facing=east": { "model": "antarchy:block/big_bush_stage1" }, + "age=0,facing=south": { "model": "antarchy:block/big_bush_stage1" }, + "age=0,facing=west": { "model": "antarchy:block/big_bush_stage1" }, + "age=1,facing=east": { "model": "antarchy:block/big_bush_stage2" }, + "age=1,facing=south": { "model": "antarchy:block/big_bush_stage2", "y": 90 }, + "age=1,facing=west": { "model": "antarchy:block/big_bush_stage2", "y": 180 }, + "age=1,facing=north": { "model": "antarchy:block/big_bush_stage2", "y": 270 }, + "age=2,facing=north": { "model": "antarchy:block/big_bush_stage3_bottom" }, + "age=2,facing=east": { "model": "antarchy:block/big_bush_stage3_bottom" }, + "age=2,facing=south": { "model": "antarchy:block/big_bush_stage3_bottom" }, + "age=2,facing=west": { "model": "antarchy:block/big_bush_stage3_bottom" } + } +} diff --git a/common/src/main/resources/assets/antarchy/blockstates/big_bush_part.json b/common/src/main/resources/assets/antarchy/blockstates/big_bush_part.json new file mode 100644 index 00000000..ea083469 --- /dev/null +++ b/common/src/main/resources/assets/antarchy/blockstates/big_bush_part.json @@ -0,0 +1,6 @@ +{ + "variants": { + "cap=false": { "model": "antarchy:block/big_bush_part" }, + "cap=true": { "model": "antarchy:block/big_bush_stage3_top" } + } +} diff --git a/common/src/main/resources/assets/antarchy/blockstates/very_short_grass.json b/common/src/main/resources/assets/antarchy/blockstates/very_short_grass.json new file mode 100644 index 00000000..c25b3915 --- /dev/null +++ b/common/src/main/resources/assets/antarchy/blockstates/very_short_grass.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "antarchy:block/very_short_grass" } + } +} diff --git a/common/src/main/resources/assets/antarchy/models/block/big_bush_part.json b/common/src/main/resources/assets/antarchy/models/block/big_bush_part.json new file mode 100644 index 00000000..906b6240 --- /dev/null +++ b/common/src/main/resources/assets/antarchy/models/block/big_bush_part.json @@ -0,0 +1,5 @@ +{ + "textures": { + "particle": "antarchy:block/big_bush/big_bush_stage3" + } +} diff --git a/common/src/main/resources/assets/antarchy/models/block/big_bush_stage1.json b/common/src/main/resources/assets/antarchy/models/block/big_bush_stage1.json new file mode 100644 index 00000000..dc28fa4f --- /dev/null +++ b/common/src/main/resources/assets/antarchy/models/block/big_bush_stage1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/tinted_cross", + "textures": { + "cross": "antarchy:block/big_bush/big_bush_stage1" + } +} diff --git a/common/src/main/resources/assets/antarchy/models/block/big_bush_stage2.json b/common/src/main/resources/assets/antarchy/models/block/big_bush_stage2.json new file mode 100644 index 00000000..05dd9750 --- /dev/null +++ b/common/src/main/resources/assets/antarchy/models/block/big_bush_stage2.json @@ -0,0 +1,29 @@ +{ + "ambientocclusion": false, + "textures": { + "particle": "antarchy:block/big_bush/big_bush_stage2", + "cross": "antarchy:block/big_bush/big_bush_stage2" + }, + "elements": [ + { + "from": [1.6, 0, 16], + "to": [30.4, 32, 16], + "rotation": { "origin": [16, 16, 16], "axis": "y", "angle": 45, "rescale": true }, + "shade": false, + "faces": { + "north": { "uv": [0, 0, 16, 16], "texture": "#cross", "tintindex": 0 }, + "south": { "uv": [0, 0, 16, 16], "texture": "#cross", "tintindex": 0 } + } + }, + { + "from": [16, 0, 1.6], + "to": [16, 32, 30.4], + "rotation": { "origin": [16, 16, 16], "axis": "y", "angle": 45, "rescale": true }, + "shade": false, + "faces": { + "west": { "uv": [0, 0, 16, 16], "texture": "#cross", "tintindex": 0 }, + "east": { "uv": [0, 0, 16, 16], "texture": "#cross", "tintindex": 0 } + } + } + ] +} diff --git a/common/src/main/resources/assets/antarchy/models/block/big_bush_stage3_bottom.json b/common/src/main/resources/assets/antarchy/models/block/big_bush_stage3_bottom.json new file mode 100644 index 00000000..ac5a27de --- /dev/null +++ b/common/src/main/resources/assets/antarchy/models/block/big_bush_stage3_bottom.json @@ -0,0 +1,29 @@ +{ + "ambientocclusion": false, + "textures": { + "particle": "antarchy:block/big_bush/big_bush_stage3", + "cross": "antarchy:block/big_bush/big_bush_stage3" + }, + "elements": [ + { + "from": [-13.6, 0, 8], + "to": [29.6, 32, 8], + "rotation": { "origin": [8, 16, 8], "axis": "y", "angle": 45, "rescale": true }, + "shade": false, + "faces": { + "north": { "uv": [0, 5.3333, 16, 16], "texture": "#cross", "tintindex": 0 }, + "south": { "uv": [0, 5.3333, 16, 16], "texture": "#cross", "tintindex": 0 } + } + }, + { + "from": [8, 0, -13.6], + "to": [8, 32, 29.6], + "rotation": { "origin": [8, 16, 8], "axis": "y", "angle": 45, "rescale": true }, + "shade": false, + "faces": { + "west": { "uv": [0, 5.3333, 16, 16], "texture": "#cross", "tintindex": 0 }, + "east": { "uv": [0, 5.3333, 16, 16], "texture": "#cross", "tintindex": 0 } + } + } + ] +} diff --git a/common/src/main/resources/assets/antarchy/models/block/big_bush_stage3_top.json b/common/src/main/resources/assets/antarchy/models/block/big_bush_stage3_top.json new file mode 100644 index 00000000..fb49b817 --- /dev/null +++ b/common/src/main/resources/assets/antarchy/models/block/big_bush_stage3_top.json @@ -0,0 +1,29 @@ +{ + "ambientocclusion": false, + "textures": { + "particle": "antarchy:block/big_bush/big_bush_stage3", + "cross": "antarchy:block/big_bush/big_bush_stage3" + }, + "elements": [ + { + "from": [-13.6, 0, 8], + "to": [29.6, 16, 8], + "rotation": { "origin": [8, 8, 8], "axis": "y", "angle": 45, "rescale": true }, + "shade": false, + "faces": { + "north": { "uv": [0, 0, 16, 5.3333], "texture": "#cross", "tintindex": 0 }, + "south": { "uv": [0, 0, 16, 5.3333], "texture": "#cross", "tintindex": 0 } + } + }, + { + "from": [8, 0, -13.6], + "to": [8, 16, 29.6], + "rotation": { "origin": [8, 8, 8], "axis": "y", "angle": 45, "rescale": true }, + "shade": false, + "faces": { + "west": { "uv": [0, 0, 16, 5.3333], "texture": "#cross", "tintindex": 0 }, + "east": { "uv": [0, 0, 16, 5.3333], "texture": "#cross", "tintindex": 0 } + } + } + ] +} diff --git a/common/src/main/resources/assets/antarchy/models/block/very_short_grass.json b/common/src/main/resources/assets/antarchy/models/block/very_short_grass.json new file mode 100644 index 00000000..c1f1d394 --- /dev/null +++ b/common/src/main/resources/assets/antarchy/models/block/very_short_grass.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/tinted_cross", + "textures": { + "cross": "antarchy:block/very_short_grass" + } +} diff --git a/common/src/main/resources/assets/antarchy/models/item/big_bush.json b/common/src/main/resources/assets/antarchy/models/item/big_bush.json new file mode 100644 index 00000000..0b62849a --- /dev/null +++ b/common/src/main/resources/assets/antarchy/models/item/big_bush.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "antarchy:block/big_bush/big_bush_stage1" + } +} diff --git a/common/src/main/resources/assets/antarchy/models/item/very_short_grass.json b/common/src/main/resources/assets/antarchy/models/item/very_short_grass.json new file mode 100644 index 00000000..0929ced1 --- /dev/null +++ b/common/src/main/resources/assets/antarchy/models/item/very_short_grass.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "antarchy:block/very_short_grass" + } +} diff --git a/common/src/main/resources/assets/antarchy/textures/block/big_bush/big_bush_stage1.png b/common/src/main/resources/assets/antarchy/textures/block/big_bush/big_bush_stage1.png new file mode 100644 index 00000000..21da1087 Binary files /dev/null and b/common/src/main/resources/assets/antarchy/textures/block/big_bush/big_bush_stage1.png differ diff --git a/common/src/main/resources/assets/antarchy/textures/block/big_bush/big_bush_stage2.png b/common/src/main/resources/assets/antarchy/textures/block/big_bush/big_bush_stage2.png new file mode 100644 index 00000000..eaecfc99 Binary files /dev/null and b/common/src/main/resources/assets/antarchy/textures/block/big_bush/big_bush_stage2.png differ diff --git a/common/src/main/resources/assets/antarchy/textures/block/big_bush/big_bush_stage3.png b/common/src/main/resources/assets/antarchy/textures/block/big_bush/big_bush_stage3.png new file mode 100644 index 00000000..e4e92e5d Binary files /dev/null and b/common/src/main/resources/assets/antarchy/textures/block/big_bush/big_bush_stage3.png differ diff --git a/common/src/main/resources/assets/antarchy/textures/block/very_short_grass.png b/common/src/main/resources/assets/antarchy/textures/block/very_short_grass.png new file mode 100644 index 00000000..2b9c8433 Binary files /dev/null and b/common/src/main/resources/assets/antarchy/textures/block/very_short_grass.png differ diff --git a/common/src/main/resources/assets/antarchy/textures/block/very_tall_grass/very_tall_grass_bottom.png b/common/src/main/resources/assets/antarchy/textures/block/very_tall_grass/very_tall_grass_bottom.png new file mode 100644 index 00000000..7b39df63 Binary files /dev/null and b/common/src/main/resources/assets/antarchy/textures/block/very_tall_grass/very_tall_grass_bottom.png differ diff --git a/common/src/main/resources/assets/antarchy/textures/block/very_tall_grass/very_tall_grass_middle.png b/common/src/main/resources/assets/antarchy/textures/block/very_tall_grass/very_tall_grass_middle.png new file mode 100644 index 00000000..20d8e01d Binary files /dev/null and b/common/src/main/resources/assets/antarchy/textures/block/very_tall_grass/very_tall_grass_middle.png differ diff --git a/common/src/main/resources/assets/antarchy/textures/block/very_tall_grass/very_tall_grass_top.png b/common/src/main/resources/assets/antarchy/textures/block/very_tall_grass/very_tall_grass_top.png new file mode 100644 index 00000000..d81d7528 Binary files /dev/null and b/common/src/main/resources/assets/antarchy/textures/block/very_tall_grass/very_tall_grass_top.png differ diff --git a/common/src/main/resources/data/antarchy/loot_table/blocks/big_bush.json b/common/src/main/resources/data/antarchy/loot_table/blocks/big_bush.json new file mode 100644 index 00000000..bdc0967f --- /dev/null +++ b/common/src/main/resources/data/antarchy/loot_table/blocks/big_bush.json @@ -0,0 +1,66 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "items": "minecraft:shears" + } + } + ], + "entries": [ + { + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "antarchy:big_bush", + "conditions": [ + { + "condition": "minecraft:block_state_property", + "block": "antarchy:big_bush", + "properties": { + "age": "2" + } + } + ], + "functions": [ + { + "function": "minecraft:set_count", + "count": 3.0 + } + ] + }, + { + "type": "minecraft:item", + "name": "antarchy:big_bush", + "conditions": [ + { + "condition": "minecraft:block_state_property", + "block": "antarchy:big_bush", + "properties": { + "age": "1" + } + } + ], + "functions": [ + { + "function": "minecraft:set_count", + "count": 2.0 + } + ] + }, + { + "type": "minecraft:item", + "name": "antarchy:big_bush" + } + ] + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "antarchy:blocks/big_bush" +} diff --git a/common/src/main/resources/data/antarchy/loot_table/blocks/very_short_grass.json b/common/src/main/resources/data/antarchy/loot_table/blocks/very_short_grass.json new file mode 100644 index 00000000..71a04620 --- /dev/null +++ b/common/src/main/resources/data/antarchy/loot_table/blocks/very_short_grass.json @@ -0,0 +1,49 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "items": "minecraft:shears" + } + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "antarchy:very_short_grass" + } + ], + "rolls": 1.0 + }, + { + "entries": [ + { + "type": "minecraft:item", + "name": "minecraft:wheat_seeds", + "conditions": [ + { + "condition": "minecraft:table_bonus", + "enchantment": "minecraft:fortune", + "chances": [ + 0.125, + 0.14285715, + 0.16666667, + 0.2 + ] + } + ], + "functions": [ + { + "function": "minecraft:explosion_decay" + } + ] + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "antarchy:blocks/very_short_grass" +} diff --git a/common/src/main/resources/data/minecraft/tags/block/sword_efficient.json b/common/src/main/resources/data/minecraft/tags/block/sword_efficient.json new file mode 100644 index 00000000..54f81cf6 --- /dev/null +++ b/common/src/main/resources/data/minecraft/tags/block/sword_efficient.json @@ -0,0 +1,8 @@ +{ + "replace": false, + "values": [ + "antarchy:big_bush", + "antarchy:big_bush_part", + "antarchy:very_short_grass" + ] +} diff --git a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/client/BigBushHideHandler.java b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/client/BigBushHideHandler.java new file mode 100644 index 00000000..f383a7c8 --- /dev/null +++ b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/client/BigBushHideHandler.java @@ -0,0 +1,20 @@ +package com.craisinlord.antarchy.neoforge.client; + +import com.craisinlord.antarchy.Antarchy; +import com.craisinlord.antarchy.content.client.BigBushCameraHider; +import net.minecraft.client.Minecraft; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.ClientTickEvent; + +@EventBusSubscriber(modid = Antarchy.MODID, value = Dist.CLIENT, bus = EventBusSubscriber.Bus.GAME) +public final class BigBushHideHandler { + private BigBushHideHandler() { + } + + @SubscribeEvent + public static void onClientTick(ClientTickEvent.Post event) { + BigBushCameraHider.update(Minecraft.getInstance()); + } +}