Some placement filters
This commit is contained in:
parent
4321017c25
commit
aa4133fad2
12 changed files with 318 additions and 47 deletions
|
@ -22,6 +22,7 @@ import org.betterx.bclib.recipes.CraftingRecipes;
|
||||||
import org.betterx.bclib.registry.BaseBlockEntities;
|
import org.betterx.bclib.registry.BaseBlockEntities;
|
||||||
import org.betterx.bclib.registry.BaseRegistry;
|
import org.betterx.bclib.registry.BaseRegistry;
|
||||||
import org.betterx.bclib.util.Logger;
|
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.BCLibEndBiomeSource;
|
||||||
import org.betterx.bclib.world.generator.BCLibNetherBiomeSource;
|
import org.betterx.bclib.world.generator.BCLibNetherBiomeSource;
|
||||||
import org.betterx.bclib.world.generator.GeneratorOptions;
|
import org.betterx.bclib.world.generator.GeneratorOptions;
|
||||||
|
@ -60,6 +61,7 @@ public class BCLib implements ModInitializer {
|
||||||
|
|
||||||
BCLibPatch.register();
|
BCLibPatch.register();
|
||||||
TemplatePiece.ensureStaticInitialization();
|
TemplatePiece.ensureStaticInitialization();
|
||||||
|
PlacementModifiers.ensureStaticInitialization();
|
||||||
Configs.save();
|
Configs.save();
|
||||||
if (isDevEnvironment()) {
|
if (isDevEnvironment()) {
|
||||||
Biome.BiomeBuilder builder = new Biome.BiomeBuilder()
|
Biome.BiomeBuilder builder = new Biome.BiomeBuilder()
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
package org.betterx.bclib.api.features;
|
package org.betterx.bclib.api.features;
|
||||||
|
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.data.worldgen.placement.PlacementUtils;
|
import net.minecraft.data.worldgen.placement.PlacementUtils;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.util.valueproviders.UniformInt;
|
import net.minecraft.util.valueproviders.UniformInt;
|
||||||
import net.minecraft.world.level.levelgen.GenerationStep.Decoration;
|
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.Feature;
|
||||||
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
|
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
|
||||||
import net.minecraft.world.level.levelgen.placement.*;
|
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.BCLFeature;
|
||||||
|
import org.betterx.bclib.world.features.placement.IsEmptyAboveSampledFilter;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -132,14 +136,79 @@ public class BCLFeatureBuilder<FC extends FeatureConfiguration, F extends Featur
|
||||||
return modifier(InSquarePlacement.spread());
|
return modifier(InSquarePlacement.spread());
|
||||||
}
|
}
|
||||||
|
|
||||||
public BCLFeatureBuilder distanceToTopAndBottom10() {
|
/**
|
||||||
|
* Select random height that is 10 above min Build height and 10 below max generation height
|
||||||
|
*
|
||||||
|
* @return The instance it was called on
|
||||||
|
*/
|
||||||
|
public BCLFeatureBuilder randomHeight10FromFloorCeil() {
|
||||||
return modifier(PlacementUtils.RANGE_10_10);
|
return modifier(PlacementUtils.RANGE_10_10);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BCLFeatureBuilder distanceToTopAndBottom4() {
|
/**
|
||||||
|
* Select random height that is 4 above min Build height and 10 below max generation height
|
||||||
|
*
|
||||||
|
* @return The instance it was called on
|
||||||
|
*/
|
||||||
|
public BCLFeatureBuilder randomHeight4FromFloorCeil() {
|
||||||
return modifier(PlacementUtils.RANGE_4_4);
|
return modifier(PlacementUtils.RANGE_4_4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select random height that is 8 above min Build height and 10 below max generation height
|
||||||
|
*
|
||||||
|
* @return The instance it was called on
|
||||||
|
*/
|
||||||
|
public BCLFeatureBuilder randomHeight8FromFloorCeil() {
|
||||||
|
return modifier(PlacementUtils.RANGE_8_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select random height that is above min Build height and 10 below max generation height
|
||||||
|
*
|
||||||
|
* @return The instance it was called on
|
||||||
|
*/
|
||||||
|
public BCLFeatureBuilder randomHeight() {
|
||||||
|
return modifier(PlacementUtils.FULL_RANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BCLFeatureBuilder isEmptyAbove4() {
|
||||||
|
return modifier(IsEmptyAboveSampledFilter.emptyAbove4());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BCLFeatureBuilder isEmptyAbove(int d1, int d2) {
|
||||||
|
return modifier(new IsEmptyAboveSampledFilter(d1, d2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cast a downward ray with max {@code distance} length to find the next solid Block.
|
||||||
|
*
|
||||||
|
* @param distance The maximum search Distance
|
||||||
|
* @return The instance it was called on
|
||||||
|
* @see #findSolidSurface(Direction, int) for Details
|
||||||
|
*/
|
||||||
|
public BCLFeatureBuilder findSolidFloor(int distance) {
|
||||||
|
return findSolidSurface(Direction.DOWN, distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cast a ray with max {@code distance} length to find the next solid Block. The ray will travel through replaceable
|
||||||
|
* Blocks (see {@link Material#isReplaceable()}) and will be accepted if it hits a solid one
|
||||||
|
* (see {@link Material#isSolid()} ()})
|
||||||
|
*
|
||||||
|
* @param dir The direction the ray is cast
|
||||||
|
* @param distance The maximum search Distance
|
||||||
|
* @return The instance it was called on
|
||||||
|
* @see #findSolidSurface(Direction, int) for Details
|
||||||
|
*/
|
||||||
|
public BCLFeatureBuilder findSolidSurface(Direction dir, int distance) {
|
||||||
|
return modifier(EnvironmentScanPlacement.scanningFor(dir,
|
||||||
|
BlockPredicate.solid(),
|
||||||
|
BlockPredicate.replaceable(),
|
||||||
|
distance));
|
||||||
|
}
|
||||||
|
|
||||||
public BCLFeatureBuilder heightmap() {
|
public BCLFeatureBuilder heightmap() {
|
||||||
return modifier(PlacementUtils.HEIGHTMAP);
|
return modifier(PlacementUtils.HEIGHTMAP);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package org.betterx.bclib.interfaces;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.block.Mirror;
|
||||||
|
import net.minecraft.world.level.block.Rotation;
|
||||||
|
|
||||||
|
public interface BCLPlacementContext {
|
||||||
|
Rotation bcl_getRotation();
|
||||||
|
void bcl_setRotation(Rotation bcl_rotation);
|
||||||
|
Mirror bcl_getMirror();
|
||||||
|
void bcl_setMirror(Mirror bcl_mirror);
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package org.betterx.bclib.mixin.common;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.block.Mirror;
|
||||||
|
import net.minecraft.world.level.block.Rotation;
|
||||||
|
import net.minecraft.world.level.levelgen.placement.PlacementContext;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
|
||||||
|
@Mixin(PlacementContext.class)
|
||||||
|
public class PlacementContextMixin implements org.betterx.bclib.interfaces.BCLPlacementContext {
|
||||||
|
private Rotation bcl_rotation = Rotation.NONE;
|
||||||
|
private Mirror bcl_mirror = Mirror.NONE;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rotation bcl_getRotation() {
|
||||||
|
return bcl_rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bcl_setRotation(Rotation bcl_rotation) {
|
||||||
|
this.bcl_rotation = bcl_rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mirror bcl_getMirror() {
|
||||||
|
return bcl_mirror;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bcl_setMirror(Mirror bcl_mirror) {
|
||||||
|
this.bcl_mirror = bcl_mirror;
|
||||||
|
}
|
||||||
|
}
|
|
@ -245,6 +245,22 @@ public class BlocksHelper {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int blockCount(LevelAccessor level,
|
||||||
|
BlockPos startPos,
|
||||||
|
Direction dir,
|
||||||
|
int length,
|
||||||
|
Predicate<BlockState> 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) {
|
public static boolean isLava(BlockState state) {
|
||||||
return state.getFluidState().getType() instanceof LavaFluid;
|
return state.getFluidState().getType() instanceof LavaFluid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.betterx.bclib.world.features;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
import net.minecraft.core.HolderSet;
|
import net.minecraft.core.HolderSet;
|
||||||
import net.minecraft.data.worldgen.placement.PlacementUtils;
|
import net.minecraft.data.worldgen.placement.PlacementUtils;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
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.api.tag.CommonBlockTags;
|
||||||
import org.betterx.bclib.util.BlocksHelper;
|
import org.betterx.bclib.util.BlocksHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@ -35,28 +38,32 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
|
||||||
int minPerChunk,
|
int minPerChunk,
|
||||||
int maxPerChunk,
|
int maxPerChunk,
|
||||||
T cfg,
|
T cfg,
|
||||||
Feature<T> inlineFeatures) {
|
Feature<T> inlineFeature) {
|
||||||
SimpleRandomFeatureConfiguration configuration = new SimpleRandomFeatureConfiguration(HolderSet.direct(
|
List<Holder<PlacedFeature>> set = new ArrayList<>(2);
|
||||||
PlacementUtils.inlinePlaced(inlineFeatures,
|
if (cfg.floorChance > 0) set.add(PlacementUtils.inlinePlaced(inlineFeature,
|
||||||
cfg,
|
cfg,
|
||||||
EnvironmentScanPlacement.scanningFor(Direction.DOWN,
|
EnvironmentScanPlacement.scanningFor(Direction.DOWN,
|
||||||
BlockPredicate.solid(),
|
BlockPredicate.solid(),
|
||||||
BlockPredicate.ONLY_IN_AIR_PREDICATE,
|
BlockPredicate.ONLY_IN_AIR_PREDICATE,
|
||||||
12),
|
12),
|
||||||
RandomOffsetPlacement.vertical(ConstantInt.of(1))),
|
RandomOffsetPlacement.vertical(ConstantInt.of(1))));
|
||||||
PlacementUtils.inlinePlaced(inlineFeatures,
|
|
||||||
|
if (cfg.floorChance < 1) {
|
||||||
|
set.add(PlacementUtils.inlinePlaced(inlineFeature,
|
||||||
cfg,
|
cfg,
|
||||||
EnvironmentScanPlacement.scanningFor(Direction.UP,
|
EnvironmentScanPlacement.scanningFor(Direction.UP,
|
||||||
BlockPredicate.solid(),
|
BlockPredicate.solid(),
|
||||||
BlockPredicate.ONLY_IN_AIR_PREDICATE,
|
BlockPredicate.ONLY_IN_AIR_PREDICATE,
|
||||||
12),
|
12),
|
||||||
RandomOffsetPlacement.vertical(ConstantInt.of(-1)))));
|
RandomOffsetPlacement.vertical(ConstantInt.of(-1))));
|
||||||
|
}
|
||||||
|
SimpleRandomFeatureConfiguration configuration = new SimpleRandomFeatureConfiguration(HolderSet.direct(set));
|
||||||
|
|
||||||
return BCLFeatureBuilder.start(location, SIMPLE_RANDOM_SELECTOR)
|
return BCLFeatureBuilder.start(location, SIMPLE_RANDOM_SELECTOR)
|
||||||
.decoration(GenerationStep.Decoration.VEGETAL_DECORATION)
|
.decoration(GenerationStep.Decoration.VEGETAL_DECORATION)
|
||||||
.modifier(CountPlacement.of(UniformInt.of(minPerChunk, maxPerChunk)))
|
.modifier(CountPlacement.of(UniformInt.of(minPerChunk, maxPerChunk)))
|
||||||
.modifier(InSquarePlacement.spread())
|
.modifier(InSquarePlacement.spread())
|
||||||
.distanceToTopAndBottom4()
|
.randomHeight4FromFloorCeil()
|
||||||
.modifier(CountPlacement.of(UniformInt.of(2, 5)))
|
.modifier(CountPlacement.of(UniformInt.of(2, 5)))
|
||||||
.modifier(RandomOffsetPlacement.of(
|
.modifier(RandomOffsetPlacement.of(
|
||||||
ClampedNormalInt.of(0.0f, 2.0f, -6, 6),
|
ClampedNormalInt.of(0.0f, 2.0f, -6, 6),
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
package org.betterx.bclib.world.features;
|
package org.betterx.bclib.world.features;
|
||||||
|
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.util.RandomSource;
|
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.GenerationStep;
|
||||||
import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate;
|
|
||||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
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 com.mojang.serialization.Codec;
|
||||||
import org.betterx.bclib.api.features.BCLFeatureBuilder;
|
import org.betterx.bclib.api.features.BCLFeatureBuilder;
|
||||||
|
@ -29,30 +24,28 @@ public class TemplateFeature<FC extends TemplateFeatureConfig> extends Feature<F
|
||||||
return BCLFeatureBuilder
|
return BCLFeatureBuilder
|
||||||
.start(location, INSTANCE)
|
.start(location, INSTANCE)
|
||||||
.decoration(GenerationStep.Decoration.SURFACE_STRUCTURES)
|
.decoration(GenerationStep.Decoration.SURFACE_STRUCTURES)
|
||||||
.squarePlacement()
|
.oncePerChunks(onceEveryChunk) //discard neighboring chunks
|
||||||
.distanceToTopAndBottom10()
|
.count(16) //try 16 placements in chunk
|
||||||
.modifier(EnvironmentScanPlacement.scanningFor(Direction.DOWN,
|
.squarePlacement() //randomize x/z in chunk
|
||||||
BlockPredicate.solid(),
|
.randomHeight10FromFloorCeil() //randomize height 10 above and 10 below max vertical
|
||||||
BlockPredicate.matchesBlocks(Blocks.AIR,
|
.findSolidFloor(12) //cast downward ray to find solid surface
|
||||||
Blocks.WATER,
|
.isEmptyAbove4() //make sure we have 4 free blocks above
|
||||||
Blocks.LAVA),
|
.onlyInBiome() //ensure that we still are in the correct biome
|
||||||
12))
|
|
||||||
.modifier(BiomeFilter.biome())
|
|
||||||
.oncePerChunks(onceEveryChunk)
|
|
||||||
.buildAndRegister(configuration);
|
.buildAndRegister(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends TemplateFeatureConfig> BCLFeature createAndRegister(ResourceLocation location,
|
public static <T extends TemplateFeatureConfig> BCLFeature createAndRegister(ResourceLocation location,
|
||||||
TemplateFeatureConfig configuration,
|
TemplateFeatureConfig configuration,
|
||||||
int count) {
|
int count) {
|
||||||
|
|
||||||
|
|
||||||
return BCLFeatureBuilder
|
return BCLFeatureBuilder
|
||||||
.start(location, INSTANCE)
|
.start(location, INSTANCE)
|
||||||
.decoration(GenerationStep.Decoration.SURFACE_STRUCTURES)
|
.decoration(GenerationStep.Decoration.SURFACE_STRUCTURES)
|
||||||
.count(count)
|
.count(count)
|
||||||
.squarePlacement()
|
.squarePlacement()
|
||||||
.distanceToTopAndBottom10()
|
.randomHeight10FromFloorCeil()
|
||||||
|
.findSolidFloor(12) //cast downward ray to find solid surface
|
||||||
|
.isEmptyAbove4()
|
||||||
.onlyInBiome()
|
.onlyInBiome()
|
||||||
.buildAndRegister(configuration);
|
.buildAndRegister(configuration);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<IsEmptyAboveSampledFilter> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<MinEmptyFilter> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<IsEmptyAboveSampledFilter> IS_EMPTY_ABOVE_SAMPLED_FILTER = register(
|
||||||
|
"is_empty_above_sampled_filter",
|
||||||
|
IsEmptyAboveSampledFilter.CODEC);
|
||||||
|
|
||||||
|
public static final PlacementModifierType<MinEmptyFilter> MIN_EMPTY_FILTER = register(
|
||||||
|
"min_empty_filter",
|
||||||
|
MinEmptyFilter.CODEC);
|
||||||
|
|
||||||
|
|
||||||
|
private static <P extends PlacementModifier> PlacementModifierType<P> register(String path, Codec<P> codec) {
|
||||||
|
return register(BCLib.makeID(path), codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <P extends PlacementModifier> PlacementModifierType<P> register(ResourceLocation location,
|
||||||
|
Codec<P> codec) {
|
||||||
|
return Registry.register(Registry.PLACEMENT_MODIFIERS, location, () -> codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ensureStaticInitialization() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import net.minecraft.util.StringRepresentable;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
|
|
||||||
public enum StructurePlacementType implements StringRepresentable {
|
public enum StructurePlacementType implements StringRepresentable {
|
||||||
FLOOR, WALL, CEIL, LAVA, UNDER, FLOOR_FREE_ABOVE;
|
FLOOR, WALL, CEIL, LAVA, UNDER;
|
||||||
|
|
||||||
public static final Codec<StructurePlacementType> CODEC = StringRepresentable.fromEnum(StructurePlacementType::values);
|
public static final Codec<StructurePlacementType> CODEC = StringRepresentable.fromEnum(StructurePlacementType::values);
|
||||||
|
|
||||||
|
|
|
@ -104,8 +104,6 @@ public class StructureWorldNBT extends StructureNBT {
|
||||||
return canGenerateUnder(level, pos, rotation);
|
return canGenerateUnder(level, pos, rotation);
|
||||||
else if (type == StructurePlacementType.CEIL)
|
else if (type == StructurePlacementType.CEIL)
|
||||||
return canGenerateCeil(level, pos, rotation);
|
return canGenerateCeil(level, pos, rotation);
|
||||||
else if (type == StructurePlacementType.FLOOR_FREE_ABOVE)
|
|
||||||
return canGenerateFloorFreeAbove(level, pos, rotation);
|
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue