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.BetterEnd;
import org.betterx.betterend.integration.Integrations; import org.betterx.betterend.integration.Integrations;
import org.betterx.betterend.integration.byg.BYGBlocks; import org.betterx.betterend.integration.byg.BYGBlocks;
import org.betterx.betterend.world.features.SinglePlantFeature; import org.betterx.betterend.registry.EndFeatures;
import org.betterx.betterend.world.features.VineFeature; import org.betterx.betterend.world.features.*;
import org.betterx.betterend.world.features.WallPlantFeature;
import org.betterx.betterend.world.features.WallPlantOnLogFeature;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
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.NoneFeatureConfiguration; import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
public class BYGFeatures { public class BYGFeatures {
public static final BCLFeature OLD_BULBIS_TREE = redisterVegetation( public static final BCLFeature<OldBulbisTreeFeature, NoneFeatureConfiguration> OLD_BULBIS_TREE = redisterVegetation(
"old_bulbis_tree", "old_bulbis_tree",
new OldBulbisTreeFeature(), EndFeatures.inlineBuild("old_bulbis_tree_feature", new OldBulbisTreeFeature()),
1 1
); );
public static final BCLFeature IVIS_SPROUT = redisterVegetation( public static final BCLFeature<SinglePlantFeature, SinglePlantFeatureConfig> IVIS_SPROUT = redisterVegetation(
"ivis_sprout", "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 6
); );
public static final BCLFeature IVIS_VINE = redisterVegetation( public static final BCLFeature<VineFeature, VineFeatureConfig> IVIS_VINE = redisterVegetation(
"ivis_vine", "ivis_vine",
new VineFeature(BYGBlocks.IVIS_VINE, 24), EndFeatures.VINE_FEATURE,
new VineFeatureConfig(BYGBlocks.IVIS_VINE, 24),
5 5
); );
public static final BCLFeature IVIS_MOSS = redisterVegetation( public static final BCLFeature<WallPlantFeature, WallPlantFeatureConfig> IVIS_MOSS = redisterVegetation(
"ivis_moss", "ivis_moss",
new WallPlantFeature(BYGBlocks.IVIS_MOSS, 6), EndFeatures.WALL_PLANT_FEATURE,
new WallPlantFeatureConfig(BYGBlocks.IVIS_MOSS, 6),
1 1
); );
public static final BCLFeature IVIS_MOSS_WOOD = redisterVegetation( public static final BCLFeature<WallPlantOnLogFeature, WallPlantFeatureConfig> IVIS_MOSS_WOOD = redisterVegetation(
"ivis_moss_wood", "ivis_moss_wood",
new WallPlantOnLogFeature(BYGBlocks.IVIS_MOSS, 6), EndFeatures.WALL_PLANT_ON_LOG_FEATURE,
new WallPlantFeatureConfig(BYGBlocks.IVIS_MOSS, 6),
15 15
); );
public static final BCLFeature NIGHTSHADE_MOSS = redisterVegetation( public static final BCLFeature<WallPlantFeature, WallPlantFeatureConfig> NIGHTSHADE_MOSS = redisterVegetation(
"nightshade_moss", "nightshade_moss",
new WallPlantFeature(BYGBlocks.NIGHTSHADE_MOSS, 5), EndFeatures.WALL_PLANT_FEATURE,
new WallPlantFeatureConfig(BYGBlocks.NIGHTSHADE_MOSS, 5),
2 2
); );
public static final BCLFeature NIGHTSHADE_MOSS_WOOD = redisterVegetation( public static final BCLFeature<WallPlantOnLogFeature, WallPlantFeatureConfig> NIGHTSHADE_MOSS_WOOD = redisterVegetation(
"nightshade_moss_wood", "nightshade_moss_wood",
new WallPlantOnLogFeature(BYGBlocks.NIGHTSHADE_MOSS, 5), EndFeatures.WALL_PLANT_ON_LOG_FEATURE,
new WallPlantFeatureConfig(BYGBlocks.NIGHTSHADE_MOSS, 5),
8 8
); );
public static final BCLFeature NIGHTSHADE_REDWOOD_TREE = redisterVegetation( public static final BCLFeature<NightshadeRedwoodTreeFeature, NoneFeatureConfiguration> NIGHTSHADE_REDWOOD_TREE = redisterVegetation(
"nightshade_redwood_tree", "nightshade_redwood_tree",
new NightshadeRedwoodTreeFeature(), new NightshadeRedwoodTreeFeature(),
1 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() { 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); ResourceLocation id = BetterEnd.makeID(name);
return BCLFeatureBuilder return BCLFeatureBuilder
.start(id, feature) .start(id, feature)
.configuration(config)
.buildAndRegister() .buildAndRegister()
.place() .place()
.countMax(density) .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;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeBuilder.BiomeSupplier; 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.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.BCLFeature;
import org.betterx.bclib.api.v3.levelgen.features.BCLFeatureBuilder; import org.betterx.bclib.api.v3.levelgen.features.BCLFeatureBuilder;
import org.betterx.bclib.util.WeightedList; import org.betterx.bclib.util.WeightedList;
import org.betterx.betterend.BetterEnd; import org.betterx.betterend.BetterEnd;
import org.betterx.betterend.registry.EndFeatures;
import org.betterx.betterend.registry.EndSounds; import org.betterx.betterend.registry.EndSounds;
import org.betterx.betterend.world.biome.EndBiome; import org.betterx.betterend.world.biome.EndBiome;
import org.betterx.betterend.world.features.terrain.caves.CaveChunkPopulatorFeature; 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.core.BlockPos;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@ -28,11 +29,13 @@ public class EndCaveBiome extends EndBiome {
@Override @Override
protected void addCustomBuildData(BCLBiomeBuilder builder) { protected void addCustomBuildData(BCLBiomeBuilder builder) {
BCLFeature feature = BCLFeatureBuilder
BCLFeature<CaveChunkPopulatorFeature, CaveChunkPopulatorFeatureConfig> feature = BCLFeatureBuilder
.start( .start(
BetterEnd.makeID(ID.getPath() + "_cave_populator"), BetterEnd.makeID(ID.getPath() + "_cave_populator"),
new CaveChunkPopulatorFeature(() -> (EndCaveBiome) BiomeAPI.getBiome(ID)) EndFeatures.CAVE_CHUNK_POPULATOR
) )
.configuration(new CaveChunkPopulatorFeatureConfig(ID))
.buildAndRegister() .buildAndRegister()
.place() .place()
.decoration(GenerationStep.Decoration.RAW_GENERATION) .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_BUSH, 1);
this.addCeilFeature(EndFeatures.CAVE_PUMPKIN, 1); this.addCeilFeature(EndFeatures.CAVE_PUMPKIN, 1);
this.addCeilFeature(EndFeatures.RUBINEA, 3); this.addCeilFeature(EndFeatures.RUBINEA.getFeature(), 3);
this.addCeilFeature(EndFeatures.MAGNULA, 1); this.addCeilFeature(EndFeatures.MAGNULA.getFeature(), 1);
this.addCeilFeature(EndFeatures.END_STONE_STALACTITE_CAVEMOSS, 10); this.addCeilFeature(EndFeatures.END_STONE_STALACTITE_CAVEMOSS, 10);
} }

View file

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

View file

@ -1,13 +1,20 @@
package org.betterx.betterend.world.features; package org.betterx.betterend.world.features;
import org.betterx.bclib.util.StructureHelper;
import org.betterx.betterend.util.LootTableUtil; 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.BlockPos;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.ChestBlock; 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.BlockEntity;
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
import net.minecraft.world.level.block.state.BlockState; 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;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import java.util.List;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public class BuildingListFeature extends ListFeature { public class BuildingListFeature extends NBTFeature<BuildingListFeatureConfig> {
public BuildingListFeature(List<StructureInfo> list, BlockState defaultBlock) { private StructureInfo selected;
super(list, defaultBlock);
public BuildingListFeature() {
super(BuildingListFeatureConfig.CODEC);
} }
@Override @Override
protected void addStructureData(StructurePlaceSettings data) { protected void addStructureData(StructurePlaceSettings data) {
super.addStructureData(data);
data.addProcessor(new ChestProcessor()); 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 { class ChestProcessor extends StructureProcessor {
@Nullable @Nullable
@Override @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; package org.betterx.betterend.world.features;
import net.minecraft.world.level.block.Block;
public class CharniaFeature extends UnderwaterPlantFeature { public class CharniaFeature extends UnderwaterPlantFeature {
public CharniaFeature(Block plant) {
super(plant, 6);
}
@Override @Override
protected int getChance() { protected int getChance() {
return 3; return 3;

View file

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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
package org.betterx.betterend.world.features; 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.blocks.BlockProperties.TripleShape;
import org.betterx.bclib.util.BlocksHelper; import org.betterx.bclib.util.BlocksHelper;
import org.betterx.betterend.blocks.EndLotusLeafBlock; 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.Blocks;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
public class EndLotusLeafFeature extends ScatterFeature { public class EndLotusLeafFeature extends ScatterFeature<ScatterFeatureConfig> {
public EndLotusLeafFeature(int radius) { public EndLotusLeafFeature() {
super(radius); super(ScatterFeatureConfig.CODEC);
} }
@Override @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)) { if (canGenerate(world, blockPos)) {
generateLeaf(world, blockPos); generateLeaf(world, blockPos);
} }
@ -31,8 +32,8 @@ public class EndLotusLeafFeature extends ScatterFeature {
} }
@Override @Override
protected BlockPos getCenterGround(WorldGenLevel world, BlockPos pos) { protected BlockPos getCenterGround(ScatterFeatureConfig cfg, WorldGenLevel world, BlockPos pos) {
return getPosOnSurface(world, pos); return DefaultFeature.getPosOnSurface(world, pos);
} }
private void generateLeaf(WorldGenLevel world, BlockPos pos) { private void generateLeaf(WorldGenLevel world, BlockPos pos) {
@ -75,6 +76,7 @@ public class EndLotusLeafFeature extends ScatterFeature {
@Override @Override
public boolean canGenerate( public boolean canGenerate(
ScatterFeatureConfig cfg,
WorldGenLevel world, WorldGenLevel world,
RandomSource random, RandomSource random,
BlockPos center, 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; import net.minecraft.world.level.block.state.properties.BlockStateProperties;
public class FilaluxFeature extends SkyScatterFeature { public class FilaluxFeature extends SkyScatterFeature {
public FilaluxFeature() {
super(10);
}
@Override @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 vine = EndBlocks.FILALUX.defaultBlockState();
BlockState wings = EndBlocks.FILALUX_WINGS.defaultBlockState(); BlockState wings = EndBlocks.FILALUX_WINGS.defaultBlockState();
BlocksHelper.setWithoutUpdate(world, blockPos, EndBlocks.FILALUX_LANTERN); BlocksHelper.setWithoutUpdate(world, blockPos, EndBlocks.FILALUX_LANTERN);

View file

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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
package org.betterx.betterend.world.features; 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.blocks.basis.EndPlantWithAgeBlock;
import org.betterx.betterend.registry.EndBlocks; import org.betterx.betterend.registry.EndBlocks;
@ -7,13 +8,14 @@ import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
public class LanceleafFeature extends ScatterFeature { public class LanceleafFeature extends ScatterFeature<ScatterFeatureConfig> {
public LanceleafFeature() { public LanceleafFeature() {
super(7); super(ScatterFeatureConfig.CODEC);
} }
@Override @Override
public boolean canGenerate( public boolean canGenerate(
ScatterFeatureConfig cfg,
WorldGenLevel world, WorldGenLevel world,
RandomSource random, RandomSource random,
BlockPos center, BlockPos center,
@ -21,11 +23,11 @@ public class LanceleafFeature extends ScatterFeature {
float radius float radius
) { ) {
//noinspection deprecation //noinspection deprecation
return EndBlocks.LANCELEAF_SEED.canSurvive(AIR, world, blockPos); return EndBlocks.LANCELEAF_SEED.canSurvive(DefaultFeature.AIR, world, blockPos);
} }
@Override @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); EndPlantWithAgeBlock seed = ((EndPlantWithAgeBlock) EndBlocks.LANCELEAF_SEED);
seed.growAdult(world, random, blockPos); 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; import java.util.function.Function;
public class MengerSpongeFeature extends UnderwaterPlantScatter { public class MengerSpongeFeature extends UnderwaterPlantScatter<ScatterFeatureConfig> {
private static final Function<BlockState, Boolean> REPLACE; private static final Function<BlockState, Boolean> REPLACE;
public MengerSpongeFeature(int radius) { public MengerSpongeFeature() {
super(radius); super(ScatterFeatureConfig.CODEC);
} }
@Override @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); BlocksHelper.setWithoutUpdate(world, blockPos, EndBlocks.MENGER_SPONGE_WET);
if (random.nextBoolean()) { if (random.nextBoolean()) {
for (Direction dir : BlocksHelper.DIRECTIONS) { 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.bclib.util.BlocksHelper;
import org.betterx.worlds.together.tag.v3.CommonBlockTags; import org.betterx.worlds.together.tag.v3.CommonBlockTags;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos; import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
@ -16,13 +17,14 @@ import net.minecraft.nbt.NbtIo;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState; 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.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.BoundingBox;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
//TODO: 1.19 Check if we can merge this with the new TemplateFeature! public abstract class NBTFeature<FC extends NBTFeatureConfig> extends Feature<FC> {
public abstract class NBTFeature extends DefaultFeature { public NBTFeature(Codec<FC> codec) {
private final BlockState defaultBlock; super(codec);
public NBTFeature(BlockState defaultBlock) {
this.defaultBlock = defaultBlock;
} }
protected static final DestructionStructureProcessor DESTRUCTION = new DestructionStructureProcessor(); 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); 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) { protected int getAverageY(WorldGenLevel world, BlockPos center) {
int y = getYOnSurface(world, center.getX(), center.getZ()); int y = DefaultFeature.getYOnSurface(world, center.getX(), center.getZ());
y += getYOnSurface(world, center.getX() - 2, center.getZ() - 2); y += DefaultFeature.getYOnSurface(world, center.getX() - 2, center.getZ() - 2);
y += getYOnSurface(world, center.getX() + 2, center.getZ() - 2); y += DefaultFeature.getYOnSurface(world, center.getX() + 2, center.getZ() - 2);
y += getYOnSurface(world, center.getX() - 2, center.getZ() + 2); y += DefaultFeature.getYOnSurface(world, center.getX() - 2, center.getZ() + 2);
y += getYOnSurface(world, center.getX() + 2, center.getZ() + 2); y += DefaultFeature.getYOnSurface(world, center.getX() + 2, center.getZ() + 2);
return y / 5; return y / 5;
} }
protected int getAverageYWG(WorldGenLevel world, BlockPos center) { protected int getAverageYWG(WorldGenLevel world, BlockPos center) {
int y = getYOnSurfaceWG(world, center.getX(), center.getZ()); int y = DefaultFeature.getYOnSurfaceWG(world, center.getX(), center.getZ());
y += getYOnSurfaceWG(world, center.getX() - 2, center.getZ() - 2); y += DefaultFeature.getYOnSurfaceWG(world, center.getX() - 2, center.getZ() - 2);
y += getYOnSurfaceWG(world, center.getX() + 2, center.getZ() - 2); y += DefaultFeature.getYOnSurfaceWG(world, center.getX() + 2, center.getZ() - 2);
y += getYOnSurfaceWG(world, center.getX() - 2, center.getZ() + 2); y += DefaultFeature.getYOnSurfaceWG(world, center.getX() - 2, center.getZ() + 2);
y += getYOnSurfaceWG(world, center.getX() + 2, center.getZ() + 2); y += DefaultFeature.getYOnSurfaceWG(world, center.getX() + 2, center.getZ() + 2);
return y / 5; return y / 5;
} }
@Override @Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) { public boolean place(FeaturePlaceContext<FC> context) {
FC cfg = context.config();
WorldGenLevel world = context.level(); WorldGenLevel world = context.level();
RandomSource random = context.random(); RandomSource random = context.random();
BlockPos center = context.origin(); BlockPos center = context.origin();
@ -103,7 +103,7 @@ public abstract class NBTFeature extends DefaultFeature {
} }
int posY = center.getY() + 1; int posY = center.getY() + 1;
StructureTemplate structure = getStructure(world, center, random); StructureTemplate structure = getStructure(cfg, world, center, random);
Rotation rotation = getRotation(world, center, random); Rotation rotation = getRotation(world, center, random);
Mirror mirror = getMirror(world, center, random); Mirror mirror = getMirror(world, center, random);
BlockPos offset = StructureTemplate.transform( BlockPos offset = StructureTemplate.transform(
@ -160,7 +160,7 @@ public abstract class NBTFeature extends DefaultFeature {
Holder<Biome> b = world.getBiome(mut); Holder<Biome> b = world.getBiome(mut);
BlockState top = (isTop BlockState top = (isTop
? BiomeAPI.findTopMaterial(b) ? BiomeAPI.findTopMaterial(b)
: BiomeAPI.findUnderMaterial(b)).orElse(defaultBlock); : BiomeAPI.findUnderMaterial(b)).orElse(cfg.defaultBlock);
BlocksHelper.setWithoutUpdate(world, mut, top); BlocksHelper.setWithoutUpdate(world, mut, top);
} else { } else {
BlocksHelper.setWithoutUpdate(world, mut, state); BlocksHelper.setWithoutUpdate(world, mut, state);
@ -169,7 +169,7 @@ public abstract class NBTFeature extends DefaultFeature {
if (isTerrain(state) && state.getMaterial().isSolidBlocking()) { if (isTerrain(state) && state.getMaterial().isSolidBlocking()) {
if (merge == TerrainMerge.SURFACE) { if (merge == TerrainMerge.SURFACE) {
Holder<Biome> b = world.getBiome(mut); 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); BlocksHelper.setWithoutUpdate(world, mut, bottom);
} else { } else {
BlocksHelper.setWithoutUpdate(world, mut, state); BlocksHelper.setWithoutUpdate(world, mut, state);
@ -222,9 +222,11 @@ public abstract class NBTFeature extends DefaultFeature {
return template; return template;
} }
public enum TerrainMerge { public enum TerrainMerge implements StringRepresentable {
NONE, SURFACE, OBJECT; NONE, SURFACE, OBJECT;
public static final Codec<TerrainMerge> CODEC = StringRepresentable.fromEnum(TerrainMerge::values);
public static TerrainMerge getFromString(String type) { public static TerrainMerge getFromString(String type) {
if (type.equals("surface")) { if (type.equals("surface")) {
return SURFACE; return SURFACE;
@ -234,5 +236,10 @@ public abstract class NBTFeature extends DefaultFeature {
return NONE; 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.betterend.util.GlobalState;
import org.betterx.worlds.together.tag.v3.CommonBlockTags; import org.betterx.worlds.together.tag.v3.CommonBlockTags;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos; import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
public abstract class ScatterFeature extends DefaultFeature { public abstract class ScatterFeature<FC extends ScatterFeatureConfig> extends Feature<FC> {
private final int radius; public ScatterFeature(Codec<FC> codec) {
super(codec);
public ScatterFeature(int radius) {
this.radius = radius;
} }
public abstract boolean canGenerate( public abstract boolean canGenerate(
FC cfg,
WorldGenLevel world, WorldGenLevel world,
RandomSource random, RandomSource random,
BlockPos center, BlockPos center,
@ -28,19 +28,19 @@ public abstract class ScatterFeature extends DefaultFeature {
float radius 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) { protected BlockPos getCenterGround(FC cfg, WorldGenLevel world, BlockPos pos) {
return getPosOnSurfaceWG(world, 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) { if (pos.getY() < 5) {
return false; return false;
} else return world.getBlockState(pos.below()).is(CommonBlockTags.END_STONES); } 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); int down = BlocksHelper.downRay(world, pos, 16);
if (down > Math.abs(getYOffset() * 2)) { if (down > Math.abs(getYOffset() * 2)) {
return false; return false;
@ -58,18 +58,19 @@ public abstract class ScatterFeature extends DefaultFeature {
} }
@Override @Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featureConfig) { public boolean place(FeaturePlaceContext<FC> featureConfig) {
FC cfg = featureConfig.config();
final MutableBlockPos POS = GlobalState.stateForThread().POS; final MutableBlockPos POS = GlobalState.stateForThread().POS;
final RandomSource random = featureConfig.random(); final RandomSource random = featureConfig.random();
BlockPos center = featureConfig.origin(); BlockPos center = featureConfig.origin();
final WorldGenLevel world = featureConfig.level(); 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; 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)); int count = MHelper.floor(r * r * MHelper.randRange(1.5F, 3F, random));
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
float pr = r * (float) Math.sqrt(random.nextFloat()); 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); float z = pr * (float) Math.sin(theta);
POS.set(center.getX() + x, center.getY() + getYOffset(), center.getZ() + z); POS.set(center.getX() + x, center.getY() + getYOffset(), center.getZ() + z);
if (getGroundPlant(world, POS) && canGenerate( if (getGroundPlant(cfg, world, POS) && canGenerate(
cfg,
world, world,
random, random,
center, center,
POS, POS,
r r
) && (getChance() < 2 || random.nextInt(getChance()) == 0)) { ) && (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.core.Direction;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BlockStateProperties;
public class SingleInvertedScatterFeature extends InvertedScatterFeature { public class SingleInvertedScatterFeature extends InvertedScatterFeature<SinglePlantFeatureConfig> {
private final Block block; private BlockState block;
public SingleInvertedScatterFeature(Block block, int radius) { public SingleInvertedScatterFeature() {
super(radius); super(SinglePlantFeatureConfig.CODEC);
this.block = block;
} }
@Override @Override
public boolean canGenerate( public boolean canGenerate(
SinglePlantFeatureConfig cfg,
WorldGenLevel world, WorldGenLevel world,
RandomSource random, RandomSource random,
BlockPos center, BlockPos center,
@ -30,17 +29,18 @@ public class SingleInvertedScatterFeature extends InvertedScatterFeature {
if (!world.isEmptyBlock(blockPos)) { if (!world.isEmptyBlock(blockPos)) {
return false; return false;
} }
BlockState state = block.defaultBlockState(); block = cfg.getPlantState(random, blockPos);
if (block instanceof BaseAttachedBlock) { BlockState state = block;
if (block.getBlock() instanceof BaseAttachedBlock) {
state = state.setValue(BlockStateProperties.FACING, Direction.DOWN); state = state.setValue(BlockStateProperties.FACING, Direction.DOWN);
} }
return state.canSurvive(world, blockPos); return state.canSurvive(world, blockPos);
} }
@Override @Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) { public void generate(SinglePlantFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
BlockState state = block.defaultBlockState(); BlockState state = block;
if (block instanceof BaseAttachedBlock) { if (block.getBlock() instanceof BaseAttachedBlock) {
state = state.setValue(BlockStateProperties.FACING, Direction.DOWN); state = state.setValue(BlockStateProperties.FACING, Direction.DOWN);
} }
BlocksHelper.setWithoutUpdate(world, blockPos, state); BlocksHelper.setWithoutUpdate(world, blockPos, state);

View file

@ -1,5 +1,6 @@
package org.betterx.betterend.world.features; 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.BaseCropBlock;
import org.betterx.bclib.blocks.BaseDoublePlantBlock; import org.betterx.bclib.blocks.BaseDoublePlantBlock;
import org.betterx.bclib.util.BlocksHelper; 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.core.BlockPos;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
public class SinglePlantFeature extends ScatterFeature { public class SinglePlantFeature extends ScatterFeature<SinglePlantFeatureConfig> {
private final Block plant;
private final boolean rawHeightmap;
private final int chance;
public SinglePlantFeature(Block plant, int radius) { BlockState plant;
this(plant, radius, true, 1);
}
public SinglePlantFeature(Block plant, int radius, int chance) { public SinglePlantFeature() {
this(plant, radius, true, chance); super(SinglePlantFeatureConfig.CODEC);
}
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;
} }
@Override @Override
protected BlockPos getCenterGround(WorldGenLevel world, BlockPos pos) { protected BlockPos getCenterGround(SinglePlantFeatureConfig cfg, WorldGenLevel world, BlockPos pos) {
return rawHeightmap ? getPosOnSurfaceWG(world, pos) : getPosOnSurface(world, pos); return cfg.rawHeightmap
? DefaultFeature.getPosOnSurfaceWG(world, pos)
: DefaultFeature.getPosOnSurface(world, pos);
} }
@Override @Override
public boolean canGenerate( public boolean canGenerate(
SinglePlantFeatureConfig cfg,
WorldGenLevel world, WorldGenLevel world,
RandomSource random, RandomSource random,
BlockPos center, BlockPos center,
BlockPos blockPos, BlockPos blockPos,
float radius float radius
) { ) {
this.plant = cfg.getPlantState(random, blockPos);
//noinspection deprecation //noinspection deprecation
return plant.canSurvive(plant.defaultBlockState(), world, blockPos); return plant.getBlock().canSurvive(plant, world, blockPos);
} }
@Override @Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) { public void generate(SinglePlantFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
if (plant instanceof BaseDoublePlantBlock) { if (this.plant.getBlock() instanceof BaseDoublePlantBlock) {
int rot = random.nextInt(4); 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, state);
BlocksHelper.setWithoutUpdate(world, blockPos.above(), state.setValue(BaseDoublePlantBlock.TOP, true)); BlocksHelper.setWithoutUpdate(world, blockPos.above(), state.setValue(BaseDoublePlantBlock.TOP, true));
} else if (plant instanceof BaseCropBlock) { } else if (this.plant.getBlock() instanceof BaseCropBlock) {
BlockState state = plant.defaultBlockState().setValue(BaseCropBlock.AGE, 3); BlockState state = this.plant.setValue(BaseCropBlock.AGE, 3);
BlocksHelper.setWithoutUpdate(world, blockPos, state); BlocksHelper.setWithoutUpdate(world, blockPos, state);
} else if (plant instanceof EndPlantWithAgeBlock) { } else if (this.plant.getBlock() instanceof EndPlantWithAgeBlock) {
int age = random.nextInt(4); 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); BlocksHelper.setWithoutUpdate(world, blockPos, state);
} else { } 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.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
public abstract class SkyScatterFeature extends ScatterFeature { public abstract class SkyScatterFeature extends ScatterFeature<ScatterFeatureConfig> {
public SkyScatterFeature(int radius) { public SkyScatterFeature() {
super(radius); super(ScatterFeatureConfig.CODEC);
} }
@Override @Override
@ -21,6 +21,7 @@ public abstract class SkyScatterFeature extends ScatterFeature {
@Override @Override
public boolean canGenerate( public boolean canGenerate(
ScatterFeatureConfig cfg,
WorldGenLevel world, WorldGenLevel world,
RandomSource random, RandomSource random,
BlockPos center, BlockPos center,
@ -44,12 +45,12 @@ public abstract class SkyScatterFeature extends ScatterFeature {
} }
@Override @Override
protected boolean canSpawn(WorldGenLevel world, BlockPos pos) { protected boolean canSpawn(ScatterFeatureConfig cfg, WorldGenLevel world, BlockPos pos) {
return true; return true;
} }
@Override @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()); 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.core.BlockPos;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
public class UnderwaterPlantFeature extends UnderwaterPlantScatter { public class UnderwaterPlantFeature extends UnderwaterPlantScatter<SinglePlantFeatureConfig> {
private final Block plant; private BlockState plant;
public UnderwaterPlantFeature() {
super(SinglePlantFeatureConfig.CODEC);
public UnderwaterPlantFeature(Block plant, int radius) {
super(radius);
this.plant = plant;
} }
@Override @Override
public boolean canGenerate( public boolean canGenerate(
SinglePlantFeatureConfig cfg,
WorldGenLevel world, WorldGenLevel world,
RandomSource random, RandomSource random,
BlockPos center, BlockPos center,
BlockPos blockPos, BlockPos blockPos,
float radius float radius
) { ) {
plant = cfg.getPlantState(random, blockPos);
//noinspection deprecation //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 @Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) { public void generate(SinglePlantFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
if (plant instanceof BaseDoublePlantBlock) { if (plant.getBlock() instanceof BaseDoublePlantBlock) {
int rot = random.nextInt(4); 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, state);
BlocksHelper.setWithoutUpdate(world, blockPos.above(), state.setValue(BaseDoublePlantBlock.TOP, true)); BlocksHelper.setWithoutUpdate(world, blockPos.above(), state.setValue(BaseDoublePlantBlock.TOP, true));
} else { } else {

View file

@ -2,19 +2,20 @@ package org.betterx.betterend.world.features;
import org.betterx.betterend.util.GlobalState; import org.betterx.betterend.util.GlobalState;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos; import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
public abstract class UnderwaterPlantScatter extends ScatterFeature { public abstract class UnderwaterPlantScatter<FC extends ScatterFeatureConfig> extends ScatterFeature<FC> {
public UnderwaterPlantScatter(int radius) { public UnderwaterPlantScatter(Codec<FC> codec) {
super(radius); super(codec);
} }
@Override @Override
protected BlockPos getCenterGround(WorldGenLevel world, BlockPos pos) { protected BlockPos getCenterGround(FC cfg, WorldGenLevel world, BlockPos pos) {
final MutableBlockPos POS = GlobalState.stateForThread().POS; final MutableBlockPos POS = GlobalState.stateForThread().POS;
POS.setX(pos.getX()); POS.setX(pos.getX());
POS.setZ(pos.getZ()); POS.setZ(pos.getZ());
@ -24,6 +25,7 @@ public abstract class UnderwaterPlantScatter extends ScatterFeature {
@Override @Override
public boolean canGenerate( public boolean canGenerate(
FC cfg,
WorldGenLevel world, WorldGenLevel world,
RandomSource random, RandomSource random,
BlockPos center, BlockPos center,
@ -34,12 +36,12 @@ public abstract class UnderwaterPlantScatter extends ScatterFeature {
} }
@Override @Override
protected boolean canSpawn(WorldGenLevel world, BlockPos pos) { protected boolean canSpawn(FC cfg, WorldGenLevel world, BlockPos pos) {
return world.getBlockState(pos).is(Blocks.WATER); return world.getBlockState(pos).is(Blocks.WATER);
} }
@Override @Override
protected boolean getGroundPlant(WorldGenLevel world, MutableBlockPos pos) { protected boolean getGroundPlant(FC cfg, WorldGenLevel world, MutableBlockPos pos) {
return getGround(world, pos).getY() < 128; 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.core.BlockPos;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
public class VineFeature extends InvertedScatterFeature { public class VineFeature extends InvertedScatterFeature<VineFeatureConfig> {
private final Block vineBlock; private BlockState plant;
private final int maxLength; boolean vine;
private final boolean vine;
public VineFeature(Block vineBlock, int maxLength) { public VineFeature() {
super(6); super(VineFeatureConfig.CODEC);
this.vineBlock = vineBlock;
this.maxLength = maxLength;
this.vine = vineBlock instanceof BaseVineBlock;
} }
@Override @Override
public boolean canGenerate( public boolean canGenerate(
VineFeatureConfig cfg,
WorldGenLevel world, WorldGenLevel world,
RandomSource random, RandomSource random,
BlockPos center, BlockPos center,
BlockPos blockPos, BlockPos blockPos,
float radius float radius
) { ) {
plant = cfg.getPlantState(random, blockPos);
BlockState state = world.getBlockState(blockPos); BlockState state = world.getBlockState(blockPos);
return state.getMaterial().isReplaceable() && canPlaceBlock(state, world, blockPos); return state.getMaterial().isReplaceable() && canPlaceBlock(state, world, blockPos);
} }
@Override @Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos blockPos) { public void generate(VineFeatureConfig cfg, WorldGenLevel world, RandomSource random, BlockPos blockPos) {
int h = BlocksHelper.downRay(world, blockPos, random.nextInt(maxLength)) - 1; int h = BlocksHelper.downRay(world, blockPos, random.nextInt(cfg.maxLength)) - 1;
if (h > 2) { if (h > 2) {
BlockState top = getTopState(); BlockState top = getTopState();
BlockState middle = getMiggleState(); BlockState middle = getMiddleState();
BlockState bottom = getBottomState(); BlockState bottom = getBottomState();
BlocksHelper.setWithoutUpdate(world, blockPos, top); BlocksHelper.setWithoutUpdate(world, blockPos, top);
for (int i = 1; i < h; i++) { 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) { private boolean canPlaceBlock(BlockState state, WorldGenLevel world, BlockPos blockPos) {
if (vine) { if (plant == null) return false;
return ((BaseVineBlock) vineBlock).canGenerate(state, world, blockPos); if (plant.getBlock() instanceof BaseVineBlock vineBlock) {
vine = true;
return vineBlock.canGenerate(state, world, blockPos);
} else { } else {
return vineBlock.canSurvive(state, world, blockPos); vine = false;
return plant.getBlock().canSurvive(state, world, blockPos);
} }
} }
private BlockState getTopState() { private BlockState getTopState() {
BlockState state = vineBlock.defaultBlockState(); BlockState state = plant;
return vine ? state.setValue(BlockProperties.TRIPLE_SHAPE, TripleShape.TOP) : state; return vine ? state.setValue(BlockProperties.TRIPLE_SHAPE, TripleShape.TOP) : state;
} }
private BlockState getMiggleState() { private BlockState getMiddleState() {
BlockState state = vineBlock.defaultBlockState(); BlockState state = plant;
return vine ? state.setValue(BlockProperties.TRIPLE_SHAPE, TripleShape.MIDDLE) : state; return vine ? state.setValue(BlockProperties.TRIPLE_SHAPE, TripleShape.MIDDLE) : state;
} }
private BlockState getBottomState() { private BlockState getBottomState() {
BlockState state = vineBlock.defaultBlockState(); BlockState state = plant;
return vine ? state.setValue(BlockProperties.TRIPLE_SHAPE, TripleShape.BOTTOM) : state; 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.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BlockStateProperties;
public class WallPlantFeature extends WallScatterFeature { public class WallPlantFeature extends WallScatterFeature<WallPlantFeatureConfig> {
private final Block block; protected BlockState plant;
public WallPlantFeature(Block block, int radius) { public WallPlantFeature() {
super(radius); super(WallPlantFeatureConfig.CODEC);
this.block = block;
} }
@Override @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) { 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); return block.canSurvive(state, world, pos);
} else if (block instanceof BaseAttachedBlock) { } 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(state, world, pos);
} }
return block.canSurvive(block.defaultBlockState(), world, pos); return block.canSurvive(plant, world, pos);
} }
@Override @Override
public void generate(WorldGenLevel world, RandomSource random, BlockPos pos, Direction dir) { public void generate(
BlockState state = block.defaultBlockState(); WallPlantFeatureConfig cfg,
WorldGenLevel world,
RandomSource random,
BlockPos pos,
Direction dir
) {
Block block = plant.getBlock();
if (block instanceof BaseWallPlantBlock) { if (block instanceof BaseWallPlantBlock) {
state = state.setValue(BaseWallPlantBlock.FACING, dir); plant = plant.setValue(BaseWallPlantBlock.FACING, dir);
} else if (block instanceof BaseAttachedBlock) { } 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.tags.BlockTags;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
public class WallPlantOnLogFeature extends WallPlantFeature { public class WallPlantOnLogFeature extends WallPlantFeature {
public WallPlantOnLogFeature(Block block, int radius) {
super(block, radius);
}
@Override @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()); BlockPos blockPos = pos.relative(dir.getOpposite());
BlockState blockState = world.getBlockState(blockPos); BlockState blockState = world.getBlockState(blockPos);
return blockState.is(BlockTags.LOGS); return blockState.is(BlockTags.LOGS);

View file

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

View file

@ -14,32 +14,25 @@ import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; 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.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import com.google.common.collect.Lists; public class ArchFeature extends Feature<ArchFeatureConfig> {
public ArchFeature() {
import java.util.List; super(ArchFeatureConfig.CODEC);
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;
} }
@Override @Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featurePlaceContext) { public boolean place(FeaturePlaceContext<ArchFeatureConfig> featurePlaceContext) {
ArchFeatureConfig cfg = featurePlaceContext.config();
final WorldGenLevel world = featurePlaceContext.level(); final WorldGenLevel world = featurePlaceContext.level();
BlockPos origin = featurePlaceContext.origin(); BlockPos origin = featurePlaceContext.origin();
RandomSource random = featurePlaceContext.random(); RandomSource random = featurePlaceContext.random();
BlockState cfgBlockState = cfg.block.getState(random, origin);
BlockPos pos = getPosOnSurfaceWG( Block cfgBlock = cfgBlockState.getBlock();
BlockPos pos = DefaultFeature.getPosOnSurfaceWG(
world, world,
new BlockPos((origin.getX() & 0xFFFFFFF0) | 7, 0, (origin.getZ() & 0xFFFFFFF0) | 7) new BlockPos((origin.getX() & 0xFFFFFFF0) | 7, 0, (origin.getZ() & 0xFFFFFFF0) | 7)
); );
@ -52,13 +45,12 @@ public class ArchFeature extends DefaultFeature {
if (smallRadius + bigRadius > 23) { if (smallRadius + bigRadius > 23) {
smallRadius = 23 - bigRadius; 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); arch = new SDFRotation().setRotation(MHelper.randomHorizontal(random), (float) Math.PI * 0.5F).setSource(arch);
final float smallRadiusF = smallRadius; final float smallRadiusF = smallRadius;
OpenSimplexNoise noise = new OpenSimplexNoise(random.nextLong()); OpenSimplexNoise noise = new OpenSimplexNoise(random.nextLong());
arch = new SDFDisplacement().setFunction((vec) -> { arch = new SDFDisplacement().setFunction((vec) -> (float) (Math.abs(noise.eval(
return (float) (Math.abs(noise.eval(
vec.x() * 0.1, vec.x() * 0.1,
vec.y() * 0.1, vec.y() * 0.1,
vec.z() * 0.1 vec.z() * 0.1
@ -66,13 +58,11 @@ public class ArchFeature extends DefaultFeature {
vec.x() * 0.3, vec.x() * 0.3,
vec.y() * 0.3 + 100, vec.y() * 0.3 + 100,
vec.z() * 0.3 vec.z() * 0.3
)) * 1.3F) - smallRadiusF * Math.abs(1 - vec.y() / bigRadius); )) * 1.3F) - smallRadiusF * Math.abs(1 - vec.y() / bigRadius)).setSource(arch);
}).setSource(arch);
List<BlockPos> surface = Lists.newArrayList();
arch.addPostProcess((info) -> { arch.addPostProcess((info) -> {
if (info.getStateUp().isAir()) { if (info.getStateUp().isAir()) {
return surfaceFunction.apply(info.getPos()); return cfg.surfaceFunction.apply(info.getPos());
} }
return info.getState(); 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; 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.SDF;
import org.betterx.bclib.sdf.operator.SDFCoordModify; import org.betterx.bclib.sdf.operator.SDFCoordModify;
import org.betterx.bclib.sdf.operator.SDFScale3D; import org.betterx.bclib.sdf.operator.SDFScale3D;
import org.betterx.bclib.sdf.primitive.SDFSphere; import org.betterx.bclib.sdf.primitive.SDFSphere;
import org.betterx.bclib.util.MHelper; import org.betterx.bclib.util.MHelper;
import org.betterx.betterend.noise.OpenSimplexNoise;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks; 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.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 SDFSphere SPHERE;
private static final SDFCoordModify NOISE; private static final SDFCoordModify NOISE;
private static final SDF FUNCTION; 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) { public OreLayerFeature() {
this.state = state; super(OreLayerFeatureConfig.CODEC);
this.radius = radius;
this.minY = minY;
this.maxY = maxY;
} }
@Override @Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featureConfig) { public boolean place(FeaturePlaceContext<OreLayerFeatureConfig> featureConfig) {
final OreLayerFeatureConfig cfg = featureConfig.config();
final RandomSource random = featureConfig.random(); final RandomSource random = featureConfig.random();
final BlockPos pos = featureConfig.origin(); final BlockPos pos = featureConfig.origin();
final WorldGenLevel world = featureConfig.level(); final WorldGenLevel world = featureConfig.level();
float radius = this.radius * 0.5F; float radius = cfg.radius * 0.5F;
int r = MHelper.floor(radius + 1); int r = MHelper.floor(radius + 1);
int posX = MHelper.randRange(Math.max(r - 16, 0), Math.min(31 - r, 15), random) + pos.getX(); 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 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) -> { NOISE.setFunction((vec) -> {
double x = (vec.x() + pos.getX()) * 0.1; double x = (vec.x() + pos.getX()) * 0.1;
double z = (vec.z() + pos.getZ()) * 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()); vec.set(vec.x(), vec.y() + (float) offset * 8, vec.z());
}); });
FUNCTION.fillRecursive(world, new BlockPos(posX, posY, posZ)); 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.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block; 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.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public class ThinArchFeature extends DefaultFeature { public class ThinArchFeature extends Feature<ThinArchFeatureConfig> {
private final Block block;
public ThinArchFeature(Block block) { public ThinArchFeature() {
this.block = block; super(ThinArchFeatureConfig.CODEC);
} }
@Override @Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featurePlaceContext) { public boolean place(FeaturePlaceContext<ThinArchFeatureConfig> featurePlaceContext) {
final ThinArchFeatureConfig cfg = featurePlaceContext.config();
final WorldGenLevel world = featurePlaceContext.level(); final WorldGenLevel world = featurePlaceContext.level();
BlockPos origin = featurePlaceContext.origin(); BlockPos origin = featurePlaceContext.origin();
RandomSource random = featurePlaceContext.random(); RandomSource random = featurePlaceContext.random();
BlockState state = cfg.block.getState(random, origin);
Block block = state.getBlock();
BlockPos pos = getPosOnSurfaceWG( BlockPos pos = DefaultFeature.getPosOnSurfaceWG(
world, world,
new BlockPos( new BlockPos(
(origin.getX() & 0xFFFFFFF0) | 7, (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; 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.bclib.util.BlocksHelper;
import org.betterx.betterend.util.BlockFixer; import org.betterx.betterend.util.BlockFixer;
import org.betterx.betterend.world.biome.cave.EndCaveBiome; 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.chunk.ChunkAccess;
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.feature.configurations.NoneFeatureConfiguration;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier;
public class CaveChunkPopulatorFeature extends DefaultFeature { public class CaveChunkPopulatorFeature extends Feature<CaveChunkPopulatorFeatureConfig> {
private final Supplier<EndCaveBiome> supplier;
public CaveChunkPopulatorFeature(Supplier<EndCaveBiome> biome) { public CaveChunkPopulatorFeature() {
this.supplier = biome; super(CaveChunkPopulatorFeatureConfig.CODEC);
} }
@Override @Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> featureConfig) { public boolean place(FeaturePlaceContext<CaveChunkPopulatorFeatureConfig> featureConfig) {
CaveChunkPopulatorFeatureConfig cfg = featureConfig.config();
final RandomSource random = featureConfig.random(); final RandomSource random = featureConfig.random();
final BlockPos pos = featureConfig.origin(); final BlockPos pos = featureConfig.origin();
final WorldGenLevel world = featureConfig.level(); final WorldGenLevel world = featureConfig.level();
@ -42,7 +39,7 @@ public class CaveChunkPopulatorFeature extends DefaultFeature {
MutableBlockPos min = new MutableBlockPos().set(pos); MutableBlockPos min = new MutableBlockPos().set(pos);
MutableBlockPos max = new MutableBlockPos().set(pos); MutableBlockPos max = new MutableBlockPos().set(pos);
fillSets(sx, sz, world.getChunk(pos), floorPositions, ceilPositions, min, max); 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(); BlockState surfaceBlock = Blocks.END_STONE.defaultBlockState(); //biome.getBiome().getGenerationSettings().getSurfaceBuilderConfig().getTopMaterial();
placeFloor(world, biome, floorPositions, random, surfaceBlock); placeFloor(world, biome, floorPositions, random, surfaceBlock);
placeCeil(world, biome, ceilPositions, random); 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);
}
}