From 72a707f456da1a721d91299c429b180c27af1ce2 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 7 Jun 2022 21:23:02 +0200 Subject: [PATCH] Updated all feature based sapling Growing --- .../api/v2/levelgen/features/BCLFeature.java | 40 ++++++- .../v2/levelgen/features/FastFeatures.java | 11 +- .../v2/levelgen/features/ScatterFeature.java | 108 +++++++----------- .../features/UserGrowableFeature.java | 6 +- .../features/config/ScatterFeatureConfig.java | 16 +++ .../blocks/FeatureHangingSaplingBlock.java | 10 +- .../bclib/blocks/FeatureSaplingBlock.java | 14 +-- .../org/betterx/bclib/util/BlocksHelper.java | 4 + 8 files changed, 119 insertions(+), 90 deletions(-) diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/BCLFeature.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/BCLFeature.java index 34024e9b..f25cf508 100644 --- a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/BCLFeature.java +++ b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/BCLFeature.java @@ -17,6 +17,7 @@ import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration; import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; import net.minecraft.world.level.levelgen.feature.configurations.RandomFeatureConfiguration; +import net.minecraft.world.level.levelgen.feature.configurations.RandomPatchConfiguration; import net.minecraft.world.level.levelgen.placement.PlacedFeature; import net.minecraft.world.level.levelgen.placement.PlacementModifier; @@ -62,6 +63,7 @@ public class BCLFeature, FC extends FeatureConfiguration> private final Decoration featureStep; private final F feature; private final FC configuration; + public final ResourceLocation id; public BCLFeature(ResourceLocation id, @@ -81,6 +83,7 @@ public class BCLFeature, FC extends FeatureConfiguration> this.featureStep = featureStep; this.feature = feature; this.configuration = configuration; + this.id = id; if (!BuiltinRegistries.PLACED_FEATURE.containsKey(id)) { Registry.register(BuiltinRegistries.PLACED_FEATURE, id, placedFeature.value()); @@ -161,22 +164,47 @@ public class BCLFeature, FC extends FeatureConfiguration> } public boolean place(ServerLevel level, BlockPos pos, RandomSource random) { - return place(this.getFeature(), level, pos, random); + return place(this.getFeature(), this.getConfiguration(), level, pos, random); } - public static boolean place(Feature feature, ServerLevel level, BlockPos pos, RandomSource random) { - if (feature instanceof UserGrowableFeature growable) { - return growable.grow(level, pos, random); + private static boolean placeUnbound(Feature feature, + FeatureConfiguration config, + ServerLevel level, + BlockPos pos, + RandomSource random) { + if (config instanceof RandomPatchConfiguration rnd) { + var configured = rnd.feature().value().feature().value(); + feature = configured.feature(); + config = configured.config(); } - + + if (feature instanceof UserGrowableFeature growable) { + return growable.grow(level, pos, random, config); + } + FeaturePlaceContext context = new FeaturePlaceContext( Optional.empty(), level, level.getChunkSource().getGenerator(), random, pos, - null + config ); return feature.place(context); } + + public static boolean place(Feature feature, + ServerLevel level, + BlockPos pos, + RandomSource random) { + return placeUnbound(feature, FeatureConfiguration.NONE, level, pos, random); + } + + public static boolean place(Feature feature, + FC config, + ServerLevel level, + BlockPos pos, + RandomSource random) { + return placeUnbound(feature, config, level, pos, random); + } } diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/FastFeatures.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/FastFeatures.java index 57ca6f49..e3206acd 100644 --- a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/FastFeatures.java +++ b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/FastFeatures.java @@ -20,10 +20,11 @@ import org.betterx.bclib.api.v2.levelgen.features.config.ScatterFeatureConfig; public class FastFeatures { - public static BCLFeature vine(ResourceLocation location, - boolean onFloor, - boolean sparse, - ScatterFeatureConfig.Builder builder) { + public static BCLFeature, ScatterFeatureConfig.OnSolid> vine( + ResourceLocation location, + boolean onFloor, + boolean sparse, + ScatterFeatureConfig.Builder builder) { return scatter(location, onFloor, sparse, builder, BCLFeature.SCATTER_ON_SOLID); } @@ -146,7 +147,7 @@ public class FastFeatures { } - public static BCLFeature + public static BCLFeature, FC> simple(ResourceLocation location, int searchDist, boolean rare, diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/ScatterFeature.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/ScatterFeature.java index b6567249..e7893272 100644 --- a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/ScatterFeature.java +++ b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/ScatterFeature.java @@ -2,73 +2,22 @@ package org.betterx.bclib.api.v2.levelgen.features; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.core.Holder; -import net.minecraft.core.HolderSet; -import net.minecraft.data.worldgen.placement.PlacementUtils; -import net.minecraft.resources.ResourceLocation; import net.minecraft.util.RandomSource; -import net.minecraft.util.valueproviders.ClampedNormalInt; -import net.minecraft.util.valueproviders.ConstantInt; -import net.minecraft.util.valueproviders.UniformInt; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.GenerationStep; -import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate; import net.minecraft.world.level.levelgen.feature.Feature; import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; -import net.minecraft.world.level.levelgen.feature.configurations.SimpleRandomFeatureConfiguration; -import net.minecraft.world.level.levelgen.placement.*; import com.mojang.serialization.Codec; import org.betterx.bclib.api.v2.levelgen.features.config.ScatterFeatureConfig; -import org.betterx.bclib.api.v2.tag.CommonBlockTags; import org.betterx.bclib.util.BlocksHelper; -import java.util.ArrayList; -import java.util.List; import java.util.Optional; public class ScatterFeature - extends Feature { - - public static BCLFeature createAndRegister(ResourceLocation location, - int minPerChunk, - int maxPerChunk, - T cfg, - Feature inlineFeature) { - List> set = new ArrayList<>(2); - if (cfg.floorChance > 0) set.add(PlacementUtils.inlinePlaced(inlineFeature, - cfg, - EnvironmentScanPlacement.scanningFor(Direction.DOWN, - BlockPredicate.matchesTag(CommonBlockTags.TERRAIN), - BlockPredicate.ONLY_IN_AIR_PREDICATE, - 12), - RandomOffsetPlacement.vertical(ConstantInt.of(1)))); - - if (cfg.floorChance < 1) { - set.add(PlacementUtils.inlinePlaced(inlineFeature, - cfg, - EnvironmentScanPlacement.scanningFor(Direction.UP, - BlockPredicate.matchesTag(CommonBlockTags.TERRAIN), - BlockPredicate.ONLY_IN_AIR_PREDICATE, - 12), - RandomOffsetPlacement.vertical(ConstantInt.of(-1)))); - } - SimpleRandomFeatureConfiguration configuration = new SimpleRandomFeatureConfiguration(HolderSet.direct(set)); - - return BCLFeatureBuilder.start(location, SIMPLE_RANDOM_SELECTOR) - .decoration(GenerationStep.Decoration.VEGETAL_DECORATION) - .modifier(CountPlacement.of(UniformInt.of(minPerChunk, maxPerChunk))) - .modifier(InSquarePlacement.spread()) - .randomHeight4FromFloorCeil() - .modifier(CountPlacement.of(UniformInt.of(2, 5))) - .modifier(RandomOffsetPlacement.of( - ClampedNormalInt.of(0.0f, 2.0f, -6, 6), - ClampedNormalInt.of(0.0f, 0.6f, -2, 2))) - .onlyInBiome() - .buildAndRegister(configuration); - } + extends Feature implements UserGrowableFeature { public ScatterFeature(Codec configCodec) { super(configCodec); @@ -104,7 +53,8 @@ public class ScatterFeature if (config.isValidBase(level.getBlockState(basePos))) { final Direction surfaceDirection = direction.getOpposite(); BlockPos.MutableBlockPos POS = new BlockPos.MutableBlockPos(); - buildPillarWithBase(level, origin, basePos, direction, centerHeight, config, random); + int adaptedHeight = freeHeight(level, direction, centerHeight, config, origin); + buildPillarWithBase(level, origin, basePos, direction, adaptedHeight, config, random, false); final double distNormalizer = (config.maxSpread * Math.sqrt(2)); final int tryCount = config.spreadCount.sample(random); @@ -114,7 +64,11 @@ public class ScatterFeature POS.set(x, basePos.getY(), z); if (BlocksHelper.findSurroundingSurface(level, POS, surfaceDirection, 4, config::isValidBase)) { - int myHeight = freeHeight(level, direction, centerHeight, config, POS); + int myHeight = freeHeight(level, + direction, + centerHeight, + config, + POS); int dx = x - POS.getX(); int dz = z - POS.getZ(); @@ -135,7 +89,7 @@ public class ScatterFeature direction, myHeight, config, - random); + random, false); } } } @@ -143,9 +97,9 @@ public class ScatterFeature private int freeHeight(LevelAccessor level, Direction direction, - int centerHeight, + int defaultHeight, ScatterFeatureConfig config, - BlockPos.MutableBlockPos POS) { + BlockPos POS) { int myHeight; if (config.growWhileFree) { myHeight = BlocksHelper.blockCount(level, @@ -155,9 +109,9 @@ public class ScatterFeature BlocksHelper::isFree ); } else { - myHeight = centerHeight; + myHeight = defaultHeight; } - return myHeight; + return Math.max(config.minHeight, myHeight); } private void buildPillarWithBase(LevelAccessor level, @@ -166,8 +120,9 @@ public class ScatterFeature Direction direction, int height, ScatterFeatureConfig config, - RandomSource random) { - if (BlocksHelper.isFreeSpace(level, origin, direction, height, BlocksHelper::isFree)) { + RandomSource random, + boolean force) { + if (force || BlocksHelper.isFreeSpace(level, origin, direction, height, BlocksHelper::isFree)) { createPatchOfBaseBlocks(level, random, basePos, config); BlockState bottom = config.bottomBlock.getState(random, origin); if (bottom.canSurvive(level, origin)) { @@ -185,11 +140,7 @@ public class ScatterFeature final BlockPos.MutableBlockPos POS = origin.mutable(); for (int size = 0; size < height; size++) { - BlockState previous = level.getBlockState(POS); BlockState state = config.createBlock(size, height - 1, random, POS); - if (!BlocksHelper.isFree(previous)) { - System.out.println("Replaced " + previous + " with " + state + " at " + POS); - } BlocksHelper.setWithoutUpdate(level, POS, state); POS.move(direction); } @@ -246,4 +197,29 @@ public class ScatterFeature levelAccessor.setBlock(blockPos, baseState, 2); } } + + @Override + public boolean grow(ServerLevelAccessor level, + BlockPos origin, + RandomSource random, + FC config) { + Optional oDirection = getTipDirection(level, origin, random, config); + if (oDirection.isEmpty()) { + return false; + } + Direction direction = oDirection.get(); + BlockPos basePos = origin.relative(direction, -1); + + if (config.isValidBase(level.getBlockState(basePos))) { + int centerHeight = (int) (random.nextFloat() * (1 + config.maxHeight - config.minHeight) + config.minHeight); + centerHeight = freeHeight(level, + direction, + centerHeight, + config, + origin.relative(direction, 1)) + 1; + buildPillarWithBase(level, origin, basePos, direction, centerHeight, config, random, true); + } + return false; + } + } diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/UserGrowableFeature.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/UserGrowableFeature.java index 28cdb5a3..c2942830 100644 --- a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/UserGrowableFeature.java +++ b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/UserGrowableFeature.java @@ -3,9 +3,11 @@ package org.betterx.bclib.api.v2.levelgen.features; import net.minecraft.core.BlockPos; import net.minecraft.util.RandomSource; import net.minecraft.world.level.ServerLevelAccessor; +import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration; -public interface UserGrowableFeature { +public interface UserGrowableFeature { boolean grow(ServerLevelAccessor level, BlockPos pos, - RandomSource random); + RandomSource random, + FC configuration); } diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/config/ScatterFeatureConfig.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/config/ScatterFeatureConfig.java index cf67de26..9065e4c4 100644 --- a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/config/ScatterFeatureConfig.java +++ b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/config/ScatterFeatureConfig.java @@ -223,6 +223,17 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { return this; } + public Builder tripleShapeCeil(Block s) { + return tripleShapeCeil(s.defaultBlockState()); + } + + public Builder tripleShapeCeil(BlockState s) { + block(s.setValue(BlockProperties.TRIPLE_SHAPE, BlockProperties.TripleShape.MIDDLE)); + tipBlock(s.setValue(BlockProperties.TRIPLE_SHAPE, BlockProperties.TripleShape.BOTTOM)); + bottomBlock(s.setValue(BlockProperties.TRIPLE_SHAPE, BlockProperties.TripleShape.TOP)); + return this; + } + public Builder block(BlockStateProvider s) { this.clusterBlock = s; if (tipBlock == null) tipBlock = s; @@ -297,6 +308,11 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { return this; } + public Builder noSpread() { + return spread(0, 0, ConstantInt.of(0)); + } + + public Builder spread(float maxSpread, float sizeVariation) { return spread(maxSpread, sizeVariation, ConstantInt.of((int) Math.min(16, 4 * maxSpread * maxSpread))); } diff --git a/src/main/java/org/betterx/bclib/blocks/FeatureHangingSaplingBlock.java b/src/main/java/org/betterx/bclib/blocks/FeatureHangingSaplingBlock.java index 8d76cae9..566c3f1a 100644 --- a/src/main/java/org/betterx/bclib/blocks/FeatureHangingSaplingBlock.java +++ b/src/main/java/org/betterx/bclib/blocks/FeatureHangingSaplingBlock.java @@ -6,25 +6,27 @@ 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.levelgen.feature.Feature; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; +import org.betterx.bclib.api.v2.levelgen.features.BCLFeature; + import java.util.function.Function; public abstract class FeatureHangingSaplingBlock extends FeatureSaplingBlock { private static final VoxelShape SHAPE = Block.box(4, 2, 4, 12, 16, 12); - public FeatureHangingSaplingBlock(Function> featureSupplier) { + public FeatureHangingSaplingBlock(Function featureSupplier) { super(featureSupplier); } - public FeatureHangingSaplingBlock(Function> featureSupplier, int light) { + public FeatureHangingSaplingBlock(Function featureSupplier, + int light) { super(light, featureSupplier); } public FeatureHangingSaplingBlock(BlockBehaviour.Properties properties, - Function> featureSupplier) { + Function featureSupplier) { super(properties, featureSupplier); } diff --git a/src/main/java/org/betterx/bclib/blocks/FeatureSaplingBlock.java b/src/main/java/org/betterx/bclib/blocks/FeatureSaplingBlock.java index ff2e445f..53799f6f 100644 --- a/src/main/java/org/betterx/bclib/blocks/FeatureSaplingBlock.java +++ b/src/main/java/org/betterx/bclib/blocks/FeatureSaplingBlock.java @@ -16,7 +16,6 @@ import net.minecraft.world.level.block.SaplingBlock; 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.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; @@ -42,9 +41,9 @@ import org.jetbrains.annotations.Nullable; public class FeatureSaplingBlock extends SaplingBlock implements RenderLayerProvider, BlockModelProvider { private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12); - private final Function> feature; + private final Function feature; - public FeatureSaplingBlock(Function> featureSupplier) { + public FeatureSaplingBlock(Function featureSupplier) { this(FabricBlockSettings.of(Material.PLANT) .collidable(false) .instabreak() @@ -54,7 +53,7 @@ public class FeatureSaplingBlock extends SaplingBlock implements RenderLayerProv ); } - public FeatureSaplingBlock(int light, Function> featureSupplier) { + public FeatureSaplingBlock(int light, Function featureSupplier) { this(FabricBlockSettings.of(Material.PLANT) .collidable(false) .luminance(light) @@ -65,12 +64,13 @@ public class FeatureSaplingBlock extends SaplingBlock implements RenderLayerProv ); } - public FeatureSaplingBlock(BlockBehaviour.Properties properties, Function> featureSupplier) { + public FeatureSaplingBlock(BlockBehaviour.Properties properties, + Function featureSupplier) { super(null, properties); this.feature = featureSupplier; } - protected Feature getFeature(BlockState state) { + protected BCLFeature getFeature(BlockState state) { return feature.apply(state); } @@ -97,7 +97,7 @@ public class FeatureSaplingBlock extends SaplingBlock implements RenderLayerProv @Override public void advanceTree(ServerLevel world, BlockPos pos, BlockState blockState, RandomSource random) { - BCLFeature.place(getFeature(blockState), world, pos, random); + getFeature(blockState).place(world, pos, random); } @Override diff --git a/src/main/java/org/betterx/bclib/util/BlocksHelper.java b/src/main/java/org/betterx/bclib/util/BlocksHelper.java index 1813328a..3b41d421 100644 --- a/src/main/java/org/betterx/bclib/util/BlocksHelper.java +++ b/src/main/java/org/betterx/bclib/util/BlocksHelper.java @@ -332,6 +332,10 @@ public class BlocksHelper { return state.isAir(); } + public static boolean isFreeOrReplaceable(BlockState state) { + return state.isAir() || state.getMaterial().isReplaceable(); + } + public static boolean isFreeOrFluid(BlockState state) { return state.isAir() || isFluid(state); }