Features for Crimson Glowing Woods

This commit is contained in:
Frank 2022-06-04 14:05:02 +02:00
parent 4f4ac722b1
commit 90921451dd
5 changed files with 47 additions and 14 deletions

View file

@ -27,7 +27,7 @@ public class BCLFeature {
BCLib.makeID("scatter_on_solid"), BCLib.makeID("scatter_on_solid"),
new ScatterFeature<>(ScatterFeatureConfig.OnSolid.CODEC)); new ScatterFeature<>(ScatterFeatureConfig.OnSolid.CODEC));
public static final Feature<RandomFeatureConfiguration> RANDOM_SELECT = register( public static final Feature<RandomFeatureConfiguration> RANDOM_SELECTOR = register(
BCLib.makeID("random_select"), BCLib.makeID("random_select"),
new WeightedRandomSelectorFeature()); new WeightedRandomSelectorFeature());
public static final Feature<TemplateFeatureConfig> TEMPLATE = register(BCLib.makeID("template"), public static final Feature<TemplateFeatureConfig> TEMPLATE = register(BCLib.makeID("template"),

View file

@ -26,14 +26,13 @@ public class WeightedRandomSelectorFeature extends Feature<RandomFeatureConfigur
if (!cfg.features.isEmpty()) { if (!cfg.features.isEmpty()) {
final float totalWeight = cfg.features.stream().map(w -> w.chance).reduce(0.0f, (p, c) -> p + c); final float totalWeight = cfg.features.stream().map(w -> w.chance).reduce(0.0f, (p, c) -> p + c);
float bar = random.nextFloat() * totalWeight; float bar = random.nextFloat() * totalWeight;
for (WeightedPlacedFeature f : cfg.features) { for (WeightedPlacedFeature f : cfg.features) {
selected = f.feature.value(); selected = f.feature.value();
bar -= f.chance; bar -= f.chance;
if (bar < 0) break; if (bar < 0) break;
} }
} }
return selected.place(level, generator, random, pos); return selected.place(level, generator, random, pos);
} }
} }

View file

@ -1,6 +1,8 @@
package org.betterx.bclib.api.features.placement; package org.betterx.bclib.api.features.placement;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate; import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate;
@ -11,29 +13,40 @@ import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.Optional;
public class Is extends PlacementFilter { public class Is extends PlacementFilter {
public static final Codec<Is> CODEC = RecordCodecBuilder.create((instance) -> instance public static final Codec<Is> CODEC = RecordCodecBuilder.create((instance) -> instance
.group( .group(
BlockPredicate.CODEC BlockPredicate.CODEC
.fieldOf("predicate") .fieldOf("predicate")
.forGetter(cfg -> cfg.predicate) .forGetter(cfg -> cfg.predicate),
Vec3i.CODEC
.optionalFieldOf("offset")
.forGetter(cfg -> cfg.offset)
) )
.apply(instance, Is::new)); .apply(instance, Is::new));
private final BlockPredicate predicate; private final BlockPredicate predicate;
private final Optional<Vec3i> offset;
public Is(BlockPredicate predicate) { public Is(BlockPredicate predicate, Optional<Vec3i> offset) {
this.predicate = predicate; this.predicate = predicate;
this.offset = offset;
} }
public static Is simple(BlockPredicate predicate) { public static Is simple(BlockPredicate predicate) {
return new Is(predicate); return new Is(predicate, Optional.empty());
}
public static Is below(BlockPredicate predicate) {
return new Is(predicate, Optional.of(Direction.DOWN.getNormal()));
} }
@Override @Override
protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) { protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) {
WorldGenLevel level = ctx.getLevel(); WorldGenLevel level = ctx.getLevel();
return predicate.test(level, pos); return predicate.test(level, offset.map(v -> pos.offset(v.getX(), v.getY(), v.getZ())).orElse(pos));
} }
@Override @Override

View file

