Migrated Feature Code to new BCLib API

This commit is contained in:
Frank 2022-07-01 16:54:17 +02:00
parent 031a14f278
commit 5c3a9986bc
45 changed files with 1363 additions and 629 deletions

View file

@ -5,66 +5,89 @@ import org.betterx.bclib.api.v3.levelgen.features.BCLFeatureBuilder;
import org.betterx.betterend.BetterEnd;
import org.betterx.betterend.integration.Integrations;
import org.betterx.betterend.integration.byg.BYGBlocks;
import org.betterx.betterend.world.features.SinglePlantFeature;
import org.betterx.betterend.world.features.VineFeature;
import org.betterx.betterend.world.features.WallPlantFeature;
import org.betterx.betterend.world.features.WallPlantOnLogFeature;
import org.betterx.betterend.registry.EndFeatures;
import org.betterx.betterend.world.features.*;
import net.minecraft.resources.ResourceLocation;
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;
public class BYGFeatures {
public static final BCLFeature OLD_BULBIS_TREE = redisterVegetation(
public static final BCLFeature<OldBulbisTreeFeature, NoneFeatureConfiguration> OLD_BULBIS_TREE = redisterVegetation(
"old_bulbis_tree",
new OldBulbisTreeFeature(),
EndFeatures.inlineBuild("old_bulbis_tree_feature", new OldBulbisTreeFeature()),
1
);
public static final BCLFeature IVIS_SPROUT = redisterVegetation(
public static final BCLFeature<SinglePlantFeature, SinglePlantFeatureConfig> IVIS_SPROUT = redisterVegetation(
"ivis_sprout",
new SinglePlantFeature(Integrations.BYG.getBlock("ivis_sprout"), 6, 2),
EndFeatures.SINGLE_PLANT_FEATURE,
new SinglePlantFeatureConfig(Integrations.BYG.getBlock("ivis_sprout"), 6, 2),
6
);
public static final BCLFeature IVIS_VINE = redisterVegetation(
public static final BCLFeature<VineFeature, VineFeatureConfig> IVIS_VINE = redisterVegetation(
"ivis_vine",
new VineFeature(BYGBlocks.IVIS_VINE, 24),
EndFeatures.VINE_FEATURE,
new VineFeatureConfig(BYGBlocks.IVIS_VINE, 24),
5
);
public static final BCLFeature IVIS_MOSS = redisterVegetation(
public static final BCLFeature<WallPlantFeature, WallPlantFeatureConfig> IVIS_MOSS = redisterVegetation(
"ivis_moss",
new WallPlantFeature(BYGBlocks.IVIS_MOSS, 6),
EndFeatures.WALL_PLANT_FEATURE,
new WallPlantFeatureConfig(BYGBlocks.IVIS_MOSS, 6),
1
);
public static final BCLFeature IVIS_MOSS_WOOD = redisterVegetation(
public static final BCLFeature<WallPlantOnLogFeature, WallPlantFeatureConfig> IVIS_MOSS_WOOD = redisterVegetation(
"ivis_moss_wood",
new WallPlantOnLogFeature(BYGBlocks.IVIS_MOSS, 6),
EndFeatures.WALL_PLANT_ON_LOG_FEATURE,
new WallPlantFeatureConfig(BYGBlocks.IVIS_MOSS, 6),
15
);
public static final BCLFeature NIGHTSHADE_MOSS = redisterVegetation(
public static final BCLFeature<WallPlantFeature, WallPlantFeatureConfig> NIGHTSHADE_MOSS = redisterVegetation(
"nightshade_moss",
new WallPlantFeature(BYGBlocks.NIGHTSHADE_MOSS, 5),
EndFeatures.WALL_PLANT_FEATURE,
new WallPlantFeatureConfig(BYGBlocks.NIGHTSHADE_MOSS, 5),
2
);
public static final BCLFeature NIGHTSHADE_MOSS_WOOD = redisterVegetation(
public static final BCLFeature<WallPlantOnLogFeature, WallPlantFeatureConfig> NIGHTSHADE_MOSS_WOOD = redisterVegetation(
"nightshade_moss_wood",
new WallPlantOnLogFeature(BYGBlocks.NIGHTSHADE_MOSS, 5),
EndFeatures.WALL_PLANT_ON_LOG_FEATURE,
new WallPlantFeatureConfig(BYGBlocks.NIGHTSHADE_MOSS, 5),
8
);
public static final BCLFeature NIGHTSHADE_REDWOOD_TREE = redisterVegetation(
public static final BCLFeature<NightshadeRedwoodTreeFeature, NoneFeatureConfiguration> NIGHTSHADE_REDWOOD_TREE = redisterVegetation(
"nightshade_redwood_tree",
new NightshadeRedwoodTreeFeature(),
1
);
public static final BCLFeature BIG_ETHER_TREE = redisterVegetation("big_ether_tree", new BigEtherTreeFeature(), 1);
public static final BCLFeature<BigEtherTreeFeature, NoneFeatureConfiguration> BIG_ETHER_TREE = redisterVegetation(
"big_ether_tree",
new BigEtherTreeFeature(),
1
);
public static void register() {
}
private static BCLFeature redisterVegetation(String name, Feature<NoneFeatureConfiguration> feature, int density) {
private static <F extends Feature<NoneFeatureConfiguration>> BCLFeature<F, NoneFeatureConfiguration> redisterVegetation(
String name,
F feature,
int density
) {
return redisterVegetation(name, feature, NoneFeatureConfiguration.NONE, density);
}
private static <F extends Feature<FC>, FC extends FeatureConfiguration> BCLFeature<F, FC> redisterVegetation(
String name,
F feature,
FC config,
int density
) {
ResourceLocation id = BetterEnd.makeID(name);
return BCLFeatureBuilder
.start(id, feature)
.configuration(config)
.buildAndRegister()
.place()
.countMax(density)

File diff suppressed because it is too large Load diff

View file

@ -3,14 +3,15 @@ package org.betterx.betterend.world.biome.cave;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeBuilder;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeBuilder.BiomeSupplier;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeSettings;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import org.betterx.bclib.api.v3.levelgen.features.BCLFeature;
import org.betterx.bclib.api.v3.levelgen.features.BCLFeatureBuilder;
import org.betterx.bclib.util.WeightedList;
import org.betterx.betterend.BetterEnd;
import org.betterx.betterend.registry.EndFeatures;
import org.betterx.betterend.registry.EndSounds;
import org.betterx.betterend.world.biome.EndBiome;
import org.betterx.betterend.world.features.terrain.caves.CaveChunkPopulatorFeature;
import org.betterx.betterend.world.features.terrain.caves.CaveChunkPopulatorFeatureConfig;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
@ -28,11 +29,13 @@ public class EndCaveBiome extends EndBiome {
@Override
protected void addCustomBuildData(BCLBiomeBuilder builder) {
BCLFeature feature = BCLFeatureBuilder
BCLFeature<CaveChunkPopulatorFeature, CaveChunkPopulatorFeatureConfig> feature = BCLFeatureBuilder
.start(
BetterEnd.makeID(ID.getPath() + "_cave_populator"),
new CaveChunkPopulatorFeature(() -> (EndCaveBiome) BiomeAPI.getBiome(ID))
EndFeatures.CAVE_CHUNK_POPULATOR
)
.configuration(new CaveChunkPopulatorFeatureConfig(ID))
.buildAndRegister()
.place()
.decoration(GenerationStep.Decoration.RAW_GENERATION)

View file

@ -26,8 +26,8 @@ public class LushAuroraCaveBiome extends EndCaveBiome.Config {
this.addCeilFeature(EndFeatures.CAVE_BUSH, 1);
this.addCeilFeature(EndFeatures.CAVE_PUMPKIN, 1);
this.addCeilFeature(EndFeatures.RUBINEA, 3);
this.addCeilFeature(EndFeatures.MAGNULA, 1);
this.addCeilFeature(EndFeatures.RUBINEA.getFeature(), 3);
this.addCeilFeature(EndFeatures.MAGNULA.getFeature(), 1);
this.addCeilFeature(EndFeatures.END_STONE_STALACTITE_CAVEMOSS, 10);
}

View file

@ -1,5 +1,6 @@
package org.betterx.betterend.world.features;
import org.betterx.bclib.api.v2.levelgen.features.features.DefaultFeature;
import org.betterx.bclib.util.BlocksHelper;
import org.betterx.bclib.util.MHelper;
import org.betterx.betterend.blocks.basis.EndPlantWithAgeBlock;
@ -9,16 +10,17 @@ import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
public class BlueVineFeature extends ScatterFeature {
public class BlueVineFeature extends ScatterFeature<ScatterFeatureConfig> {
private boolean small;
public BlueVineFeature() {
super(5);
super(ScatterFeatureConfig.CODEC);
}
@Override
@SuppressWarnings("deprecation")
public boolean canGenerate(
ScatterFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
@ -30,11 +32,11 @@ public class BlueVineFeature extends ScatterFeature {
center.getZ() - blockPos.getZ()
) / radius * 0.6F + random.nextFloat() * 0.4F;
small = d > 0.5F;
return EndBlocks.BLUE_VINE_SEED.canSurvive(AIR, world, blockPos);
return EndBlocks.BLUE_VINE_SEED.canSurvive(DefaultFeature.AIR, world, blockPos);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
public void generate(ScatterFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
if (small) {
BlocksHelper.setWithoutUpdate(
world,

View file

@ -1,13 +1,20 @@
package org.betterx.betterend.world.features;
import org.betterx.bclib.util.StructureHelper;
import org.betterx.betterend.util.LootTableUtil;
import org.betterx.worlds.together.tag.v3.CommonBlockTags;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
@ -17,20 +24,89 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProc
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import java.util.List;
import org.jetbrains.annotations.Nullable;
public class BuildingListFeature extends ListFeature {
public BuildingListFeature(List<StructureInfo> list, BlockState defaultBlock) {
super(list, defaultBlock);
public class BuildingListFeature extends NBTFeature<BuildingListFeatureConfig> {
private StructureInfo selected;
public BuildingListFeature() {
super(BuildingListFeatureConfig.CODEC);
}
@Override
protected void addStructureData(StructurePlaceSettings data) {
super.addStructureData(data);
data.addProcessor(new ChestProcessor());
}
@Override
protected StructureTemplate getStructure(
BuildingListFeatureConfig cfg,
WorldGenLevel world,
BlockPos pos,
RandomSource random
) {
selected = cfg.getRandom(random);
return selected.getStructure();
}
@Override
protected boolean canSpawn(WorldGenLevel world, BlockPos pos, RandomSource random) {
int cx = pos.getX() >> 4;
int cz = pos.getZ() >> 4;
return ((cx + cz) & 1) == 0 && pos.getY() > 58
&& world.getBlockState(pos).isAir()
&& world.getBlockState(pos.below()).is(CommonBlockTags.TERRAIN);
}
@Override
protected Rotation getRotation(WorldGenLevel world, BlockPos pos, RandomSource random) {
return Rotation.getRandom(random);
}
@Override
protected Mirror getMirror(WorldGenLevel world, BlockPos pos, RandomSource random) {
return Mirror.values()[random.nextInt(3)];
}
@Override
protected int getYOffset(StructureTemplate structure, WorldGenLevel world, BlockPos pos, RandomSource random) {
return selected.offsetY;
}
@Override
protected TerrainMerge getTerrainMerge(WorldGenLevel world, BlockPos pos, RandomSource random) {
return selected.terrainMerge;
}
public static final class StructureInfo {
public static final Codec<StructureInfo> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
Codec.STRING.fieldOf("path").forGetter(o -> o.structurePath),
Codec.INT.fieldOf("offset_y").forGetter(o -> o.offsetY),
TerrainMerge.CODEC.fieldOf("terrain_merger").forGetter(o -> o.terrainMerge)
)
.apply(instance, StructureInfo::new));
public final TerrainMerge terrainMerge;
public final String structurePath;
public final int offsetY;
private StructureTemplate structure;
public StructureInfo(String structurePath, int offsetY, TerrainMerge terrainMerge) {
this.terrainMerge = terrainMerge;
this.structurePath = structurePath;
this.offsetY = offsetY;
}
public StructureTemplate getStructure() {
if (structure == null) {
structure = StructureHelper.readStructure(structurePath);
}
return structure;
}
}
class ChestProcessor extends StructureProcessor {
@Nullable
@Override

View file

@ -0,0 +1,31 @@
package org.betterx.betterend.world.features;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState;
import java.util.List;
public class BuildingListFeatureConfig extends NBTFeatureConfig {
public static final Codec<BuildingListFeatureConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
ExtraCodecs.nonEmptyList(BuildingListFeature.StructureInfo.CODEC.listOf())
.fieldOf("structures")
.forGetter(a -> a.list),
BlockState.CODEC.fieldOf("default").forGetter(o -> o.defaultBlock)
)
.apply(instance, BuildingListFeatureConfig::new)
);
protected final List<BuildingListFeature.StructureInfo> list;
public BuildingListFeatureConfig(List<BuildingListFeature.StructureInfo> list, BlockState defaultBlock) {
super(defaultBlock);
this.list = list;
}
public BuildingListFeature.StructureInfo getRandom(RandomSource random) {
return this.list.get(random.nextInt(this.list.size()));
}
}

View file

@ -1,12 +1,6 @@
package org.betterx.betterend.world.features;
import net.minecraft.world.level.block.Block;
public class CharniaFeature extends UnderwaterPlantFeature {
public CharniaFeature(Block plant) {
super(plant, 6);
}
@Override
protected int getChance() {
return 3;

View file

@ -1,10 +1,10 @@
package org.betterx.betterend.world.features;
import org.betterx.bclib.api.v2.levelgen.features.features.DefaultFeature;
import org.betterx.bclib.util.MHelper;
import org.betterx.bclib.util.StructureErode;
import org.betterx.bclib.util.StructureHelper;
import org.betterx.betterend.util.BlockFixer;
import org.betterx.betterend.world.biome.EndBiome;
import org.betterx.worlds.together.tag.v3.CommonBlockTags;
import net.minecraft.core.BlockPos;
@ -17,23 +17,27 @@ import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.templatesystem.*;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import net.minecraft.world.level.material.Material;
public class CrashedShipFeature extends NBTFeature {
public class CrashedShipFeature extends NBTFeature<NBTFeatureConfig> {
private static final StructureProcessor REPLACER;
private static final String STRUCTURE_PATH = "/data/minecraft/structures/end_city/ship.nbt";
private StructureTemplate structure;
public CrashedShipFeature() {
super(EndBiome.Config.DEFAULT_MATERIAL.getTopMaterial());
super(NBTFeatureConfig.CODEC);
}
@Override
protected StructureTemplate getStructure(WorldGenLevel world, BlockPos pos, RandomSource random) {
protected StructureTemplate getStructure(
NBTFeatureConfig cfg,
WorldGenLevel world,
BlockPos pos,
RandomSource random
) {
if (structure == null) {
structure = world.getLevel().getStructureManager().getOrCreate(new ResourceLocation("end_city/ship"));
if (structure == null) {
@ -76,7 +80,7 @@ public class CrashedShipFeature extends NBTFeature {
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featureConfig) {
public boolean place(FeaturePlaceContext<NBTFeatureConfig> featureConfig) {
final RandomSource random = featureConfig.random();
BlockPos center = featureConfig.origin();
final WorldGenLevel world = featureConfig.level();
@ -88,7 +92,7 @@ public class CrashedShipFeature extends NBTFeature {
return false;
}
StructureTemplate structure = getStructure(world, center, random);
StructureTemplate structure = getStructure(featureConfig.config(), world, center, random);
Rotation rotation = getRotation(world, center, random);
Mirror mirror = getMirror(world, center, random);
BlockPos offset = StructureTemplate.transform(
@ -135,7 +139,7 @@ public class CrashedShipFeature extends NBTFeature {
) {
BlockState state = structureBlockInfo2.state;
if (state.is(Blocks.SPAWNER) || state.getMaterial().equals(Material.WOOL)) {
return new StructureBlockInfo(structureBlockInfo2.pos, AIR, null);
return new StructureBlockInfo(structureBlockInfo2.pos, DefaultFeature.AIR, null);
}
return structureBlockInfo2;
}

View file

@ -7,22 +7,19 @@ import org.betterx.bclib.util.MHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public class DoublePlantFeature extends ScatterFeature {
private final Block smallPlant;
private final Block largePlant;
private Block plant;
public class DoublePlantFeature extends ScatterFeature<DoublePlantFeatureConfig> {
private BlockState plant;
public DoublePlantFeature() {
super(DoublePlantFeatureConfig.CODEC);
public DoublePlantFeature(Block smallPlant, Block largePlant, int radius) {
super(radius);
this.smallPlant = smallPlant;
this.largePlant = largePlant;
}
@Override
public boolean canGenerate(
DoublePlantFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
@ -33,16 +30,21 @@ public class DoublePlantFeature extends ScatterFeature {
center.getX() - blockPos.getX(),
center.getZ() - blockPos.getZ()
) / radius * 0.6F + random.nextFloat() * 0.4F;
plant = d < 0.5F ? largePlant : smallPlant;
plant = d < 0.5F ? cfg.getLargePlantState(random, blockPos) : cfg.getSmallPlantState(random, blockPos);
//noinspection deprecation
return plant.canSurvive(plant.defaultBlockState(), world, blockPos);
return plant.getBlock().canSurvive(plant, world, blockPos);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
if (plant instanceof BaseDoublePlantBlock) {
public void generate(
DoublePlantFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos blockPos
) {
if (plant.getBlock() instanceof BaseDoublePlantBlock) {
int rot = random.nextInt(4);
BlockState state = plant.defaultBlockState().setValue(BaseDoublePlantBlock.ROTATION, rot);
BlockState state = plant.setValue(BaseDoublePlantBlock.ROTATION, rot);
BlocksHelper.setWithoutUpdate(world, blockPos, state);
BlocksHelper.setWithoutUpdate(world, blockPos.above(), state.setValue(BaseDoublePlantBlock.TOP, true));
} else {

View file

@ -0,0 +1,44 @@
package org.betterx.betterend.world.features;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider;
public class DoublePlantFeatureConfig extends ScatterFeatureConfig {
public static final Codec<DoublePlantFeatureConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
BlockStateProvider.CODEC.fieldOf("small_state").forGetter(o -> o.smallPlant),
BlockStateProvider.CODEC.fieldOf("large_state").forGetter(o -> o.largePlant),
Codec.INT.fieldOf("radius").forGetter(o -> o.radius)
)
.apply(
instance,
DoublePlantFeatureConfig::new
));
public final BlockStateProvider smallPlant;
public final BlockStateProvider largePlant;
public DoublePlantFeatureConfig(Block smallPlant, Block largePlant, int radius) {
this(SimpleStateProvider.simple(smallPlant), SimpleStateProvider.simple(largePlant), radius);
}
public DoublePlantFeatureConfig(BlockStateProvider smallPlant, BlockStateProvider largePlant, int radius) {
super(radius);
this.smallPlant = smallPlant;
this.largePlant = largePlant;
}
BlockState getLargePlantState(RandomSource rnd, BlockPos pos) {
return largePlant.getState(rnd, pos);
}
BlockState getSmallPlantState(RandomSource rnd, BlockPos pos) {
return smallPlant.getState(rnd, pos);
}
}

View file

@ -7,13 +7,13 @@ import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
public class EndLilyFeature extends UnderwaterPlantScatter {
public EndLilyFeature(int radius) {
super(radius);
public class EndLilyFeature extends UnderwaterPlantScatter<ScatterFeatureConfig> {
public EndLilyFeature() {
super(ScatterFeatureConfig.CODEC);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
public void generate(ScatterFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
EndLilySeedBlock seed = (EndLilySeedBlock) EndBlocks.END_LILY_SEED;
seed.grow(world, random, blockPos);
}

View file

@ -7,13 +7,13 @@ import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
public class EndLotusFeature extends UnderwaterPlantScatter {
public EndLotusFeature(int radius) {
super(radius);
public class EndLotusFeature extends UnderwaterPlantScatter<ScatterFeatureConfig> {
public EndLotusFeature() {
super(ScatterFeatureConfig.CODEC);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
public void generate(ScatterFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
EndLotusSeedBlock seed = (EndLotusSeedBlock) EndBlocks.END_LOTUS_SEED;
seed.grow(world, random, blockPos);
}

View file

@ -1,5 +1,6 @@
package org.betterx.betterend.world.features;
import org.betterx.bclib.api.v2.levelgen.features.features.DefaultFeature;
import org.betterx.bclib.blocks.BlockProperties.TripleShape;
import org.betterx.bclib.util.BlocksHelper;
import org.betterx.betterend.blocks.EndLotusLeafBlock;
@ -13,13 +14,13 @@ import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
public class EndLotusLeafFeature extends ScatterFeature {
public EndLotusLeafFeature(int radius) {
super(radius);
public class EndLotusLeafFeature extends ScatterFeature<ScatterFeatureConfig> {
public EndLotusLeafFeature() {
super(ScatterFeatureConfig.CODEC);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
public void generate(ScatterFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
if (canGenerate(world, blockPos)) {
generateLeaf(world, blockPos);
}
@ -31,8 +32,8 @@ public class EndLotusLeafFeature extends ScatterFeature {
}
@Override
protected BlockPos getCenterGround(WorldGenLevel world, BlockPos pos) {
return getPosOnSurface(world, pos);
protected BlockPos getCenterGround(ScatterFeatureConfig cfg, WorldGenLevel world, BlockPos pos) {
return DefaultFeature.getPosOnSurface(world, pos);
}
private void generateLeaf(WorldGenLevel world, BlockPos pos) {
@ -75,6 +76,7 @@ public class EndLotusLeafFeature extends ScatterFeature {
@Override
public boolean canGenerate(
ScatterFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,

View file

@ -14,12 +14,8 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
public class FilaluxFeature extends SkyScatterFeature {
public FilaluxFeature() {
super(10);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
public void generate(ScatterFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
BlockState vine = EndBlocks.FILALUX.defaultBlockState();
BlockState wings = EndBlocks.FILALUX_WINGS.defaultBlockState();
BlocksHelper.setWithoutUpdate(world, blockPos, EndBlocks.FILALUX_LANTERN);

View file

@ -1,5 +1,6 @@
package org.betterx.betterend.world.features;
import org.betterx.bclib.api.v2.levelgen.features.features.DefaultFeature;
import org.betterx.betterend.blocks.basis.EndPlantWithAgeBlock;
import org.betterx.betterend.registry.EndBlocks;
@ -7,13 +8,14 @@ import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
public class GlowPillarFeature extends ScatterFeature {
public class GlowPillarFeature extends ScatterFeature<ScatterFeatureConfig> {
public GlowPillarFeature() {
super(9);
super(ScatterFeatureConfig.CODEC);
}
@Override
public boolean canGenerate(
ScatterFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
@ -21,11 +23,13 @@ public class GlowPillarFeature extends ScatterFeature {
float radius
) {
//noinspection deprecation
return EndBlocks.GLOWING_PILLAR_SEED.canSurvive(AIR, world, blockPos);
return EndBlocks.GLOWING_PILLAR_SEED.canSurvive(DefaultFeature.AIR, world, blockPos);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
public void generate(
ScatterFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos
) {
EndPlantWithAgeBlock seed = ((EndPlantWithAgeBlock) EndBlocks.GLOWING_PILLAR_SEED);
seed.growAdult(world, random, blockPos);
}

View file

@ -7,13 +7,13 @@ import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
public class HydraluxFeature extends UnderwaterPlantScatter {
public HydraluxFeature(int radius) {
super(radius);
public class HydraluxFeature extends UnderwaterPlantScatter<ScatterFeatureConfig> {
public HydraluxFeature() {
super(ScatterFeatureConfig.CODEC);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
public void generate(ScatterFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
HydraluxSaplingBlock seed = (HydraluxSaplingBlock) EndBlocks.HYDRALUX_SAPLING;
seed.grow(world, random, blockPos);
}

View file

@ -1,26 +1,27 @@
package org.betterx.betterend.world.features;
import org.betterx.bclib.api.v2.levelgen.features.features.DefaultFeature;
import org.betterx.bclib.util.BlocksHelper;
import org.betterx.bclib.util.MHelper;
import org.betterx.betterend.util.GlobalState;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
public abstract class InvertedScatterFeature extends DefaultFeature {
private final int radius;
public abstract class InvertedScatterFeature<FC extends ScatterFeatureConfig> extends Feature<FC> {
public InvertedScatterFeature(int radius) {
this.radius = radius;
public InvertedScatterFeature(Codec<FC> codec) {
super(codec);
}
public abstract boolean canGenerate(
FC cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
@ -28,10 +29,11 @@ public abstract class InvertedScatterFeature extends DefaultFeature {
float radius
);
public abstract void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos);
public abstract void generate(FC cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos);
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featureConfig) {
public boolean place(FeaturePlaceContext<FC> featureConfig) {
FC cfg = featureConfig.config();
final MutableBlockPos POS = GlobalState.stateForThread().POS;
final RandomSource random = featureConfig.random();
final BlockPos center = featureConfig.origin();
@ -41,7 +43,7 @@ public abstract class InvertedScatterFeature extends DefaultFeature {
for (int y = maxY; y > minY; y--) {
POS.set(center.getX(), y, center.getZ());
if (world.getBlockState(POS).isAir() && !world.getBlockState(POS.above()).isAir()) {
float r = MHelper.randRange(radius * 0.5F, radius, random);
float r = MHelper.randRange(cfg.radius * 0.5F, cfg.radius, random);
int count = MHelper.floor(r * r * MHelper.randRange(0.5F, 1.5F, random));
for (int i = 0; i < count; i++) {
float pr = r * (float) Math.sqrt(random.nextFloat());
@ -54,8 +56,8 @@ public abstract class InvertedScatterFeature extends DefaultFeature {
if (up > 14) continue;
POS.setY(POS.getY() + up);
if (canGenerate(world, random, center, POS, r)) {
generate(world, random, POS);
if (canGenerate(cfg, world, random, center, POS, r)) {
generate(cfg, world, random, POS);
}
}
}

View file

@ -1,5 +1,6 @@
package org.betterx.betterend.world.features;
import org.betterx.bclib.api.v2.levelgen.features.features.DefaultFeature;
import org.betterx.betterend.blocks.basis.EndPlantWithAgeBlock;
import org.betterx.betterend.registry.EndBlocks;
@ -7,13 +8,14 @@ import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
public class LanceleafFeature extends ScatterFeature {
public class LanceleafFeature extends ScatterFeature<ScatterFeatureConfig> {
public LanceleafFeature() {
super(7);
super(ScatterFeatureConfig.CODEC);
}
@Override
public boolean canGenerate(
ScatterFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
@ -21,11 +23,11 @@ public class LanceleafFeature extends ScatterFeature {
float radius
) {
//noinspection deprecation
return EndBlocks.LANCELEAF_SEED.canSurvive(AIR, world, blockPos);
return EndBlocks.LANCELEAF_SEED.canSurvive(DefaultFeature.AIR, world, blockPos);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
public void generate(ScatterFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
EndPlantWithAgeBlock seed = ((EndPlantWithAgeBlock) EndBlocks.LANCELEAF_SEED);
seed.growAdult(world, random, blockPos);
}

View file

@ -1,86 +0,0 @@
package org.betterx.betterend.world.features;
import org.betterx.bclib.util.StructureHelper;
import org.betterx.worlds.together.tag.v3.CommonBlockTags;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import java.util.List;
public class ListFeature extends NBTFeature {
private final List<StructureInfo> list;
private StructureInfo selected;
public ListFeature(List<StructureInfo> list, BlockState defaultBlock) {
super(defaultBlock);
this.list = list;
}
@Override
protected StructureTemplate getStructure(WorldGenLevel world, BlockPos pos, RandomSource random) {
selected = list.get(random.nextInt(list.size()));
return selected.getStructure();
}
@Override
protected boolean canSpawn(WorldGenLevel world, BlockPos pos, RandomSource random) {
int cx = pos.getX() >> 4;
int cz = pos.getZ() >> 4;
return ((cx + cz) & 1) == 0 && pos.getY() > 58
&& world.getBlockState(pos).isAir()
&& world.getBlockState(pos.below()).is(CommonBlockTags.TERRAIN);
}
@Override
protected Rotation getRotation(WorldGenLevel world, BlockPos pos, RandomSource random) {
return Rotation.getRandom(random);
}
@Override
protected Mirror getMirror(WorldGenLevel world, BlockPos pos, RandomSource random) {
return Mirror.values()[random.nextInt(3)];
}
@Override
protected int getYOffset(StructureTemplate structure, WorldGenLevel world, BlockPos pos, RandomSource random) {
return selected.offsetY;
}
@Override
protected TerrainMerge getTerrainMerge(WorldGenLevel world, BlockPos pos, RandomSource random) {
return selected.terrainMerge;
}
@Override
protected void addStructureData(StructurePlaceSettings data) {
}
public static final class StructureInfo {
public final TerrainMerge terrainMerge;
public final String structurePath;
public final int offsetY;
private StructureTemplate structure;
public StructureInfo(String structurePath, int offsetY, TerrainMerge terrainMerge) {
this.terrainMerge = terrainMerge;
this.structurePath = structurePath;
this.offsetY = offsetY;
}
public StructureTemplate getStructure() {
if (structure == null) {
structure = StructureHelper.readStructure(structurePath);
}
return structure;
}
}
}

View file

@ -11,15 +11,15 @@ import net.minecraft.world.level.block.state.BlockState;
import java.util.function.Function;
public class MengerSpongeFeature extends UnderwaterPlantScatter {
public class MengerSpongeFeature extends UnderwaterPlantScatter<ScatterFeatureConfig> {
private static final Function<BlockState, Boolean> REPLACE;
public MengerSpongeFeature(int radius) {
super(radius);
public MengerSpongeFeature() {
super(ScatterFeatureConfig.CODEC);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
public void generate(ScatterFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
BlocksHelper.setWithoutUpdate(world, blockPos, EndBlocks.MENGER_SPONGE_WET);
if (random.nextBoolean()) {
for (Direction dir : BlocksHelper.DIRECTIONS) {

View file

@ -6,6 +6,7 @@ import org.betterx.bclib.api.v2.levelgen.structures.templatesystem.DestructionSt
import org.betterx.bclib.util.BlocksHelper;
import org.betterx.worlds.together.tag.v3.CommonBlockTags;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.core.Direction;
@ -16,13 +17,14 @@ import net.minecraft.nbt.NbtIo;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
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 net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
@ -30,17 +32,14 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
import java.io.IOException;
import java.io.InputStream;
//TODO: 1.19 Check if we can merge this with the new TemplateFeature!
public abstract class NBTFeature extends DefaultFeature {
private final BlockState defaultBlock;
public NBTFeature(BlockState defaultBlock) {
this.defaultBlock = defaultBlock;
public abstract class NBTFeature<FC extends NBTFeatureConfig> extends Feature<FC> {
public NBTFeature(Codec<FC> codec) {
super(codec);
}
protected static final DestructionStructureProcessor DESTRUCTION = new DestructionStructureProcessor();
protected abstract StructureTemplate getStructure(WorldGenLevel world, BlockPos pos, RandomSource random);
protected abstract StructureTemplate getStructure(FC cfg, WorldGenLevel world, BlockPos pos, RandomSource random);
protected abstract boolean canSpawn(WorldGenLevel world, BlockPos pos, RandomSource random);
@ -72,25 +71,26 @@ public abstract class NBTFeature extends DefaultFeature {
}
protected int getAverageY(WorldGenLevel world, BlockPos center) {
int y = getYOnSurface(world, center.getX(), center.getZ());
y += getYOnSurface(world, center.getX() - 2, center.getZ() - 2);
y += getYOnSurface(world, center.getX() + 2, center.getZ() - 2);
y += getYOnSurface(world, center.getX() - 2, center.getZ() + 2);
y += getYOnSurface(world, center.getX() + 2, center.getZ() + 2);
int y = DefaultFeature.getYOnSurface(world, center.getX(), center.getZ());
y += DefaultFeature.getYOnSurface(world, center.getX() - 2, center.getZ() - 2);
y += DefaultFeature.getYOnSurface(world, center.getX() + 2, center.getZ() - 2);
y += DefaultFeature.getYOnSurface(world, center.getX() - 2, center.getZ() + 2);
y += DefaultFeature.getYOnSurface(world, center.getX() + 2, center.getZ() + 2);
return y / 5;
}
protected int getAverageYWG(WorldGenLevel world, BlockPos center) {
int y = getYOnSurfaceWG(world, center.getX(), center.getZ());
y += getYOnSurfaceWG(world, center.getX() - 2, center.getZ() - 2);
y += getYOnSurfaceWG(world, center.getX() + 2, center.getZ() - 2);
y += getYOnSurfaceWG(world, center.getX() - 2, center.getZ() + 2);
y += getYOnSurfaceWG(world, center.getX() + 2, center.getZ() + 2);
int y = DefaultFeature.getYOnSurfaceWG(world, center.getX(), center.getZ());
y += DefaultFeature.getYOnSurfaceWG(world, center.getX() - 2, center.getZ() - 2);
y += DefaultFeature.getYOnSurfaceWG(world, center.getX() + 2, center.getZ() - 2);
y += DefaultFeature.getYOnSurfaceWG(world, center.getX() - 2, center.getZ() + 2);
y += DefaultFeature.getYOnSurfaceWG(world, center.getX() + 2, center.getZ() + 2);
return y / 5;
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
public boolean place(FeaturePlaceContext<FC> context) {
FC cfg = context.config();
WorldGenLevel world = context.level();
RandomSource random = context.random();
BlockPos center = context.origin();
@ -103,7 +103,7 @@ public abstract class NBTFeature extends DefaultFeature {
}
int posY = center.getY() + 1;
StructureTemplate structure = getStructure(world, center, random);
StructureTemplate structure = getStructure(cfg, world, center, random);
Rotation rotation = getRotation(world, center, random);
Mirror mirror = getMirror(world, center, random);
BlockPos offset = StructureTemplate.transform(
@ -160,7 +160,7 @@ public abstract class NBTFeature extends DefaultFeature {
Holder<Biome> b = world.getBiome(mut);
BlockState top = (isTop
? BiomeAPI.findTopMaterial(b)
: BiomeAPI.findUnderMaterial(b)).orElse(defaultBlock);
: BiomeAPI.findUnderMaterial(b)).orElse(cfg.defaultBlock);
BlocksHelper.setWithoutUpdate(world, mut, top);
} else {
BlocksHelper.setWithoutUpdate(world, mut, state);
@ -169,7 +169,7 @@ public abstract class NBTFeature extends DefaultFeature {
if (isTerrain(state) && state.getMaterial().isSolidBlocking()) {
if (merge == TerrainMerge.SURFACE) {
Holder<Biome> b = world.getBiome(mut);
BlockState bottom = BiomeAPI.findUnderMaterial(b).orElse(defaultBlock);
BlockState bottom = BiomeAPI.findUnderMaterial(b).orElse(cfg.defaultBlock);
BlocksHelper.setWithoutUpdate(world, mut, bottom);
} else {
BlocksHelper.setWithoutUpdate(world, mut, state);
@ -222,9 +222,11 @@ public abstract class NBTFeature extends DefaultFeature {
return template;
}
public enum TerrainMerge {
public enum TerrainMerge implements StringRepresentable {
NONE, SURFACE, OBJECT;
public static final Codec<TerrainMerge> CODEC = StringRepresentable.fromEnum(TerrainMerge::values);
public static TerrainMerge getFromString(String type) {
if (type.equals("surface")) {
return SURFACE;
@ -234,5 +236,10 @@ public abstract class NBTFeature extends DefaultFeature {
return NONE;
}
}
@Override
public String getSerializedName() {
return this.name();
}
}
}

View file

@ -0,0 +1,20 @@
package org.betterx.betterend.world.features;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
public class NBTFeatureConfig implements FeatureConfiguration {
public static final Codec<NBTFeatureConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
BlockState.CODEC.fieldOf("default").forGetter(o -> o.defaultBlock)
)
.apply(instance, NBTFeatureConfig::new)
);
public final BlockState defaultBlock;
public NBTFeatureConfig(BlockState defaultBlock) {
this.defaultBlock = defaultBlock;
}
}

View file

@ -6,21 +6,21 @@ import org.betterx.bclib.util.MHelper;
import org.betterx.betterend.util.GlobalState;
import org.betterx.worlds.together.tag.v3.CommonBlockTags;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
public abstract class ScatterFeature extends DefaultFeature {
private final int radius;
public ScatterFeature(int radius) {
this.radius = radius;
public abstract class ScatterFeature<FC extends ScatterFeatureConfig> extends Feature<FC> {
public ScatterFeature(Codec<FC> codec) {
super(codec);
}
public abstract boolean canGenerate(
FC cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
@ -28,19 +28,19 @@ public abstract class ScatterFeature extends DefaultFeature {
float radius
);
public abstract void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos);
public abstract void generate(FC cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos);
protected BlockPos getCenterGround(WorldGenLevel world, BlockPos pos) {
return getPosOnSurfaceWG(world, pos);
protected BlockPos getCenterGround(FC cfg, WorldGenLevel world, BlockPos pos) {
return DefaultFeature.getPosOnSurfaceWG(world, pos);
}
protected boolean canSpawn(WorldGenLevel world, BlockPos pos) {
protected boolean canSpawn(FC cfg, WorldGenLevel world, BlockPos pos) {
if (pos.getY() < 5) {
return false;
} else return world.getBlockState(pos.below()).is(CommonBlockTags.END_STONES);
}
protected boolean getGroundPlant(WorldGenLevel world, MutableBlockPos pos) {
protected boolean getGroundPlant(FC cfg, WorldGenLevel world, MutableBlockPos pos) {
int down = BlocksHelper.downRay(world, pos, 16);
if (down > Math.abs(getYOffset() * 2)) {
return false;
@ -58,18 +58,19 @@ public abstract class ScatterFeature extends DefaultFeature {
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featureConfig) {
public boolean place(FeaturePlaceContext<FC> featureConfig) {
FC cfg = featureConfig.config();
final MutableBlockPos POS = GlobalState.stateForThread().POS;
final RandomSource random = featureConfig.random();
BlockPos center = featureConfig.origin();
final WorldGenLevel world = featureConfig.level();
center = getCenterGround(world, center);
center = getCenterGround(cfg, world, center);
if (!canSpawn(world, center)) {
if (!canSpawn(cfg, world, center)) {
return false;
}
float r = MHelper.randRange(radius * 0.5F, radius, random);
float r = MHelper.randRange(cfg.radius * 0.5F, cfg.radius, random);
int count = MHelper.floor(r * r * MHelper.randRange(1.5F, 3F, random));
for (int i = 0; i < count; i++) {
float pr = r * (float) Math.sqrt(random.nextFloat());
@ -78,14 +79,15 @@ public abstract class ScatterFeature extends DefaultFeature {
float z = pr * (float) Math.sin(theta);
POS.set(center.getX() + x, center.getY() + getYOffset(), center.getZ() + z);
if (getGroundPlant(world, POS) && canGenerate(
if (getGroundPlant(cfg, world, POS) && canGenerate(
cfg,
world,
random,
center,
POS,
r
) && (getChance() < 2 || random.nextInt(getChance()) == 0)) {
generate(world, random, POS);
generate(cfg, world, random, POS);
}
}

View file

@ -0,0 +1,35 @@
package org.betterx.betterend.world.features;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
public class ScatterFeatureConfig implements FeatureConfiguration {
public static final Codec<ScatterFeatureConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
Codec.INT.fieldOf("radius").forGetter(o -> o.radius)
)
.apply(instance, ScatterFeatureConfig::new));
public final int radius;
public ScatterFeatureConfig(int radius) {
this.radius = radius;
}
public static ScatterFeatureConfig blueVine() {
return new ScatterFeatureConfig(5);
}
public static ScatterFeatureConfig filalux() {
return new ScatterFeatureConfig(10);
}
public static ScatterFeatureConfig glowPillar() {
return new ScatterFeatureConfig(9);
}
public static ScatterFeatureConfig lanceleaf() {
return new ScatterFeatureConfig(7);
}
}

View file

@ -7,20 +7,19 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
public class SingleInvertedScatterFeature extends InvertedScatterFeature {
private final Block block;
public class SingleInvertedScatterFeature extends InvertedScatterFeature<SinglePlantFeatureConfig> {
private BlockState block;
public SingleInvertedScatterFeature(Block block, int radius) {
super(radius);
this.block = block;
public SingleInvertedScatterFeature() {
super(SinglePlantFeatureConfig.CODEC);
}
@Override
public boolean canGenerate(
SinglePlantFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
@ -30,17 +29,18 @@ public class SingleInvertedScatterFeature extends InvertedScatterFeature {
if (!world.isEmptyBlock(blockPos)) {
return false;
}
BlockState state = block.defaultBlockState();
if (block instanceof BaseAttachedBlock) {
block = cfg.getPlantState(random, blockPos);
BlockState state = block;
if (block.getBlock() instanceof BaseAttachedBlock) {
state = state.setValue(BlockStateProperties.FACING, Direction.DOWN);
}
return state.canSurvive(world, blockPos);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
BlockState state = block.defaultBlockState();
if (block instanceof BaseAttachedBlock) {
public void generate(SinglePlantFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
BlockState state = block;
if (block.getBlock() instanceof BaseAttachedBlock) {
state = state.setValue(BlockStateProperties.FACING, Direction.DOWN);
}
BlocksHelper.setWithoutUpdate(world, blockPos, state);

View file

@ -1,5 +1,6 @@
package org.betterx.betterend.world.features;
import org.betterx.bclib.api.v2.levelgen.features.features.DefaultFeature;
import org.betterx.bclib.blocks.BaseCropBlock;
import org.betterx.bclib.blocks.BaseDoublePlantBlock;
import org.betterx.bclib.util.BlocksHelper;
@ -8,70 +9,53 @@ import org.betterx.betterend.blocks.basis.EndPlantWithAgeBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public class SinglePlantFeature extends ScatterFeature {
private final Block plant;
private final boolean rawHeightmap;
private final int chance;
public class SinglePlantFeature extends ScatterFeature<SinglePlantFeatureConfig> {
public SinglePlantFeature(Block plant, int radius) {
this(plant, radius, true, 1);
}
BlockState plant;
public SinglePlantFeature(Block plant, int radius, int chance) {
this(plant, radius, true, chance);
}
public SinglePlantFeature(Block plant, int radius, boolean rawHeightmap) {
this(plant, radius, rawHeightmap, 1);
}
public SinglePlantFeature(Block plant, int radius, boolean rawHeightmap, int chance) {
super(radius);
this.plant = plant;
this.rawHeightmap = rawHeightmap;
this.chance = chance;
}
protected int getChance() {
return chance;
public SinglePlantFeature() {
super(SinglePlantFeatureConfig.CODEC);
}
@Override
protected BlockPos getCenterGround(WorldGenLevel world, BlockPos pos) {
return rawHeightmap ? getPosOnSurfaceWG(world, pos) : getPosOnSurface(world, pos);
protected BlockPos getCenterGround(SinglePlantFeatureConfig cfg, WorldGenLevel world, BlockPos pos) {
return cfg.rawHeightmap
? DefaultFeature.getPosOnSurfaceWG(world, pos)
: DefaultFeature.getPosOnSurface(world, pos);
}
@Override
public boolean canGenerate(
SinglePlantFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
BlockPos blockPos,
float radius
) {
this.plant = cfg.getPlantState(random, blockPos);
//noinspection deprecation
return plant.canSurvive(plant.defaultBlockState(), world, blockPos);
return plant.getBlock().canSurvive(plant, world, blockPos);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
if (plant instanceof BaseDoublePlantBlock) {
public void generate(SinglePlantFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
if (this.plant.getBlock() instanceof BaseDoublePlantBlock) {
int rot = random.nextInt(4);
BlockState state = plant.defaultBlockState().setValue(BaseDoublePlantBlock.ROTATION, rot);
BlockState state = this.plant.setValue(BaseDoublePlantBlock.ROTATION, rot);
BlocksHelper.setWithoutUpdate(world, blockPos, state);
BlocksHelper.setWithoutUpdate(world, blockPos.above(), state.setValue(BaseDoublePlantBlock.TOP, true));
} else if (plant instanceof BaseCropBlock) {
BlockState state = plant.defaultBlockState().setValue(BaseCropBlock.AGE, 3);
} else if (this.plant.getBlock() instanceof BaseCropBlock) {
BlockState state = this.plant.setValue(BaseCropBlock.AGE, 3);
BlocksHelper.setWithoutUpdate(world, blockPos, state);
} else if (plant instanceof EndPlantWithAgeBlock) {
} else if (this.plant.getBlock() instanceof EndPlantWithAgeBlock) {
int age = random.nextInt(4);
BlockState state = plant.defaultBlockState().setValue(EndPlantWithAgeBlock.AGE, age);
BlockState state = this.plant.setValue(EndPlantWithAgeBlock.AGE, age);
BlocksHelper.setWithoutUpdate(world, blockPos, state);
} else {
BlocksHelper.setWithoutUpdate(world, blockPos, plant);
BlocksHelper.setWithoutUpdate(world, blockPos, this.plant);
}
}
}

View file

@ -0,0 +1,59 @@
package org.betterx.betterend.world.features;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider;
public class SinglePlantFeatureConfig extends ScatterFeatureConfig {
public static final Codec<SinglePlantFeatureConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
BlockStateProvider.CODEC.fieldOf("state").forGetter(o -> o.plant),
Codec.INT.fieldOf("radius").forGetter(o -> o.radius),
Codec.BOOL.fieldOf("raw_heightmap").forGetter(o -> o.rawHeightmap),
Codec.INT.fieldOf("chance").forGetter(o -> o.chance)
)
.apply(
instance,
SinglePlantFeatureConfig::new
));
public final BlockStateProvider plant;
public final boolean rawHeightmap;
public final int chance;
public SinglePlantFeatureConfig(Block plant, int radius) {
this(SimpleStateProvider.simple(plant), radius, true, 1);
}
public SinglePlantFeatureConfig(Block plant, int radius, int chance) {
this(SimpleStateProvider.simple(plant), radius, true, chance);
}
public SinglePlantFeatureConfig(Block plant, int radius, boolean rawHeightmap) {
this(SimpleStateProvider.simple(plant), radius, rawHeightmap, 1);
}
public SinglePlantFeatureConfig(Block plant, int radius, boolean rawHeightmap, int chance) {
this(SimpleStateProvider.simple(plant), radius, rawHeightmap, chance);
}
public SinglePlantFeatureConfig(BlockStateProvider plant, int radius, boolean rawHeightmap, int chance) {
super(radius);
this.plant = plant;
this.rawHeightmap = rawHeightmap;
this.chance = chance;
}
public BlockState getPlantState(RandomSource rnd, BlockPos pos) {
return plant.getState(rnd, pos);
}
public static SinglePlantFeatureConfig charnia(Block plant) {
return new SinglePlantFeatureConfig(plant, 6);
}
}

View file

@ -9,9 +9,9 @@ import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
public abstract class SkyScatterFeature extends ScatterFeature {
public SkyScatterFeature(int radius) {
super(radius);
public abstract class SkyScatterFeature extends ScatterFeature<ScatterFeatureConfig> {
public SkyScatterFeature() {
super(ScatterFeatureConfig.CODEC);
}
@Override
@ -21,6 +21,7 @@ public abstract class SkyScatterFeature extends ScatterFeature {
@Override
public boolean canGenerate(
ScatterFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
@ -44,12 +45,12 @@ public abstract class SkyScatterFeature extends ScatterFeature {
}
@Override
protected boolean canSpawn(WorldGenLevel world, BlockPos pos) {
protected boolean canSpawn(ScatterFeatureConfig cfg, WorldGenLevel world, BlockPos pos) {
return true;
}
@Override
protected BlockPos getCenterGround(WorldGenLevel world, BlockPos pos) {
protected BlockPos getCenterGround(ScatterFeatureConfig cfg, WorldGenLevel world, BlockPos pos) {
return new BlockPos(pos.getX(), MHelper.randRange(32, 192, world.getRandom()), pos.getZ());
}

View file

@ -6,34 +6,35 @@ import org.betterx.bclib.util.BlocksHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public class UnderwaterPlantFeature extends UnderwaterPlantScatter {
private final Block plant;
public class UnderwaterPlantFeature extends UnderwaterPlantScatter<SinglePlantFeatureConfig> {
private BlockState plant;
public UnderwaterPlantFeature() {
super(SinglePlantFeatureConfig.CODEC);
public UnderwaterPlantFeature(Block plant, int radius) {
super(radius);
this.plant = plant;
}
@Override
public boolean canGenerate(
SinglePlantFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
BlockPos blockPos,
float radius
) {
plant = cfg.getPlantState(random, blockPos);
//noinspection deprecation
return super.canSpawn(world, blockPos) && plant.canSurvive(plant.defaultBlockState(), world, blockPos);
return super.canSpawn(cfg, world, blockPos) && plant.getBlock().canSurvive(plant, world, blockPos);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
if (plant instanceof BaseDoublePlantBlock) {
public void generate(SinglePlantFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
if (plant.getBlock() instanceof BaseDoublePlantBlock) {
int rot = random.nextInt(4);
BlockState state = plant.defaultBlockState().setValue(BaseDoublePlantBlock.ROTATION, rot);
BlockState state = plant.setValue(BaseDoublePlantBlock.ROTATION, rot);
BlocksHelper.setWithoutUpdate(world, blockPos, state);
BlocksHelper.setWithoutUpdate(world, blockPos.above(), state.setValue(BaseDoublePlantBlock.TOP, true));
} else {

View file

@ -2,19 +2,20 @@ package org.betterx.betterend.world.features;
import org.betterx.betterend.util.GlobalState;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
public abstract class UnderwaterPlantScatter extends ScatterFeature {
public UnderwaterPlantScatter(int radius) {
super(radius);
public abstract class UnderwaterPlantScatter<FC extends ScatterFeatureConfig> extends ScatterFeature<FC> {
public UnderwaterPlantScatter(Codec<FC> codec) {
super(codec);
}
@Override
protected BlockPos getCenterGround(WorldGenLevel world, BlockPos pos) {
protected BlockPos getCenterGround(FC cfg, WorldGenLevel world, BlockPos pos) {
final MutableBlockPos POS = GlobalState.stateForThread().POS;
POS.setX(pos.getX());
POS.setZ(pos.getZ());
@ -24,6 +25,7 @@ public abstract class UnderwaterPlantScatter extends ScatterFeature {
@Override
public boolean canGenerate(
FC cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
@ -34,12 +36,12 @@ public abstract class UnderwaterPlantScatter extends ScatterFeature {
}
@Override
protected boolean canSpawn(WorldGenLevel world, BlockPos pos) {
protected boolean canSpawn(FC cfg, WorldGenLevel world, BlockPos pos) {
return world.getBlockState(pos).is(Blocks.WATER);
}
@Override
protected boolean getGroundPlant(WorldGenLevel world, MutableBlockPos pos) {
protected boolean getGroundPlant(FC cfg, WorldGenLevel world, MutableBlockPos pos) {
return getGround(world, pos).getY() < 128;
}

View file

@ -8,39 +8,37 @@ import org.betterx.bclib.util.BlocksHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public class VineFeature extends InvertedScatterFeature {
private final Block vineBlock;
private final int maxLength;
private final boolean vine;
public class VineFeature extends InvertedScatterFeature<VineFeatureConfig> {
private BlockState plant;
boolean vine;
public VineFeature(Block vineBlock, int maxLength) {
super(6);
this.vineBlock = vineBlock;
this.maxLength = maxLength;
this.vine = vineBlock instanceof BaseVineBlock;
public VineFeature() {
super(VineFeatureConfig.CODEC);
}
@Override
public boolean canGenerate(
VineFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos center,
BlockPos blockPos,
float radius
) {
plant = cfg.getPlantState(random, blockPos);
BlockState state = world.getBlockState(blockPos);
return state.getMaterial().isReplaceable() && canPlaceBlock(state, world, blockPos);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) {
int h = BlocksHelper.downRay(world, blockPos, random.nextInt(maxLength)) - 1;
public void generate(VineFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
int h = BlocksHelper.downRay(world, blockPos, random.nextInt(cfg.maxLength)) - 1;
if (h > 2) {
BlockState top = getTopState();
BlockState middle = getMiggleState();
BlockState middle = getMiddleState();
BlockState bottom = getBottomState();
BlocksHelper.setWithoutUpdate(world, blockPos, top);
for (int i = 1; i < h; i++) {
@ -51,25 +49,28 @@ public class VineFeature extends InvertedScatterFeature {
}
private boolean canPlaceBlock(BlockState state, WorldGenLevel world, BlockPos blockPos) {
if (vine) {
return ((BaseVineBlock) vineBlock).canGenerate(state, world, blockPos);
if (plant == null) return false;
if (plant.getBlock() instanceof BaseVineBlock vineBlock) {
vine = true;
return vineBlock.canGenerate(state, world, blockPos);
} else {
return vineBlock.canSurvive(state, world, blockPos);
vine = false;
return plant.getBlock().canSurvive(state, world, blockPos);
}
}
private BlockState getTopState() {
BlockState state = vineBlock.defaultBlockState();
BlockState state = plant;
return vine ? state.setValue(BlockProperties.TRIPLE_SHAPE, TripleShape.TOP) : state;
}
private BlockState getMiggleState() {
BlockState state = vineBlock.defaultBlockState();
private BlockState getMiddleState() {
BlockState state = plant;
return vine ? state.setValue(BlockProperties.TRIPLE_SHAPE, TripleShape.MIDDLE) : state;
}
private BlockState getBottomState() {
BlockState state = vineBlock.defaultBlockState();
BlockState state = plant;
return vine ? state.setValue(BlockProperties.TRIPLE_SHAPE, TripleShape.BOTTOM) : state;
}
}

View file

@ -0,0 +1,42 @@
package org.betterx.betterend.world.features;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider;
public class VineFeatureConfig extends ScatterFeatureConfig {
public static final Codec<VineFeatureConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
BlockStateProvider.CODEC.fieldOf("state").forGetter(o -> o.plant),
Codec.INT.fieldOf("radius").forGetter(o -> o.radius),
Codec.INT.fieldOf("max_length").forGetter(o -> o.maxLength)
)
.apply(
instance,
VineFeatureConfig::new
));
public final BlockStateProvider plant;
public final int maxLength;
public VineFeatureConfig(Block vineBlock, int maxLength) {
this(SimpleStateProvider.simple(vineBlock), 6, maxLength);
}
public VineFeatureConfig(BlockStateProvider plant, int radius, int maxLength) {
super(radius);
this.plant = plant;
this.maxLength = maxLength;
}
public BlockState getPlantState(RandomSource rnd, BlockPos pos) {
return plant.getState(rnd, pos);
}
}

View file

@ -12,34 +12,47 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
public class WallPlantFeature extends WallScatterFeature {
private final Block block;
public class WallPlantFeature extends WallScatterFeature<WallPlantFeatureConfig> {
protected BlockState plant;
public WallPlantFeature(Block block, int radius) {
super(radius);
this.block = block;
public WallPlantFeature() {
super(WallPlantFeatureConfig.CODEC);
}
@Override
public boolean canGenerate(WorldGenLevel world, RandomSource random, BlockPos pos, Direction dir) {
public boolean canGenerate(
WallPlantFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos pos,
Direction dir
) {
plant = cfg.getPlantState(random, pos);
Block block = plant.getBlock();
if (block instanceof BaseWallPlantBlock) {
BlockState state = block.defaultBlockState().setValue(BaseWallPlantBlock.FACING, dir);
BlockState state = plant.setValue(BaseWallPlantBlock.FACING, dir);
return block.canSurvive(state, world, pos);
} else if (block instanceof BaseAttachedBlock) {
BlockState state = block.defaultBlockState().setValue(BlockStateProperties.FACING, dir);
BlockState state = plant.setValue(BlockStateProperties.FACING, dir);
return block.canSurvive(state, world, pos);
}
return block.canSurvive(block.defaultBlockState(), world, pos);
return block.canSurvive(plant, world, pos);
}
@Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos pos, Direction dir) {
BlockState state = block.defaultBlockState();
public void generate(
WallPlantFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos pos,
Direction dir
) {
Block block = plant.getBlock();
if (block instanceof BaseWallPlantBlock) {
state = state.setValue(BaseWallPlantBlock.FACING, dir);
plant = plant.setValue(BaseWallPlantBlock.FACING, dir);
} else if (block instanceof BaseAttachedBlock) {
state = state.setValue(BlockStateProperties.FACING, dir);
plant = plant.setValue(BlockStateProperties.FACING, dir);
}
BlocksHelper.setWithoutUpdate(world, pos, state);
BlocksHelper.setWithoutUpdate(world, pos, plant);
}
}

View file

@ -0,0 +1,39 @@
package org.betterx.betterend.world.features;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider;
public class WallPlantFeatureConfig extends ScatterFeatureConfig {
public static final Codec<WallPlantFeatureConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
BlockStateProvider.CODEC.fieldOf("state").forGetter(o -> o.plant),
Codec.INT.fieldOf("radius").forGetter(o -> o.radius)
)
.apply(
instance,
WallPlantFeatureConfig::new
));
public final BlockStateProvider plant;
public WallPlantFeatureConfig(Block plant, int radius) {
this(SimpleStateProvider.simple(plant), radius);
}
public WallPlantFeatureConfig(BlockStateProvider plant, int radius) {
super(radius);
this.plant = plant;
}
public BlockState getPlantState(RandomSource rnd, BlockPos pos) {
return plant.getState(rnd, pos);
}
}

View file

@ -5,16 +5,18 @@ import net.minecraft.core.Direction;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public class WallPlantOnLogFeature extends WallPlantFeature {
public WallPlantOnLogFeature(Block block, int radius) {
super(block, radius);
}
@Override
public boolean canGenerate(WorldGenLevel world, RandomSource random, BlockPos pos, Direction dir) {
public boolean canGenerate(
WallPlantFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos pos,
Direction dir
) {
plant = cfg.getPlantState(random, pos);
BlockPos blockPos = pos.relative(dir.getOpposite());
BlockState blockState = world.getBlockState(blockPos);
return blockState.is(BlockTags.LOGS);

View file

@ -1,32 +1,32 @@
package org.betterx.betterend.world.features;
import org.betterx.bclib.api.v2.levelgen.features.features.DefaultFeature;
import org.betterx.bclib.util.BlocksHelper;
import org.betterx.bclib.util.MHelper;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
public abstract class WallScatterFeature extends DefaultFeature {
public abstract class WallScatterFeature<FC extends ScatterFeatureConfig> extends Feature<FC> {
private static final Direction[] DIR = BlocksHelper.makeHorizontal();
private final int radius;
public WallScatterFeature(int radius) {
this.radius = radius;
public WallScatterFeature(Codec<FC> codec) {
super(codec);
}
public abstract boolean canGenerate(WorldGenLevel world, RandomSource random, BlockPos pos, Direction dir);
public abstract boolean canGenerate(FC cfg, WorldGenLevel world, RandomSource random, BlockPos pos, Direction dir);
public abstract void generate(WorldGenLevel world, RandomSource random, BlockPos pos, Direction dir);
public abstract void generate(FC cfg, WorldGenLevel world, RandomSource random, BlockPos pos, Direction dir);
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featureConfig) {
public boolean place(FeaturePlaceContext<FC> featureConfig) {
FC cfg = featureConfig.config();
final RandomSource random = featureConfig.random();
final BlockPos center = featureConfig.origin();
final WorldGenLevel world = featureConfig.level();
@ -38,17 +38,17 @@ public abstract class WallScatterFeature extends DefaultFeature {
int py = MHelper.randRange(minY, maxY, random);
MutableBlockPos mut = new MutableBlockPos();
for (int x = -radius; x <= radius; x++) {
for (int x = -cfg.radius; x <= cfg.radius; x++) {
mut.setX(center.getX() + x);
for (int y = -radius; y <= radius; y++) {
for (int y = -cfg.radius; y <= cfg.radius; y++) {
mut.setY(py + y);
for (int z = -radius; z <= radius; z++) {
for (int z = -cfg.radius; z <= cfg.radius; z++) {
mut.setZ(center.getZ() + z);
if (random.nextInt(4) == 0 && world.isEmptyBlock(mut)) {
shuffle(random);
for (Direction dir : DIR) {
if (canGenerate(world, random, mut, dir)) {
generate(world, random, mut, dir);
if (canGenerate(cfg, world, random, mut, dir)) {
generate(cfg, world, random, mut, dir);
break;
}
}

View file

@ -14,32 +14,25 @@ import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
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 net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.function.Function;
public class ArchFeature extends DefaultFeature {
private final Function<BlockPos, BlockState> surfaceFunction;
private final Block block;
public ArchFeature(Block block, Function<BlockPos, BlockState> surfaceFunction) {
this.surfaceFunction = surfaceFunction;
this.block = block;
public class ArchFeature extends Feature<ArchFeatureConfig> {
public ArchFeature() {
super(ArchFeatureConfig.CODEC);
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featurePlaceContext) {
public boolean place(FeaturePlaceContext<ArchFeatureConfig> featurePlaceContext) {
ArchFeatureConfig cfg = featurePlaceContext.config();
final WorldGenLevel world = featurePlaceContext.level();
BlockPos origin = featurePlaceContext.origin();
RandomSource random = featurePlaceContext.random();
BlockPos pos = getPosOnSurfaceWG(
BlockState cfgBlockState = cfg.block.getState(random, origin);
Block cfgBlock = cfgBlockState.getBlock();
BlockPos pos = DefaultFeature.getPosOnSurfaceWG(
world,
new BlockPos((origin.getX() & 0xFFFFFFF0) | 7, 0, (origin.getZ() & 0xFFFFFFF0) | 7)
);
@ -52,27 +45,24 @@ public class ArchFeature extends DefaultFeature {
if (smallRadius + bigRadius > 23) {
smallRadius = 23 - bigRadius;
}
SDF arch = new SDFTorus().setBigRadius(bigRadius).setSmallRadius(smallRadius).setBlock(block);
SDF arch = new SDFTorus().setBigRadius(bigRadius).setSmallRadius(smallRadius).setBlock(cfgBlock);
arch = new SDFRotation().setRotation(MHelper.randomHorizontal(random), (float) Math.PI * 0.5F).setSource(arch);
final float smallRadiusF = smallRadius;
OpenSimplexNoise noise = new OpenSimplexNoise(random.nextLong());
arch = new SDFDisplacement().setFunction((vec) -> {
return (float) (Math.abs(noise.eval(
vec.x() * 0.1,
vec.y() * 0.1,
vec.z() * 0.1
)) * 3F + Math.abs(noise.eval(
vec.x() * 0.3,
vec.y() * 0.3 + 100,
vec.z() * 0.3
)) * 1.3F) - smallRadiusF * Math.abs(1 - vec.y() / bigRadius);
}).setSource(arch);
arch = new SDFDisplacement().setFunction((vec) -> (float) (Math.abs(noise.eval(
vec.x() * 0.1,
vec.y() * 0.1,
vec.z() * 0.1
)) * 3F + Math.abs(noise.eval(
vec.x() * 0.3,
vec.y() * 0.3 + 100,
vec.z() * 0.3
)) * 1.3F) - smallRadiusF * Math.abs(1 - vec.y() / bigRadius)).setSource(arch);
List<BlockPos> surface = Lists.newArrayList();
arch.addPostProcess((info) -> {
if (info.getStateUp().isAir()) {
return surfaceFunction.apply(info.getPos());
return cfg.surfaceFunction.apply(info.getPos());
}
return info.getState();
});

View file

@ -0,0 +1,58 @@
package org.betterx.betterend.world.features.terrain;
import org.betterx.betterend.world.biome.land.UmbraValleyBiome;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.util.StringRepresentable;
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 net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider;
import java.util.function.Function;
public class ArchFeatureConfig implements FeatureConfiguration {
public static final Codec<ArchFeatureConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
BlockStateProvider.CODEC.fieldOf("states").forGetter(o -> o.block),
SurfaceFunction.CODEC.fieldOf("surface_function").forGetter(o -> o.surfaceFunction)
)
.apply(instance, ArchFeatureConfig::new));
public final BlockStateProvider block;
public final SurfaceFunction surfaceFunction;
public ArchFeatureConfig(Block block, SurfaceFunction surfaceFunction) {
this(SimpleStateProvider.simple(block), surfaceFunction);
}
public ArchFeatureConfig(BlockStateProvider block, SurfaceFunction surfaceFunction) {
this.block = block;
this.surfaceFunction = surfaceFunction;
}
public enum SurfaceFunction implements StringRepresentable {
UMBRA_VALLEY("umbra_valley", pos -> UmbraValleyBiome.getSurface(pos.getX(), pos.getZ()).defaultBlockState());
public static final Codec<SurfaceFunction> CODEC = StringRepresentable.fromEnum(SurfaceFunction::values);
private final Function<BlockPos, BlockState> surfaceFunction;
private final String name;
SurfaceFunction(String name, Function<BlockPos, BlockState> surfaceFunction) {
this.name = name;
this.surfaceFunction = surfaceFunction;
}
@Override
public String getSerializedName() {
return name;
}
public BlockState apply(BlockPos pos) {
return this.surfaceFunction.apply(pos);
}
}
}

View file

@ -1,59 +1,46 @@
package org.betterx.betterend.world.features.terrain;
import org.betterx.bclib.api.v2.levelgen.features.features.DefaultFeature;
import org.betterx.bclib.sdf.SDF;
import org.betterx.bclib.sdf.operator.SDFCoordModify;
import org.betterx.bclib.sdf.operator.SDFScale3D;
import org.betterx.bclib.sdf.primitive.SDFSphere;
import org.betterx.bclib.util.MHelper;
import org.betterx.betterend.noise.OpenSimplexNoise;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
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 net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
public class OreLayerFeature extends DefaultFeature {
public class OreLayerFeature extends Feature<OreLayerFeatureConfig> {
private static final SDFSphere SPHERE;
private static final SDFCoordModify NOISE;
private static final SDF FUNCTION;
private final BlockState state;
private final float radius;
private final int minY;
private final int maxY;
private OpenSimplexNoise noise;
public OreLayerFeature(BlockState state, float radius, int minY, int maxY) {
this.state = state;
this.radius = radius;
this.minY = minY;
this.maxY = maxY;
public OreLayerFeature() {
super(OreLayerFeatureConfig.CODEC);
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featureConfig) {
public boolean place(FeaturePlaceContext<OreLayerFeatureConfig> featureConfig) {
final OreLayerFeatureConfig cfg = featureConfig.config();
final RandomSource random = featureConfig.random();
final BlockPos pos = featureConfig.origin();
final WorldGenLevel world = featureConfig.level();
float radius = this.radius * 0.5F;
float radius = cfg.radius * 0.5F;
int r = MHelper.floor(radius + 1);
int posX = MHelper.randRange(Math.max(r - 16, 0), Math.min(31 - r, 15), random) + pos.getX();
int posZ = MHelper.randRange(Math.max(r - 16, 0), Math.min(31 - r, 15), random) + pos.getZ();
int posY = MHelper.randRange(minY, maxY, random);
int posY = MHelper.randRange(cfg.minY, cfg.maxY, random);
if (noise == null) {
noise = new OpenSimplexNoise(world.getSeed());
}
SPHERE.setRadius(radius).setBlock(state);
SPHERE.setRadius(radius).setBlock(cfg.state);
NOISE.setFunction((vec) -> {
double x = (vec.x() + pos.getX()) * 0.1;
double z = (vec.z() + pos.getZ()) * 0.1;
double offset = noise.eval(x, z);
double offset = cfg.getNoise(world.getSeed()).eval(x, z);
vec.set(vec.x(), vec.y() + (float) offset * 8, vec.z());
});
FUNCTION.fillRecursive(world, new BlockPos(posX, posY, posZ));

View file

@ -0,0 +1,39 @@
package org.betterx.betterend.world.features.terrain;
import org.betterx.betterend.noise.OpenSimplexNoise;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
public class OreLayerFeatureConfig implements FeatureConfiguration {
public static final Codec<OreLayerFeatureConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
BlockState.CODEC.fieldOf("state").forGetter(o -> o.state),
Codec.FLOAT.fieldOf("radius").forGetter(o -> o.radius),
Codec.INT.fieldOf("min_y").forGetter(o -> o.minY),
Codec.INT.fieldOf("max_y").forGetter(o -> o.maxY)
)
.apply(instance, OreLayerFeatureConfig::new));
public final BlockState state;
public final float radius;
public final int minY;
public final int maxY;
private OpenSimplexNoise noise;
public OreLayerFeatureConfig(BlockState state, float radius, int minY, int maxY) {
this.state = state;
this.radius = radius;
this.minY = minY;
this.maxY = maxY;
}
public OpenSimplexNoise getNoise(long seed) {
if (noise == null) {
noise = new OpenSimplexNoise(seed);
}
return noise;
}
}

View file

@ -17,25 +17,28 @@ import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
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 net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
public class ThinArchFeature extends DefaultFeature {
private final Block block;
public class ThinArchFeature extends Feature<ThinArchFeatureConfig> {
public ThinArchFeature(Block block) {
this.block = block;
public ThinArchFeature() {
super(ThinArchFeatureConfig.CODEC);
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featurePlaceContext) {
public boolean place(FeaturePlaceContext<ThinArchFeatureConfig> featurePlaceContext) {
final ThinArchFeatureConfig cfg = featurePlaceContext.config();
final WorldGenLevel world = featurePlaceContext.level();
BlockPos origin = featurePlaceContext.origin();
RandomSource random = featurePlaceContext.random();
BlockState state = cfg.block.getState(random, origin);
Block block = state.getBlock();
BlockPos pos = getPosOnSurfaceWG(
BlockPos pos = DefaultFeature.getPosOnSurfaceWG(
world,
new BlockPos(
(origin.getX() & 0xFFFFFFF0) | 7,

View file

@ -0,0 +1,28 @@
package org.betterx.betterend.world.features.terrain;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider;
public class ThinArchFeatureConfig implements FeatureConfiguration {
public static final Codec<ThinArchFeatureConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
BlockStateProvider.CODEC.fieldOf("states").forGetter(o -> o.block)
)
.apply(instance, ThinArchFeatureConfig::new));
public final BlockStateProvider block;
public ThinArchFeatureConfig(Block block) {
this(SimpleStateProvider.simple(block));
}
public ThinArchFeatureConfig(BlockStateProvider block) {
this.block = block;
}
}

View file

@ -1,6 +1,5 @@
package org.betterx.betterend.world.features.terrain.caves;
import org.betterx.bclib.api.v2.levelgen.features.features.DefaultFeature;
import org.betterx.bclib.util.BlocksHelper;
import org.betterx.betterend.util.BlockFixer;
import org.betterx.betterend.world.biome.cave.EndCaveBiome;
@ -15,23 +14,21 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
import com.google.common.collect.Sets;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
public class CaveChunkPopulatorFeature extends DefaultFeature {
private final Supplier<EndCaveBiome> supplier;
public class CaveChunkPopulatorFeature extends Feature<CaveChunkPopulatorFeatureConfig> {
public CaveChunkPopulatorFeature(Supplier<EndCaveBiome> biome) {
this.supplier = biome;
public CaveChunkPopulatorFeature() {
super(CaveChunkPopulatorFeatureConfig.CODEC);
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featureConfig) {
public boolean place(FeaturePlaceContext<CaveChunkPopulatorFeatureConfig> featureConfig) {
CaveChunkPopulatorFeatureConfig cfg = featureConfig.config();
final RandomSource random = featureConfig.random();
final BlockPos pos = featureConfig.origin();
final WorldGenLevel world = featureConfig.level();
@ -42,7 +39,7 @@ public class CaveChunkPopulatorFeature extends DefaultFeature {
MutableBlockPos min = new MutableBlockPos().set(pos);
MutableBlockPos max = new MutableBlockPos().set(pos);
fillSets(sx, sz, world.getChunk(pos), floorPositions, ceilPositions, min, max);
EndCaveBiome biome = supplier.get();
EndCaveBiome biome = cfg.getCaveBiome();
BlockState surfaceBlock = Blocks.END_STONE.defaultBlockState(); //biome.getBiome().getGenerationSettings().getSurfaceBuilderConfig().getTopMaterial();
placeFloor(world, biome, floorPositions, random, surfaceBlock);
placeCeil(world, biome, ceilPositions, random);

View file

@ -0,0 +1,19 @@
package org.betterx.betterend.world.features.terrain.caves;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import org.betterx.betterend.world.biome.cave.EndCaveBiome;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
public record CaveChunkPopulatorFeatureConfig(ResourceLocation biomeID) implements FeatureConfiguration {
public static final Codec<CaveChunkPopulatorFeatureConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(ResourceLocation.CODEC.fieldOf("biome").forGetter(o -> o.biomeID))
.apply(instance, CaveChunkPopulatorFeatureConfig::new));
public EndCaveBiome getCaveBiome() {
return (EndCaveBiome) BiomeAPI.getBiome(biomeID);
}
}