diff --git a/src/main/java/org/betterx/bclib/api/features/BCLCommonFeatures.java b/src/main/java/org/betterx/bclib/api/features/BCLCommonFeatures.java index b8701e3b..6eb2b817 100644 --- a/src/main/java/org/betterx/bclib/api/features/BCLCommonFeatures.java +++ b/src/main/java/org/betterx/bclib/api/features/BCLCommonFeatures.java @@ -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); } diff --git a/src/main/java/org/betterx/bclib/api/features/BCLFeature.java b/src/main/java/org/betterx/bclib/api/features/BCLFeature.java index ff41bb66..2989dd39 100644 --- a/src/main/java/org/betterx/bclib/api/features/BCLFeature.java +++ b/src/main/java/org/betterx/bclib/api/features/BCLFeature.java @@ -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 SCATTER_ON_SOLID = register( BCLib.makeID("scatter_on_solid"), - new ScatterFeature<>(ScatterFeatureConfig.OnSolid.CODEC) - ); + new ScatterFeature<>(ScatterFeatureConfig.OnSolid.CODEC)); + + public static final Feature RANDOM_SELECT = register( + BCLib.makeID("random_select"), + new WeightedRandomSelectorFeature()); + public static final Feature TEMPLATE = register(BCLib.makeID("template"), + new TemplateFeature( + TemplateFeatureConfig.CODEC)); private final Holder placedFeature; private final Decoration featureStep; private final Feature feature; @@ -62,12 +70,12 @@ public class BCLFeature { Holder> configuredFeature; if (!BuiltinRegistries.CONFIGURED_FEATURE.containsKey(id)) { configuredFeature = (Holder>) (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(); } } diff --git a/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java b/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java index a7f961eb..7950458c 100644 --- a/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java +++ b/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java @@ -119,13 +119,13 @@ public class BCLFeatureBuilder extends Feature { + public BlockPlaceFeature(Codec codec) { + super(codec); + } + + @Override + public boolean place(FeaturePlaceContext ctx) { + Optional state = ctx.config().getRandomBlock(ctx.random()); + if (state.isPresent()) + BlocksHelper.setWithoutUpdate(ctx.level(), ctx.origin(), state.get()); + return true; + } +} diff --git a/src/main/java/org/betterx/bclib/api/features/FastFeatures.java b/src/main/java/org/betterx/bclib/api/features/FastFeatures.java new file mode 100644 index 00000000..407dc243 --- /dev/null +++ b/src/main/java/org/betterx/bclib/api/features/FastFeatures.java @@ -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 feature) { + return patch(location, 96, 7, 3, feature, FeatureConfiguration.NONE); + } + + public static BCLFeature + patch(ResourceLocation location, + int attempts, + int xzSpread, + int ySpread, + Feature feature) { + return patch(location, attempts, xzSpread, ySpread, feature, FeatureConfiguration.NONE); + } + + public static BCLFeature + patch(ResourceLocation location, + int attempts, + int xzSpread, + int ySpread, + Feature 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())); + } +} diff --git a/src/main/java/org/betterx/bclib/api/features/ScatterFeature.java b/src/main/java/org/betterx/bclib/api/features/ScatterFeature.java index 7588998a..bdf7eb0b 100644 --- a/src/main/java/org/betterx/bclib/api/features/ScatterFeature.java +++ b/src/main/java/org/betterx/bclib/api/features/ScatterFeature.java @@ -161,7 +161,9 @@ public class ScatterFeature 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); + } } } diff --git a/src/main/java/org/betterx/bclib/api/features/TemplateFeature.java b/src/main/java/org/betterx/bclib/api/features/TemplateFeature.java index 67a967b7..f3ae8e1a 100644 --- a/src/main/java/org/betterx/bclib/api/features/TemplateFeature.java +++ b/src/main/java/org/betterx/bclib/api/features/TemplateFeature.java @@ -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 extends Feature { - public static final Feature INSTANCE = BCLFeature.register(BCLib.makeID("template"), - new TemplateFeature( - TemplateFeatureConfig.CODEC)); public static BCLFeature createAndRegisterRare(ResourceLocation location, TemplateFeatureConfig configuration, @@ -23,9 +19,9 @@ public class TemplateFeature extends Feature extends Feature { + public WeightedRandomSelectorFeature() { + super(RandomFeatureConfiguration.CODEC); + } + + public boolean place(FeaturePlaceContext 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); + } +} diff --git a/src/main/java/org/betterx/bclib/api/features/config/BlockPlaceFeatureConfig.java b/src/main/java/org/betterx/bclib/api/features/config/BlockPlaceFeatureConfig.java new file mode 100644 index 00000000..c37e5e51 --- /dev/null +++ b/src/main/java/org/betterx/bclib/api/features/config/BlockPlaceFeatureConfig.java @@ -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 CODEC = SimpleWeightedRandomList + .wrappedCodec(BlockState.CODEC) + .comapFlatMap(BlockPlaceFeatureConfig::create, cfg -> cfg.weightedList) + .fieldOf("entries").codec(); + + private final SimpleWeightedRandomList weightedList; + + private static DataResult create(SimpleWeightedRandomList simpleWeightedRandomList) { + if (simpleWeightedRandomList.isEmpty()) { + return DataResult.error("BlockPlaceFeatureConfig with no states"); + } + return DataResult.success(new BlockPlaceFeatureConfig(simpleWeightedRandomList)); + } + + + private static SimpleWeightedRandomList convert(List states) { + var builder = SimpleWeightedRandomList.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 + .builder() + .add(state, 1) + .build()); + } + + public BlockPlaceFeatureConfig(List states) { + this(convert(states)); + } + + public BlockPlaceFeatureConfig(SimpleWeightedRandomList blocks) { + this.weightedList = blocks; + } + + public Optional getRandomBlock(RandomSource random) { + return this.weightedList.getRandomValue(random); + } +} diff --git a/src/main/java/org/betterx/bclib/api/features/placement/FindSolidInDirection.java b/src/main/java/org/betterx/bclib/api/features/placement/FindSolidInDirection.java index d73ebb96..c5fad618 100644 --- a/src/main/java/org/betterx/bclib/api/features/placement/FindSolidInDirection.java +++ b/src/main/java/org/betterx/bclib/api/features/placement/FindSolidInDirection.java @@ -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; @@ -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(); } diff --git a/src/main/java/org/betterx/bclib/world/surface/DoubleBlockSurfaceNoiseCondition.java b/src/main/java/org/betterx/bclib/world/surface/DoubleBlockSurfaceNoiseCondition.java index 30b63787..b12dfbc6 100644 --- a/src/main/java/org/betterx/bclib/world/surface/DoubleBlockSurfaceNoiseCondition.java +++ b/src/main/java/org/betterx/bclib/world/surface/DoubleBlockSurfaceNoiseCondition.java @@ -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 CODEC = KeyDispatchDataCodec.of(Codec.DOUBLE.fieldOf( - "threshold").xmap(DoubleBlockSurfaceNoiseCondition::new, obj -> obj.threshold).codec()); + public static final Codec 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 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 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); } }