@ -10,24 +10,40 @@ import net.minecraft.world.level.levelgen.placement.PlacementModifier;
import net.minecraft.world.level.levelgen.placement.PlacementModifierType; import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import org.betterx.bclib.util.BlocksHelper; import org.betterx.bclib.util.BlocksHelper;
import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
public class OnEveryLayer public class OnEveryLayer
extends PlacementModifier { extends PlacementModifier {
private static OnEveryLayer INSTANCE = new OnEveryLayer(); private static OnEveryLayer INSTANCE = new OnEveryLayer(Optional.empty(), Optional.empty());
public static final Codec<OnEveryLayer> CODEC = Codec.unit(() -> INSTANCE); private static OnEveryLayer INSTANCE_MIN_4 = new OnEveryLayer(Optional.of(4), Optional.empty());
public static final Codec<OnEveryLayer> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
Codec.INT.optionalFieldOf("min").forGetter(o -> o.minHeight),
Codec.INT.optionalFieldOf("max").forGetter(o -> o.maxHeight)
).apply(instance, OnEveryLayer::new));
private OnEveryLayer() { private final Optional<Integer> minHeight;
private final Optional<Integer> maxHeight;
private OnEveryLayer(Optional<Integer> minHeight, Optional<Integer> maxHeight) {
this.minHeight = minHeight;
this.maxHeight = maxHeight;
} }
public static OnEveryLayer simple() { public static OnEveryLayer simple() {
return INSTANCE; return INSTANCE;
} }
public static OnEveryLayer min4() {
return INSTANCE_MIN_4;
}
@Override @Override
public Stream<BlockPos> getPositions(PlacementContext ctx, public Stream<BlockPos> getPositions(PlacementContext ctx,
RandomSource random, RandomSource random,
@ -37,10 +53,14 @@ public class OnEveryLayer
final int z = pos.getZ(); final int z = pos.getZ();
final int x = pos.getX(); final int x = pos.getX();
int y = ctx.getHeight(Heightmap.Types.MOTION_BLOCKING, x, z); final int levelHeight = ctx.getHeight(Heightmap.Types.MOTION_BLOCKING, x, z);
final int minLevelHeight = ctx.getMinBuildHeight();
int y = maxHeight.map(h -> Math.min(levelHeight, h)).orElse(levelHeight);
final int minHeight = this.minHeight.map(h -> Math.max(minLevelHeight, h)).orElse(minLevelHeight);
int layerY; int layerY;
do { do {
layerY = OnEveryLayer.findOnGroundYPosition(ctx, x, y, z); layerY = OnEveryLayer.findOnGroundYPosition(ctx, x, y, z, minHeight);
if (layerY != Integer.MAX_VALUE) { if (layerY != Integer.MAX_VALUE) {
builder.add(new BlockPos(x, layerY, z)); builder.add(new BlockPos(x, layerY, z));
y = layerY - 1; y = layerY - 1;
@ -55,10 +75,10 @@ public class OnEveryLayer
return PlacementModifiers.ON_EVERY_LAYER; return PlacementModifiers.ON_EVERY_LAYER;
} }
private static int findOnGroundYPosition(PlacementContext ctx, int x, int startY, int z) { private static int findOnGroundYPosition(PlacementContext ctx, int x, int startY, int z, int minHeight) {
BlockPos.MutableBlockPos mPos = new BlockPos.MutableBlockPos(x, startY, z); BlockPos.MutableBlockPos mPos = new BlockPos.MutableBlockPos(x, startY, z);
BlockState nowState = ctx.getBlockState(mPos); BlockState nowState = ctx.getBlockState(mPos);
for (int y = startY; y >= ctx.getMinBuildHeight() + 1; --y) { for (int y = startY; y >= minHeight + 1; --y) {
mPos.setY(y - 1); mPos.setY(y - 1);
BlockState belowState = ctx.getBlockState(mPos); BlockState belowState = ctx.getBlockState(mPos);
if (BlocksHelper.isTerrain(belowState) && BlocksHelper.isFreeOrFluid(nowState) && !belowState.is(Blocks.BEDROCK)) { if (BlocksHelper.isTerrain(belowState) && BlocksHelper.isFreeOrFluid(nowState) && !belowState.is(Blocks.BEDROCK)) {

View file

@ -58,6 +58,7 @@ public class CommonBlockTags {
TagAPI.BLOCKS.addOtherTags(TERRAIN, TagAPI.BLOCKS.addOtherTags(TERRAIN,
BlockTags.DRIPSTONE_REPLACEABLE, BlockTags.DRIPSTONE_REPLACEABLE,
BlockTags.BASE_STONE_OVERWORLD, BlockTags.BASE_STONE_OVERWORLD,
BlockTags.NYLIUM,
NETHER_STONES, NETHER_STONES,
NETHER_ORES, NETHER_ORES,
SOUL_GROUND, SOUL_GROUND,