New combined Feature Strategy and Features for BoneReef
This commit is contained in:
parent
4a95927e1c
commit
c14928ea80
11 changed files with 260 additions and 31 deletions
|
@ -84,7 +84,7 @@ public class BCLCommonFeatures {
|
|||
int chance) {
|
||||
return BCLFeatureBuilder.start(id, feature)
|
||||
.decoration(decoration)
|
||||
.oncePerChunks(chance)
|
||||
.onceEvery(chance)
|
||||
.squarePlacement()
|
||||
.onlyInBiome()
|
||||
.buildAndRegister();
|
||||
|
@ -136,7 +136,7 @@ public class BCLCommonFeatures {
|
|||
BCLFeatureBuilder builder = BCLFeatureBuilder.start(id, Feature.ORE).decoration(Decoration.UNDERGROUND_ORES);
|
||||
|
||||
if (rare) {
|
||||
builder.oncePerChunks(veins);
|
||||
builder.onceEvery(veins);
|
||||
} else {
|
||||
builder.count(veins);
|
||||
}
|
||||
|
|
|
@ -11,11 +11,13 @@ import net.minecraft.world.level.levelgen.GenerationStep.Decoration;
|
|||
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.RandomFeatureConfiguration;
|
||||
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementModifier;
|
||||
|
||||
import org.betterx.bclib.BCLib;
|
||||
import org.betterx.bclib.api.features.config.ScatterFeatureConfig;
|
||||
import org.betterx.bclib.api.features.config.TemplateFeatureConfig;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
@ -23,8 +25,14 @@ import java.util.Optional;
|
|||
public class BCLFeature {
|
||||
public static final Feature<ScatterFeatureConfig.OnSolid> SCATTER_ON_SOLID = register(
|
||||
BCLib.makeID("scatter_on_solid"),
|
||||
new ScatterFeature<>(ScatterFeatureConfig.OnSolid.CODEC)
|
||||
);
|
||||
new ScatterFeature<>(ScatterFeatureConfig.OnSolid.CODEC));
|
||||
|
||||
public static final Feature<RandomFeatureConfiguration> RANDOM_SELECT = register(
|
||||
BCLib.makeID("random_select"),
|
||||
new WeightedRandomSelectorFeature());
|
||||
public static final Feature<TemplateFeatureConfig> TEMPLATE = register(BCLib.makeID("template"),
|
||||
new TemplateFeature(
|
||||
TemplateFeatureConfig.CODEC));
|
||||
private final Holder<PlacedFeature> placedFeature;
|
||||
private final Decoration featureStep;
|
||||
private final Feature<?> feature;
|
||||
|
@ -62,12 +70,12 @@ public class BCLFeature {
|
|||
Holder<ConfiguredFeature<?, ?>> configuredFeature;
|
||||
if (!BuiltinRegistries.CONFIGURED_FEATURE.containsKey(id)) {
|
||||
configuredFeature = (Holder<ConfiguredFeature<?, ?>>) (Object) FeatureUtils.register(id.toString(),
|
||||
feature,
|
||||
configuration);
|
||||
feature,
|
||||
configuration);
|
||||
} else {
|
||||
configuredFeature = BuiltinRegistries.CONFIGURED_FEATURE
|
||||
.getHolder(ResourceKey.create(BuiltinRegistries.CONFIGURED_FEATURE.key(),
|
||||
id))
|
||||
id))
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
|
@ -75,7 +83,7 @@ public class BCLFeature {
|
|||
return PlacementUtils.register(id.toString(), configuredFeature, modifiers);
|
||||
} else {
|
||||
return BuiltinRegistries.PLACED_FEATURE.getHolder(ResourceKey.create(BuiltinRegistries.PLACED_FEATURE.key(),
|
||||
id)).orElseThrow();
|
||||
id)).orElseThrow();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -119,13 +119,13 @@ public class BCLFeatureBuilder<FC extends FeatureConfiguration, F extends Featur
|
|||
}
|
||||
|
||||
/**
|
||||
* Will place feature once in certain amount of chunks (in average).
|
||||
* Will place feature once every n-th attempts (in average).
|
||||
*
|
||||
* @param chunks amount of chunks.
|
||||
* @param n amount of attempts.
|
||||
* @return same {@link BCLFeatureBuilder} instance.
|
||||
*/
|
||||
public BCLFeatureBuilder oncePerChunks(int chunks) {
|
||||
return modifier(RarityFilter.onAverageOnceEvery(chunks));
|
||||
public BCLFeatureBuilder onceEvery(int n) {
|
||||
return modifier(RarityFilter.onAverageOnceEvery(n));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package org.betterx.bclib.api.features;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import org.betterx.bclib.api.features.config.BlockPlaceFeatureConfig;
|
||||
import org.betterx.bclib.util.BlocksHelper;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class BlockPlaceFeature<FC extends BlockPlaceFeatureConfig> extends Feature<FC> {
|
||||
public BlockPlaceFeature(Codec<FC> codec) {
|
||||
super(codec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean place(FeaturePlaceContext<FC> ctx) {
|
||||
Optional<BlockState> state = ctx.config().getRandomBlock(ctx.random());
|
||||
if (state.isPresent())
|
||||
BlocksHelper.setWithoutUpdate(ctx.level(), ctx.origin(), state.get());
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package org.betterx.bclib.api.features;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
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.RandomPatchConfiguration;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.SimpleBlockConfiguration;
|
||||
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
|
||||
|
||||
import org.betterx.bclib.api.features.config.ScatterFeatureConfig;
|
||||
|
||||
public class FastFeatures {
|
||||
|
||||
|
||||
public static BCLFeature vine(ResourceLocation location,
|
||||
boolean onFloor,
|
||||
boolean sparse,
|
||||
ScatterFeatureConfig.Builder builder) {
|
||||
return scatter(location, onFloor, sparse, builder, BCLFeature.SCATTER_ON_SOLID);
|
||||
}
|
||||
|
||||
public static BCLFeature scatter(ResourceLocation location,
|
||||
boolean onFloor,
|
||||
boolean sparse,
|
||||
ScatterFeatureConfig.Builder builder,
|
||||
Feature scatterFeature) {
|
||||
BCLFeatureBuilder fBuilder = BCLFeatureBuilder.start(location, scatterFeature);
|
||||
if (onFloor) {
|
||||
fBuilder.findSolidFloor(3).isEmptyAbove2();
|
||||
builder.onFloor();
|
||||
} else {
|
||||
fBuilder.findSolidCeil(3).isEmptyBelow2();
|
||||
builder.onCeil();
|
||||
}
|
||||
if (sparse) {
|
||||
fBuilder.onceEvery(3);
|
||||
}
|
||||
|
||||
return fBuilder
|
||||
.is(BlockPredicate.ONLY_IN_AIR_PREDICATE)
|
||||
.buildAndRegister(builder.build());
|
||||
}
|
||||
|
||||
public static BCLFeature patch(ResourceLocation location, Block block) {
|
||||
return patch(location, block, 96, 7, 3);
|
||||
}
|
||||
|
||||
public static BCLFeature
|
||||
patch(ResourceLocation location, Block block, int attempts, int xzSpread, int ySpread) {
|
||||
return patch(location,
|
||||
attempts,
|
||||
xzSpread,
|
||||
ySpread,
|
||||
Feature.SIMPLE_BLOCK,
|
||||
new SimpleBlockConfiguration(BlockStateProvider.simple(block)));
|
||||
}
|
||||
|
||||
public static BCLFeature
|
||||
patch(ResourceLocation location, Feature<NoneFeatureConfiguration> feature) {
|
||||
return patch(location, 96, 7, 3, feature, FeatureConfiguration.NONE);
|
||||
}
|
||||
|
||||
public static BCLFeature
|
||||
patch(ResourceLocation location,
|
||||
int attempts,
|
||||
int xzSpread,
|
||||
int ySpread,
|
||||
Feature<NoneFeatureConfiguration> feature) {
|
||||
return patch(location, attempts, xzSpread, ySpread, feature, FeatureConfiguration.NONE);
|
||||
}
|
||||
|
||||
public static <FC extends FeatureConfiguration> BCLFeature
|
||||
patch(ResourceLocation location,
|
||||
int attempts,
|
||||
int xzSpread,
|
||||
int ySpread,
|
||||
Feature<FC> feature,
|
||||
FC config) {
|
||||
ResourceLocation patchLocation = new ResourceLocation(location.getNamespace(), location.getPath() + "_patch");
|
||||
final BCLFeature SINGLE = BCLFeatureBuilder
|
||||
.start(location, feature)
|
||||
.findSolidFloor(Math.min(12, ySpread))
|
||||
.is(BlockPredicate.ONLY_IN_AIR_PREDICATE)
|
||||
.buildAndRegister(config);
|
||||
|
||||
return BCLFeatureBuilder
|
||||
.start(patchLocation, Feature.RANDOM_PATCH)
|
||||
.buildAndRegister(new RandomPatchConfiguration(attempts, xzSpread, ySpread, SINGLE.getPlacedFeature()));
|
||||
}
|
||||
}
|
|
@ -161,7 +161,9 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
|
|||
RandomSource random) {
|
||||
if (BlocksHelper.isFreeSpace(level, origin, direction, height, BlocksHelper::isFree)) {
|
||||
createPatchOfBaseBlocks(level, random, basePos, config);
|
||||
buildPillar(level, origin, direction, height, config, random);
|
||||
if (config.bottomBlock.canSurvive(level, origin)) {
|
||||
buildPillar(level, origin, direction, height, config, random);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,15 +7,11 @@ import net.minecraft.world.level.levelgen.feature.Feature;
|
|||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import org.betterx.bclib.BCLib;
|
||||
import org.betterx.bclib.api.features.config.TemplateFeatureConfig;
|
||||
import org.betterx.bclib.world.structures.StructureNBT;
|
||||
import org.betterx.bclib.world.structures.StructureWorldNBT;
|
||||
|
||||
public class TemplateFeature<FC extends TemplateFeatureConfig> extends Feature<FC> {
|
||||
public static final Feature<TemplateFeatureConfig> INSTANCE = BCLFeature.register(BCLib.makeID("template"),
|
||||
new TemplateFeature(
|
||||
TemplateFeatureConfig.CODEC));
|
||||
|
||||
public static <T extends TemplateFeatureConfig> BCLFeature createAndRegisterRare(ResourceLocation location,
|
||||
TemplateFeatureConfig configuration,
|
||||
|
@ -23,9 +19,9 @@ public class TemplateFeature<FC extends TemplateFeatureConfig> extends Feature<F
|
|||
|
||||
|
||||
return BCLFeatureBuilder
|
||||
.start(location, INSTANCE)
|
||||
.start(location, BCLFeature.TEMPLATE)
|
||||
.decoration(GenerationStep.Decoration.SURFACE_STRUCTURES)
|
||||
.oncePerChunks(onceEveryChunk) //discard neighboring chunks
|
||||
.onceEvery(onceEveryChunk) //discard neighboring chunks
|
||||
.count(16) //try 16 placements in chunk
|
||||
.squarePlacement() //randomize x/z in chunk
|
||||
.randomHeight10FromFloorCeil() //randomize height 10 above and 10 below max vertical
|
||||
|
@ -40,7 +36,7 @@ public class TemplateFeature<FC extends TemplateFeatureConfig> extends Feature<F
|
|||
TemplateFeatureConfig configuration,
|
||||
int count) {
|
||||
return BCLFeatureBuilder
|
||||
.start(location, INSTANCE)
|
||||
.start(location, BCLFeature.TEMPLATE)
|
||||
.decoration(GenerationStep.Decoration.SURFACE_STRUCTURES)
|
||||
.count(count)
|
||||
.squarePlacement()
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package org.betterx.bclib.api.features;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.WeightedPlacedFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.RandomFeatureConfiguration;
|
||||
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
|
||||
|
||||
public class WeightedRandomSelectorFeature extends Feature<RandomFeatureConfiguration> {
|
||||
public WeightedRandomSelectorFeature() {
|
||||
super(RandomFeatureConfiguration.CODEC);
|
||||
}
|
||||
|
||||
public boolean place(FeaturePlaceContext<RandomFeatureConfiguration> ctx) {
|
||||
final WorldGenLevel level = ctx.level();
|
||||
final ChunkGenerator generator = ctx.chunkGenerator();
|
||||
final RandomFeatureConfiguration cfg = ctx.config();
|
||||
final RandomSource random = ctx.random();
|
||||
final BlockPos pos = ctx.origin();
|
||||
|
||||
PlacedFeature selected = cfg.defaultFeature.value();
|
||||
if (!cfg.features.isEmpty()) {
|
||||
final float totalWeight = cfg.features.stream().map(w -> w.chance).reduce(0.0f, (p, c) -> p + c);
|
||||
float bar = random.nextFloat() * totalWeight;
|
||||
|
||||
for (WeightedPlacedFeature f : cfg.features) {
|
||||
selected = f.feature.value();
|
||||
bar -= f.chance;
|
||||
if (bar < 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
return selected.place(level, generator, random, pos);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package org.betterx.bclib.api.features.config;
|
||||
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.util.random.SimpleWeightedRandomList;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class BlockPlaceFeatureConfig implements FeatureConfiguration {
|
||||
public static final Codec<BlockPlaceFeatureConfig> CODEC = SimpleWeightedRandomList
|
||||
.wrappedCodec(BlockState.CODEC)
|
||||
.comapFlatMap(BlockPlaceFeatureConfig::create, cfg -> cfg.weightedList)
|
||||
.fieldOf("entries").codec();
|
||||
|
||||
private final SimpleWeightedRandomList<BlockState> weightedList;
|
||||
|
||||
private static DataResult<BlockPlaceFeatureConfig> create(SimpleWeightedRandomList<BlockState> simpleWeightedRandomList) {
|
||||
if (simpleWeightedRandomList.isEmpty()) {
|
||||
return DataResult.error("BlockPlaceFeatureConfig with no states");
|
||||
}
|
||||
return DataResult.success(new BlockPlaceFeatureConfig(simpleWeightedRandomList));
|
||||
}
|
||||
|
||||
|
||||
private static SimpleWeightedRandomList<BlockState> convert(List<BlockState> states) {
|
||||
var builder = SimpleWeightedRandomList.<BlockState>builder();
|
||||
for (BlockState s : states) builder.add(s, 1);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public BlockPlaceFeatureConfig(Block block) {
|
||||
this(block.defaultBlockState());
|
||||
}
|
||||
|
||||
public BlockPlaceFeatureConfig(BlockState state) {
|
||||
this(SimpleWeightedRandomList
|
||||
.<BlockState>builder()
|
||||
.add(state, 1)
|
||||
.build());
|
||||
}
|
||||
|
||||
public BlockPlaceFeatureConfig(List<BlockState> states) {
|
||||
this(convert(states));
|
||||
}
|
||||
|
||||
public BlockPlaceFeatureConfig(SimpleWeightedRandomList<BlockState> blocks) {
|
||||
this.weightedList = blocks;
|
||||
}
|
||||
|
||||
public Optional<BlockState> getRandomBlock(RandomSource random) {
|
||||
return this.weightedList.getRandomValue(random);
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@ import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
|
|||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import org.betterx.bclib.api.tag.CommonBlockTags;
|
||||
import org.betterx.bclib.util.BlocksHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -26,7 +25,7 @@ public class FindSolidInDirection extends PlacementModifier {
|
|||
.forGetter(a -> a.direction),
|
||||
Codec.intRange(1, 32).fieldOf("dist").orElse(12).forGetter((p) -> p.maxSearchDistance))
|
||||
.apply(instance,
|
||||
FindSolidInDirection::new));
|
||||
FindSolidInDirection::new));
|
||||
protected static final FindSolidInDirection DOWN = new FindSolidInDirection(Direction.DOWN, 6);
|
||||
protected static final FindSolidInDirection UP = new FindSolidInDirection(Direction.UP, 6);
|
||||
private final List<Direction> direction;
|
||||
|
@ -70,11 +69,12 @@ public class FindSolidInDirection extends PlacementModifier {
|
|||
BlockPos.MutableBlockPos POS = blockPos.mutable();
|
||||
Direction d = randomDirection(randomSource);
|
||||
if (BlocksHelper.findOnSurroundingSurface(placementContext.getLevel(),
|
||||
POS,
|
||||
d,
|
||||
maxSearchDistance,
|
||||
state -> state.is(CommonBlockTags.TERRAIN)))
|
||||
POS,
|
||||
d,
|
||||
maxSearchDistance,
|
||||
BlocksHelper::isTerrain)) {
|
||||
return Stream.of(POS);
|
||||
}
|
||||
|
||||
return Stream.of();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import net.minecraft.util.KeyDispatchDataCodec;
|
|||
import net.minecraft.world.level.levelgen.SurfaceRules;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import org.betterx.bclib.BCLib;
|
||||
import org.betterx.bclib.api.surface.rules.SurfaceNoiseCondition;
|
||||
import org.betterx.bclib.mixin.common.SurfaceRulesContextAccessor;
|
||||
|
@ -14,8 +15,14 @@ import org.betterx.bclib.util.MHelper;
|
|||
public class DoubleBlockSurfaceNoiseCondition extends SurfaceNoiseCondition {
|
||||
public static final DoubleBlockSurfaceNoiseCondition CONDITION = new DoubleBlockSurfaceNoiseCondition(0);
|
||||
private static final OpenSimplexNoise NOISE = new OpenSimplexNoise(4141);
|
||||
public static final KeyDispatchDataCodec<DoubleBlockSurfaceNoiseCondition> CODEC = KeyDispatchDataCodec.of(Codec.DOUBLE.fieldOf(
|
||||
"threshold").xmap(DoubleBlockSurfaceNoiseCondition::new, obj -> obj.threshold).codec());
|
||||
public static final Codec<DoubleBlockSurfaceNoiseCondition> CODEC = RecordCodecBuilder.create(instance -> instance
|
||||
.group(
|
||||
Codec.DOUBLE.fieldOf("threshold").orElse(0.0).forGetter(o -> o.threshold)
|
||||
)
|
||||
.apply(instance, DoubleBlockSurfaceNoiseCondition::new));
|
||||
|
||||
public static final KeyDispatchDataCodec<DoubleBlockSurfaceNoiseCondition> KEY_CODEC = KeyDispatchDataCodec.of(
|
||||
CODEC);
|
||||
private final double threshold;
|
||||
|
||||
public DoubleBlockSurfaceNoiseCondition(double threshold) {
|
||||
|
@ -24,7 +31,7 @@ public class DoubleBlockSurfaceNoiseCondition extends SurfaceNoiseCondition {
|
|||
|
||||
@Override
|
||||
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
|
||||
return CODEC;
|
||||
return KEY_CODEC;
|
||||
}
|
||||
|
||||
private static int lastX = Integer.MIN_VALUE;
|
||||
|
@ -47,7 +54,7 @@ public class DoubleBlockSurfaceNoiseCondition extends SurfaceNoiseCondition {
|
|||
|
||||
static {
|
||||
Registry.register(Registry.CONDITION,
|
||||
BCLib.makeID("doubleblock_surface"),
|
||||
DoubleBlockSurfaceNoiseCondition.CODEC.codec());
|
||||
BCLib.makeID("doubleblock_surface"),
|
||||
DoubleBlockSurfaceNoiseCondition.CODEC);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue