Updated all feature based sapling Growing
This commit is contained in:
parent
7285ada6d6
commit
72a707f456
8 changed files with 119 additions and 90 deletions
|
@ -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<F extends Feature<FC>, 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<F extends Feature<FC>, 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,12 +164,22 @@ public class BCLFeature<F extends Feature<FC>, 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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public static boolean place(Feature<?> feature, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||
if (feature instanceof UserGrowableFeature growable) {
|
||||
return growable.grow(level, pos, random);
|
||||
return growable.grow(level, pos, random, config);
|
||||
}
|
||||
|
||||
FeaturePlaceContext context = new FeaturePlaceContext(
|
||||
|
@ -175,8 +188,23 @@ public class BCLFeature<F extends Feature<FC>, FC extends FeatureConfiguration>
|
|||
level.getChunkSource().getGenerator(),
|
||||
random,
|
||||
pos,
|
||||
null
|
||||
config
|
||||
);
|
||||
return feature.place(context);
|
||||
}
|
||||
|
||||
public static boolean place(Feature<NoneFeatureConfiguration> feature,
|
||||
ServerLevel level,
|
||||
BlockPos pos,
|
||||
RandomSource random) {
|
||||
return placeUnbound(feature, FeatureConfiguration.NONE, level, pos, random);
|
||||
}
|
||||
|
||||
public static <FC extends FeatureConfiguration> boolean place(Feature<FC> feature,
|
||||
FC config,
|
||||
ServerLevel level,
|
||||
BlockPos pos,
|
||||
RandomSource random) {
|
||||
return placeUnbound(feature, config, level, pos, random);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,8 @@ import org.betterx.bclib.api.v2.levelgen.features.config.ScatterFeatureConfig;
|
|||
public class FastFeatures {
|
||||
|
||||
|
||||
public static BCLFeature vine(ResourceLocation location,
|
||||
public static BCLFeature<ScatterFeature<ScatterFeatureConfig.OnSolid>, ScatterFeatureConfig.OnSolid> vine(
|
||||
ResourceLocation location,
|
||||
boolean onFloor,
|
||||
boolean sparse,
|
||||
ScatterFeatureConfig.Builder builder) {
|
||||
|
@ -146,7 +147,7 @@ public class FastFeatures {
|
|||
}
|
||||
|
||||
|
||||
public static <FC extends FeatureConfiguration> BCLFeature
|
||||
public static <FC extends FeatureConfiguration> BCLFeature<Feature<FC>, FC>
|
||||
simple(ResourceLocation location,
|
||||
int searchDist,
|
||||
boolean rare,
|
||||
|
|
|
@ -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<FC extends ScatterFeatureConfig>
|
||||
extends Feature<FC> {
|
||||
|
||||
public static <T extends ScatterFeatureConfig> BCLFeature createAndRegister(ResourceLocation location,
|
||||
int minPerChunk,
|
||||
int maxPerChunk,
|
||||
T cfg,
|
||||
Feature<T> inlineFeature) {
|
||||
List<Holder<PlacedFeature>> 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<FC> implements UserGrowableFeature<FC> {
|
||||
|
||||
public ScatterFeature(Codec<FC> configCodec) {
|
||||
super(configCodec);
|
||||
|
@ -104,7 +53,8 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
|
|||
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<FC extends ScatterFeatureConfig>
|
|||
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<FC extends ScatterFeatureConfig>
|
|||
direction,
|
||||
myHeight,
|
||||
config,
|
||||
random);
|
||||
random, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,9 +97,9 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
|
|||
|
||||
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<FC extends ScatterFeatureConfig>
|
|||
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<FC extends ScatterFeatureConfig>
|
|||
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<FC extends ScatterFeatureConfig>
|
|||
|
||||
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<FC extends ScatterFeatureConfig>
|
|||
levelAccessor.setBlock(blockPos, baseState, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean grow(ServerLevelAccessor level,
|
||||
BlockPos origin,
|
||||
RandomSource random,
|
||||
FC config) {
|
||||
Optional<Direction> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<FC extends FeatureConfiguration> {
|
||||
boolean grow(ServerLevelAccessor level,
|
||||
BlockPos pos,
|
||||
RandomSource random);
|
||||
RandomSource random,
|
||||
FC configuration);
|
||||
}
|
||||
|
|
|
@ -223,6 +223,17 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> tripleShapeCeil(Block s) {
|
||||
return tripleShapeCeil(s.defaultBlockState());
|
||||
}
|
||||
|
||||
public Builder<T> 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<T> 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<T> noSpread() {
|
||||
return spread(0, 0, ConstantInt.of(0));
|
||||
}
|
||||
|
||||
|
||||
public Builder<T> spread(float maxSpread, float sizeVariation) {
|
||||
return spread(maxSpread, sizeVariation, ConstantInt.of((int) Math.min(16, 4 * maxSpread * maxSpread)));
|
||||
}
|
||||
|
|
|
@ -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<BlockState, Feature<?>> featureSupplier) {
|
||||
public FeatureHangingSaplingBlock(Function<BlockState, BCLFeature> featureSupplier) {
|
||||
super(featureSupplier);
|
||||
}
|
||||
|
||||
public FeatureHangingSaplingBlock(Function<BlockState, Feature<?>> featureSupplier, int light) {
|
||||
public FeatureHangingSaplingBlock(Function<BlockState, BCLFeature> featureSupplier,
|
||||
int light) {
|
||||
super(light, featureSupplier);
|
||||
}
|
||||
|
||||
public FeatureHangingSaplingBlock(BlockBehaviour.Properties properties,
|
||||
Function<BlockState, Feature<?>> featureSupplier) {
|
||||
Function<BlockState, BCLFeature> featureSupplier) {
|
||||
super(properties, featureSupplier);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<BlockState, Feature<?>> feature;
|
||||
private final Function<BlockState, BCLFeature> feature;
|
||||
|
||||
public FeatureSaplingBlock(Function<BlockState, Feature<?>> featureSupplier) {
|
||||
public FeatureSaplingBlock(Function<BlockState, BCLFeature> 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<BlockState, Feature<?>> featureSupplier) {
|
||||
public FeatureSaplingBlock(int light, Function<BlockState, BCLFeature> 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<BlockState, Feature<?>> featureSupplier) {
|
||||
public FeatureSaplingBlock(BlockBehaviour.Properties properties,
|
||||
Function<BlockState, BCLFeature> 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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue