From aa4133fad2d91e2ba1cf189792090696df1b738f Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 2 Jun 2022 11:17:07 +0200 Subject: [PATCH] Some placement filters --- src/main/java/org/betterx/bclib/BCLib.java | 16 ++-- .../bclib/api/features/BCLFeatureBuilder.java | 73 ++++++++++++++++++- .../bclib/interfaces/BCLPlacementContext.java | 11 +++ .../mixin/common/PlacementContextMixin.java | 34 +++++++++ .../org/betterx/bclib/util/BlocksHelper.java | 16 ++++ .../bclib/world/features/ScatterFeature.java | 41 ++++++----- .../bclib/world/features/TemplateFeature.java | 29 +++----- .../placement/IsEmptyAboveSampledFilter.java | 51 +++++++++++++ .../features/placement/MinEmptyFilter.java | 56 ++++++++++++++ .../placement/PlacementModifiers.java | 34 +++++++++ .../structures/StructurePlacementType.java | 2 +- .../world/structures/StructureWorldNBT.java | 2 - 12 files changed, 318 insertions(+), 47 deletions(-) create mode 100644 src/main/java/org/betterx/bclib/interfaces/BCLPlacementContext.java create mode 100644 src/main/java/org/betterx/bclib/mixin/common/PlacementContextMixin.java create mode 100644 src/main/java/org/betterx/bclib/world/features/placement/IsEmptyAboveSampledFilter.java create mode 100644 src/main/java/org/betterx/bclib/world/features/placement/MinEmptyFilter.java create mode 100644 src/main/java/org/betterx/bclib/world/features/placement/PlacementModifiers.java diff --git a/src/main/java/org/betterx/bclib/BCLib.java b/src/main/java/org/betterx/bclib/BCLib.java index ac43126a..f81bafec 100644 --- a/src/main/java/org/betterx/bclib/BCLib.java +++ b/src/main/java/org/betterx/bclib/BCLib.java @@ -22,6 +22,7 @@ import org.betterx.bclib.recipes.CraftingRecipes; import org.betterx.bclib.registry.BaseBlockEntities; import org.betterx.bclib.registry.BaseRegistry; import org.betterx.bclib.util.Logger; +import org.betterx.bclib.world.features.placement.PlacementModifiers; import org.betterx.bclib.world.generator.BCLibEndBiomeSource; import org.betterx.bclib.world.generator.BCLibNetherBiomeSource; import org.betterx.bclib.world.generator.GeneratorOptions; @@ -50,16 +51,17 @@ public class BCLib implements ModInitializer { AnvilRecipe.register(); DataExchangeAPI.registerDescriptors(List.of( - HelloClient.DESCRIPTOR, - HelloServer.DESCRIPTOR, - RequestFiles.DESCRIPTOR, - SendFiles.DESCRIPTOR, - Chunker.DESCRIPTOR - ) - ); + HelloClient.DESCRIPTOR, + HelloServer.DESCRIPTOR, + RequestFiles.DESCRIPTOR, + SendFiles.DESCRIPTOR, + Chunker.DESCRIPTOR + ) + ); BCLibPatch.register(); TemplatePiece.ensureStaticInitialization(); + PlacementModifiers.ensureStaticInitialization(); Configs.save(); if (isDevEnvironment()) { Biome.BiomeBuilder builder = new Biome.BiomeBuilder() 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 68127ddb..4738e886 100644 --- a/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java +++ b/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java @@ -1,14 +1,18 @@ package org.betterx.bclib.api.features; +import net.minecraft.core.Direction; import net.minecraft.data.worldgen.placement.PlacementUtils; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.valueproviders.UniformInt; import net.minecraft.world.level.levelgen.GenerationStep.Decoration; +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.placement.*; +import net.minecraft.world.level.material.Material; import org.betterx.bclib.world.features.BCLFeature; +import org.betterx.bclib.world.features.placement.IsEmptyAboveSampledFilter; import java.util.ArrayList; import java.util.List; @@ -132,14 +136,79 @@ public class BCLFeatureBuilder freeSurface) { + MutableBlockPos POS = startPos.mutable(); + for (int len = 1; len < length; len++) { + POS.move(dir, 1); + if (!freeSurface.test(level.getBlockState(POS))) { + return len - 1; + } + + } + return length; + } + public static boolean isLava(BlockState state) { return state.getFluidState().getType() instanceof LavaFluid; } diff --git a/src/main/java/org/betterx/bclib/world/features/ScatterFeature.java b/src/main/java/org/betterx/bclib/world/features/ScatterFeature.java index 16c91deb..c9e9766e 100644 --- a/src/main/java/org/betterx/bclib/world/features/ScatterFeature.java +++ b/src/main/java/org/betterx/bclib/world/features/ScatterFeature.java @@ -2,6 +2,7 @@ package org.betterx.bclib.world.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; @@ -25,6 +26,8 @@ import org.betterx.bclib.api.features.BCLFeatureBuilder; import org.betterx.bclib.api.tag.CommonBlockTags; import org.betterx.bclib.util.BlocksHelper; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.function.Consumer; @@ -35,28 +38,32 @@ public class ScatterFeature int minPerChunk, int maxPerChunk, T cfg, - Feature inlineFeatures) { - SimpleRandomFeatureConfiguration configuration = new SimpleRandomFeatureConfiguration(HolderSet.direct( - PlacementUtils.inlinePlaced(inlineFeatures, - cfg, - EnvironmentScanPlacement.scanningFor(Direction.DOWN, - BlockPredicate.solid(), - BlockPredicate.ONLY_IN_AIR_PREDICATE, - 12), - RandomOffsetPlacement.vertical(ConstantInt.of(1))), - PlacementUtils.inlinePlaced(inlineFeatures, - cfg, - EnvironmentScanPlacement.scanningFor(Direction.UP, - BlockPredicate.solid(), - BlockPredicate.ONLY_IN_AIR_PREDICATE, - 12), - RandomOffsetPlacement.vertical(ConstantInt.of(-1))))); + Feature inlineFeature) { + List> set = new ArrayList<>(2); + if (cfg.floorChance > 0) set.add(PlacementUtils.inlinePlaced(inlineFeature, + cfg, + EnvironmentScanPlacement.scanningFor(Direction.DOWN, + BlockPredicate.solid(), + 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.solid(), + 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()) - .distanceToTopAndBottom4() + .randomHeight4FromFloorCeil() .modifier(CountPlacement.of(UniformInt.of(2, 5))) .modifier(RandomOffsetPlacement.of( ClampedNormalInt.of(0.0f, 2.0f, -6, 6), diff --git a/src/main/java/org/betterx/bclib/world/features/TemplateFeature.java b/src/main/java/org/betterx/bclib/world/features/TemplateFeature.java index 34bc01b8..8a93d521 100644 --- a/src/main/java/org/betterx/bclib/world/features/TemplateFeature.java +++ b/src/main/java/org/betterx/bclib/world/features/TemplateFeature.java @@ -1,15 +1,10 @@ package org.betterx.bclib.world.features; -import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.Blocks; 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.placement.BiomeFilter; -import net.minecraft.world.level.levelgen.placement.EnvironmentScanPlacement; import com.mojang.serialization.Codec; import org.betterx.bclib.api.features.BCLFeatureBuilder; @@ -29,30 +24,28 @@ public class TemplateFeature extends Feature BCLFeature createAndRegister(ResourceLocation location, TemplateFeatureConfig configuration, int count) { - - return BCLFeatureBuilder .start(location, INSTANCE) .decoration(GenerationStep.Decoration.SURFACE_STRUCTURES) .count(count) .squarePlacement() - .distanceToTopAndBottom10() + .randomHeight10FromFloorCeil() + .findSolidFloor(12) //cast downward ray to find solid surface + .isEmptyAbove4() .onlyInBiome() .buildAndRegister(configuration); } diff --git a/src/main/java/org/betterx/bclib/world/features/placement/IsEmptyAboveSampledFilter.java b/src/main/java/org/betterx/bclib/world/features/placement/IsEmptyAboveSampledFilter.java new file mode 100644 index 00000000..ea36b026 --- /dev/null +++ b/src/main/java/org/betterx/bclib/world/features/placement/IsEmptyAboveSampledFilter.java @@ -0,0 +1,51 @@ +package org.betterx.bclib.world.features.placement; + +import net.minecraft.core.BlockPos; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.levelgen.placement.PlacementContext; +import net.minecraft.world.level.levelgen.placement.PlacementFilter; +import net.minecraft.world.level.levelgen.placement.PlacementModifierType; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +/** + * Tests if there is air at two locations above the tested block position + */ +public class IsEmptyAboveSampledFilter extends PlacementFilter { + private static final IsEmptyAboveSampledFilter DEFAULT = new IsEmptyAboveSampledFilter(4, 2); + public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance + .group( + Codec.intRange(1, 32).fieldOf("d1").orElse(2).forGetter((p) -> p.distance1), + Codec.intRange(1, 32).fieldOf("d2").orElse(4).forGetter((p) -> p.distance1) + ) + .apply(instance, IsEmptyAboveSampledFilter::new)); + + public static PlacementFilter emptyAbove4() { + return DEFAULT; + } + + public IsEmptyAboveSampledFilter(int d1, int d2) { + this.distance1 = d1; + this.distance2 = d2; + } + + private final int distance1; + private final int distance2; + + + @Override + protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) { + WorldGenLevel level = ctx.getLevel(); + if (level.isEmptyBlock(pos.above(distance1)) && level.isEmptyBlock(pos.above(distance2))) { + return true; + } + return false; + } + + @Override + public PlacementModifierType type() { + return PlacementModifiers.IS_EMPTY_ABOVE_SAMPLED_FILTER; + } +} diff --git a/src/main/java/org/betterx/bclib/world/features/placement/MinEmptyFilter.java b/src/main/java/org/betterx/bclib/world/features/placement/MinEmptyFilter.java new file mode 100644 index 00000000..3c8656d8 --- /dev/null +++ b/src/main/java/org/betterx/bclib/world/features/placement/MinEmptyFilter.java @@ -0,0 +1,56 @@ +package org.betterx.bclib.world.features.placement; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.levelgen.placement.PlacementContext; +import net.minecraft.world.level.levelgen.placement.PlacementFilter; +import net.minecraft.world.level.levelgen.placement.PlacementModifier; +import net.minecraft.world.level.levelgen.placement.PlacementModifierType; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import org.betterx.bclib.util.BlocksHelper; + +public class MinEmptyFilter extends PlacementFilter { + private static MinEmptyFilter DOWN = new MinEmptyFilter(Direction.DOWN, 12); + public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance + .group( + Direction.CODEC.fieldOf("dir").orElse(Direction.DOWN).forGetter((p) -> p.direction), + Codec.intRange(1, 32).fieldOf("dist").orElse(12).forGetter((p) -> p.maxSearchDistance) + ) + .apply(instance, MinEmptyFilter::new)); + + private final Direction direction; + private final int maxSearchDistance; + + protected MinEmptyFilter(Direction direction, int maxSearchDistance) { + this.direction = direction; + this.maxSearchDistance = maxSearchDistance; + } + + public PlacementModifier down() { + return DOWN; + } + + public PlacementModifier down(int dist) { + return new MinEmptyFilter(Direction.DOWN, dist); + } + + @Override + protected boolean shouldPlace(PlacementContext ctx, RandomSource randomSource, BlockPos pos) { + int h = BlocksHelper.blockCount( + ctx.getLevel(), + pos.relative(direction), + direction, + maxSearchDistance, + state -> state.getMaterial().isReplaceable() + ); + return false; + } + + @Override + public PlacementModifierType type() { + return PlacementModifiers.MIN_EMPTY_FILTER; + } +} diff --git a/src/main/java/org/betterx/bclib/world/features/placement/PlacementModifiers.java b/src/main/java/org/betterx/bclib/world/features/placement/PlacementModifiers.java new file mode 100644 index 00000000..a7e200ee --- /dev/null +++ b/src/main/java/org/betterx/bclib/world/features/placement/PlacementModifiers.java @@ -0,0 +1,34 @@ +package org.betterx.bclib.world.features.placement; + +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.levelgen.placement.PlacementModifier; +import net.minecraft.world.level.levelgen.placement.PlacementModifierType; + +import com.mojang.serialization.Codec; +import org.betterx.bclib.BCLib; + +public class PlacementModifiers { + public static final PlacementModifierType IS_EMPTY_ABOVE_SAMPLED_FILTER = register( + "is_empty_above_sampled_filter", + IsEmptyAboveSampledFilter.CODEC); + + public static final PlacementModifierType MIN_EMPTY_FILTER = register( + "min_empty_filter", + MinEmptyFilter.CODEC); + + + private static

PlacementModifierType

register(String path, Codec

codec) { + return register(BCLib.makeID(path), codec); + } + + public static

PlacementModifierType

register(ResourceLocation location, + Codec

codec) { + return Registry.register(Registry.PLACEMENT_MODIFIERS, location, () -> codec); + } + + public static void ensureStaticInitialization() { + + } +} + diff --git a/src/main/java/org/betterx/bclib/world/structures/StructurePlacementType.java b/src/main/java/org/betterx/bclib/world/structures/StructurePlacementType.java index 33767cd2..adb48ad7 100644 --- a/src/main/java/org/betterx/bclib/world/structures/StructurePlacementType.java +++ b/src/main/java/org/betterx/bclib/world/structures/StructurePlacementType.java @@ -5,7 +5,7 @@ import net.minecraft.util.StringRepresentable; import com.mojang.serialization.Codec; public enum StructurePlacementType implements StringRepresentable { - FLOOR, WALL, CEIL, LAVA, UNDER, FLOOR_FREE_ABOVE; + FLOOR, WALL, CEIL, LAVA, UNDER; public static final Codec CODEC = StringRepresentable.fromEnum(StructurePlacementType::values); diff --git a/src/main/java/org/betterx/bclib/world/structures/StructureWorldNBT.java b/src/main/java/org/betterx/bclib/world/structures/StructureWorldNBT.java index b6010fe0..58bc2b0f 100644 --- a/src/main/java/org/betterx/bclib/world/structures/StructureWorldNBT.java +++ b/src/main/java/org/betterx/bclib/world/structures/StructureWorldNBT.java @@ -104,8 +104,6 @@ public class StructureWorldNBT extends StructureNBT { return canGenerateUnder(level, pos, rotation); else if (type == StructurePlacementType.CEIL) return canGenerateCeil(level, pos, rotation); - else if (type == StructurePlacementType.FLOOR_FREE_ABOVE) - return canGenerateFloorFreeAbove(level, pos, rotation); else return false; }