diff --git a/src/main/java/org/betterx/bclib/BCLib.java b/src/main/java/org/betterx/bclib/BCLib.java index 66d4a803..ac43126a 100644 --- a/src/main/java/org/betterx/bclib/BCLib.java +++ b/src/main/java/org/betterx/bclib/BCLib.java @@ -25,6 +25,7 @@ import org.betterx.bclib.util.Logger; import org.betterx.bclib.world.generator.BCLibEndBiomeSource; import org.betterx.bclib.world.generator.BCLibNetherBiomeSource; import org.betterx.bclib.world.generator.GeneratorOptions; +import org.betterx.bclib.world.structures.TemplatePiece; import java.util.List; @@ -49,15 +50,16 @@ public class BCLib implements ModInitializer { AnvilRecipe.register(); DataExchangeAPI.registerDescriptors(List.of( - HelloClient.DESCRIPTOR, - HelloServer.DESCRIPTOR, - RequestFiles.DESCRIPTOR, - SendFiles.DESCRIPTOR, - Chunker.DESCRIPTOR - ) - ); + HelloClient.DESCRIPTOR, + HelloServer.DESCRIPTOR, + RequestFiles.DESCRIPTOR, + SendFiles.DESCRIPTOR, + Chunker.DESCRIPTOR + ) + ); BCLibPatch.register(); + TemplatePiece.ensureStaticInitialization(); Configs.save(); if (isDevEnvironment()) { Biome.BiomeBuilder builder = new Biome.BiomeBuilder() diff --git a/src/main/java/org/betterx/bclib/world/features/TemplateFeature.java b/src/main/java/org/betterx/bclib/world/features/TemplateFeature.java index 6e4b40c6..03a166da 100644 --- a/src/main/java/org/betterx/bclib/world/features/TemplateFeature.java +++ b/src/main/java/org/betterx/bclib/world/features/TemplateFeature.java @@ -12,24 +12,28 @@ import net.minecraft.world.level.levelgen.placement.EnvironmentScanPlacement; import com.mojang.serialization.Codec; import org.betterx.bclib.api.features.BCLFeatureBuilder; +import org.betterx.bclib.world.structures.StructureNBT; public class TemplateFeature extends Feature { public static final Feature INSTANCE = BCLFeature.register("template", - new TemplateFeature(TemplateFeatureConfig.CODEC)); + new TemplateFeature( + TemplateFeatureConfig.CODEC)); public static BCLFeature createAndRegister(TemplateFeatureConfig configuration, int onveEveryChunk) { return BCLFeatureBuilder .start(new ResourceLocation(configuration.structure.location.getNamespace(), - "feature_" + configuration.structure.location.getPath()), INSTANCE) + "feature_" + configuration.structure.location.getPath()), INSTANCE) .decoration(GenerationStep.Decoration.SURFACE_STRUCTURES) .oncePerChunks(onveEveryChunk) .squarePlacement() .distanceToTopAndBottom10() .modifier(EnvironmentScanPlacement.scanningFor(Direction.DOWN, - BlockPredicate.solid(), - BlockPredicate.matchesBlocks(Blocks.AIR, Blocks.WATER, Blocks.LAVA), - 12)) + BlockPredicate.solid(), + BlockPredicate.matchesBlocks(Blocks.AIR, + Blocks.WATER, + Blocks.LAVA), + 12)) .modifier(BiomeFilter.biome()) .buildAndRegister(configuration); } @@ -40,6 +44,10 @@ public class TemplateFeature extends Feature ctx) { - return ctx.config().structure.generateInRandomOrientation(ctx.level(), ctx.origin(), ctx.random()); + return ctx.config().structure.generateIfPlaceable(ctx.level(), + ctx.origin(), + StructureNBT.getRandomRotation(ctx.random()), + StructureNBT.getRandomMirror(ctx.random()) + ); } } diff --git a/src/main/java/org/betterx/bclib/world/structures/StructureNBT.java b/src/main/java/org/betterx/bclib/world/structures/StructureNBT.java index 576fb7dd..8c1bf179 100644 --- a/src/main/java/org/betterx/bclib/world/structures/StructureNBT.java +++ b/src/main/java/org/betterx/bclib/world/structures/StructureNBT.java @@ -26,8 +26,7 @@ import java.util.Map; public class StructureNBT { public final ResourceLocation location; protected StructureTemplate structure; - protected Mirror mirror = Mirror.NONE; - protected Rotation rotation = Rotation.NONE; + protected StructureNBT(ResourceLocation location) { this.location = location; @@ -39,44 +38,33 @@ public class StructureNBT { this.structure = structure; } + public static Rotation getRandomRotation(RandomSource random) { + return Rotation.getRandom(random) == Rotation.NONE ? Rotation.CLOCKWISE_90 : Rotation.COUNTERCLOCKWISE_90; + } + + public static Mirror getRandomMirror(RandomSource random) { + return Mirror.values()[random.nextInt(3)]; + } + private static final Map STRUCTURE_CACHE = Maps.newHashMap(); public static StructureNBT create(ResourceLocation location) { return STRUCTURE_CACHE.computeIfAbsent(location, r -> new StructureNBT(r)); } - public StructureNBT setRotation(Rotation rotation) { - this.rotation = rotation; - return this; - } - - public Mirror getMirror() { - return mirror; - } - - public StructureNBT setMirror(Mirror mirror) { - this.mirror = mirror; - return this; - } - - public void randomRM(RandomSource random) { - rotation = Rotation.values()[random.nextInt(4)]; - mirror = Mirror.values()[random.nextInt(3)]; - } - - public boolean generateCentered(ServerLevelAccessor world, BlockPos pos) { + public boolean generateCentered(ServerLevelAccessor world, BlockPos pos, Rotation rotation, Mirror mirror) { if (structure == null) { BCLib.LOGGER.error("No structure: " + location.toString()); return false; } MutableBlockPos blockpos2 = new MutableBlockPos().set(structure.getSize()); - if (this.mirror == Mirror.FRONT_BACK) + if (mirror == Mirror.FRONT_BACK) blockpos2.setX(-blockpos2.getX()); - if (this.mirror == Mirror.LEFT_RIGHT) + if (mirror == Mirror.LEFT_RIGHT) blockpos2.setZ(-blockpos2.getZ()); blockpos2.set(blockpos2.rotate(rotation)); - StructurePlaceSettings data = new StructurePlaceSettings().setRotation(this.rotation).setMirror(this.mirror); + StructurePlaceSettings data = new StructurePlaceSettings().setRotation(rotation).setMirror(mirror); BlockPos newPos = pos.offset(-blockpos2.getX() >> 1, 0, -blockpos2.getZ() >> 1); structure.placeInWorld( world, @@ -85,7 +73,7 @@ public class StructureNBT { data, world.getRandom(), Block.UPDATE_CLIENTS - ); + ); return true; } @@ -118,7 +106,7 @@ public class StructureNBT { return template; } - public BlockPos getSize() { + public BlockPos getSize(Rotation rotation) { if (rotation == Rotation.NONE || rotation == Rotation.CLOCKWISE_180) return new BlockPos(structure.getSize()); else { @@ -133,7 +121,7 @@ public class StructureNBT { return location.getPath(); } - public BoundingBox getBoundingBox(BlockPos pos) { - return structure.getBoundingBox(new StructurePlaceSettings().setRotation(this.rotation).setMirror(mirror), pos); + public BoundingBox getBoundingBox(BlockPos pos, Rotation rotation, Mirror mirror) { + return structure.getBoundingBox(new StructurePlaceSettings().setRotation(rotation).setMirror(mirror), pos); } } diff --git a/src/main/java/org/betterx/bclib/world/structures/StructureWorldNBT.java b/src/main/java/org/betterx/bclib/world/structures/StructureWorldNBT.java index 436c0a4c..7ef6a141 100644 --- a/src/main/java/org/betterx/bclib/world/structures/StructureWorldNBT.java +++ b/src/main/java/org/betterx/bclib/world/structures/StructureWorldNBT.java @@ -3,10 +3,10 @@ package org.betterx.bclib.world.structures; import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos.MutableBlockPos; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.RandomSource; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.levelgen.structure.BoundingBox; @@ -33,27 +33,29 @@ public class StructureWorldNBT extends StructureNBT { } - public boolean generateInRandomOrientation(ServerLevelAccessor level, BlockPos pos, RandomSource random) { - randomRM(random); - return generate(level, pos); - } - - public boolean generate(ServerLevelAccessor level, BlockPos pos) { - if (canGenerate(level, pos)) { - return generateCentered(level, pos.above(offsetY)); + public boolean generateIfPlaceable(ServerLevelAccessor level, + BlockPos pos, + Rotation r, + Mirror m) { + if (canGenerate(level, pos, r)) { + return generate(level, pos, r, m); } return false; } - protected boolean canGenerate(LevelAccessor level, BlockPos pos) { + public boolean generate(ServerLevelAccessor level, BlockPos pos, Rotation r, Mirror m) { + return generateCentered(level, pos.above(offsetY), r, m); + } + + protected boolean canGenerate(LevelAccessor level, BlockPos pos, Rotation rotation) { if (type == StructurePlacementType.FLOOR) - return canGenerateFloor(level, pos); + return canGenerateFloor(level, pos, rotation); else if (type == StructurePlacementType.LAVA) - return canGenerateLava(level, pos); + return canGenerateLava(level, pos, rotation); else if (type == StructurePlacementType.UNDER) - return canGenerateUnder(level, pos); + return canGenerateUnder(level, pos, rotation); else if (type == StructurePlacementType.CEIL) - return canGenerateCeil(level, pos); + return canGenerateCeil(level, pos, rotation); else return false; } @@ -67,46 +69,35 @@ public class StructureWorldNBT extends StructureNBT { return false; } - protected boolean canGenerateFloor(LevelAccessor world, BlockPos pos) { + protected boolean canGenerateFloor(LevelAccessor world, BlockPos pos, Rotation rotation) { if (containsBedrock(world, pos)) return false; - return getAirFraction(world, pos) > 0.6 && getAirFractionFoundation(world, pos) < 0.5; + return getAirFraction(world, pos, rotation) > 0.6 && getAirFractionFoundation(world, pos, rotation) < 0.5; } - protected boolean canGenerateLava(LevelAccessor world, BlockPos pos) { + protected boolean canGenerateLava(LevelAccessor world, BlockPos pos, Rotation rotation) { if (containsBedrock(world, pos)) return false; - return getLavaFractionFoundation(world, pos) > 0.9 && getAirFraction(world, pos) > 0.9; + return getLavaFractionFoundation(world, pos, rotation) > 0.9 && getAirFraction(world, pos, rotation) > 0.9; } - protected boolean canGenerateUnder(LevelAccessor world, BlockPos pos) { + protected boolean canGenerateUnder(LevelAccessor world, BlockPos pos, Rotation rotation) { if (containsBedrock(world, pos)) return false; - return getAirFraction(world, pos) < 0.2; + return getAirFraction(world, pos, rotation) < 0.2; } - protected boolean canGenerateCeil(LevelAccessor world, BlockPos pos) { + protected boolean canGenerateCeil(LevelAccessor world, BlockPos pos, Rotation rotation) { if (containsBedrock(world, pos)) return false; - return getAirFractionBottom(world, pos) > 0.8 && getAirFraction(world, pos) < 0.6; + return getAirFractionBottom(world, pos, rotation) > 0.8 && getAirFraction(world, pos, rotation) < 0.6; } public BoundingBox boundingBox(Rotation r, BlockPos p) { - MutableBlockPos size = new MutableBlockPos().set(new BlockPos(structure.getSize()).rotate(rotation)); - size.setX(Math.abs(size.getX()) >> 1); - size.setY(Math.abs(size.getY()) >> 1); - size.setZ(Math.abs(size.getZ()) >> 1); - return new BoundingBox( - p.getX() - size.getX(), - p.getY() - size.getY(), - p.getZ() - size.getZ(), - p.getX() + size.getX(), - p.getY() + size.getY(), - p.getZ() + size.getZ() - ); + return getBoundingBox(p, r, Mirror.NONE); } - protected float getAirFraction(LevelAccessor world, BlockPos pos) { + protected float getAirFraction(LevelAccessor world, BlockPos pos, Rotation rotation) { final MutableBlockPos POS = new MutableBlockPos(); int airCount = 0; @@ -134,7 +125,7 @@ public class StructureWorldNBT extends StructureNBT { return (float) airCount / count; } - private float getLavaFractionFoundation(LevelAccessor world, BlockPos pos) { + private float getLavaFractionFoundation(LevelAccessor world, BlockPos pos, Rotation rotation) { final MutableBlockPos POS = new MutableBlockPos(); int lavaCount = 0; @@ -161,7 +152,7 @@ public class StructureWorldNBT extends StructureNBT { return (float) lavaCount / count; } - private float getAirFractionFoundation(LevelAccessor world, BlockPos pos) { + private float getAirFractionFoundation(LevelAccessor world, BlockPos pos, Rotation rotation) { final MutableBlockPos POS = new MutableBlockPos(); int airCount = 0; @@ -189,7 +180,7 @@ public class StructureWorldNBT extends StructureNBT { return (float) airCount / count; } - private float getAirFractionBottom(LevelAccessor world, BlockPos pos) { + private float getAirFractionBottom(LevelAccessor world, BlockPos pos, Rotation rotation) { final MutableBlockPos POS = new MutableBlockPos(); int airCount = 0; diff --git a/src/main/java/org/betterx/bclib/world/structures/TemplatePiece.java b/src/main/java/org/betterx/bclib/world/structures/TemplatePiece.java index b7d9ddbb..a97989d8 100644 --- a/src/main/java/org/betterx/bclib/world/structures/TemplatePiece.java +++ b/src/main/java/org/betterx/bclib/world/structures/TemplatePiece.java @@ -6,34 +6,154 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.RandomSource; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.StructureManager; import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.StructurePiece; +import net.minecraft.world.level.levelgen.structure.TemplateStructurePiece; import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext; import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceType; +import net.minecraft.world.level.levelgen.structure.templatesystem.BlockIgnoreProcessor; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; import org.betterx.bclib.BCLib; +import org.betterx.bclib.util.BlocksHelper; -public class TemplatePiece extends StructurePiece { - public static final StructurePieceType INSTANCE = register("template_piece", TemplatePiece::new); +public class TemplatePiece extends TemplateStructurePiece { + public static final StructurePieceType INSTANCE = setTemplatePieceId(TemplatePiece::new, + "template_piece"); + + + private static StructurePieceType setFullContextPieceId(StructurePieceType structurePieceType, String id) { + return Registry.register(Registry.STRUCTURE_PIECE, BCLib.makeID(id), structurePieceType); + } + + private static StructurePieceType setTemplatePieceId(StructurePieceType.StructureTemplateType structureTemplateType, + String string) { + return setFullContextPieceId(structureTemplateType, string); + } + + + public static void ensureStaticInitialization() { + } + + + public TemplatePiece(StructureTemplateManager structureTemplateManager, + ResourceLocation resourceLocation, + BlockPos centerPos, + Rotation rotation, + Mirror mirror, + BlockPos halfSize) { + super(INSTANCE, + 0, + structureTemplateManager, + resourceLocation, + resourceLocation.toString(), + makeSettings(rotation, mirror, halfSize), + shiftPos(halfSize, centerPos)); + } + + public TemplatePiece(StructureTemplateManager structureTemplateManager, CompoundTag compoundTag) { + super(INSTANCE, + compoundTag, + structureTemplateManager, + (ResourceLocation resourceLocation) -> makeSettings(compoundTag)); + } + + + @Override + public void postProcess(WorldGenLevel level, + StructureManager structureManager, + ChunkGenerator chunkGenerator, + RandomSource randomSource, + BoundingBox boundingBox, + ChunkPos chunkPos, + BlockPos blockPos) { + super.postProcess(level, + structureManager, + chunkGenerator, + randomSource, + boundingBox, + chunkPos, + blockPos); + + BlocksHelper.setWithoutUpdate(level, new BlockPos(boundingBox.minX(), boundingBox.minY(), boundingBox.minZ()), + Blocks.YELLOW_CONCRETE); + BlocksHelper.setWithoutUpdate(level, new BlockPos(boundingBox.maxX(), boundingBox.maxY(), boundingBox.maxZ()), + Blocks.LIGHT_BLUE_CONCRETE); + BlocksHelper.setWithoutUpdate(level, boundingBox.getCenter(), + Blocks.LIME_CONCRETE); + BlocksHelper.setWithoutUpdate(level, blockPos, + Blocks.ORANGE_CONCRETE); + } + + private static BlockPos shiftPos(BlockPos halfSize, + BlockPos pos) { + return pos.offset(-(2 * halfSize.getX()), 0, -(2 * halfSize.getZ())); + //return pos; + } + + private static StructurePlaceSettings makeSettings(CompoundTag compoundTag) { + return makeSettings( + Rotation.valueOf(compoundTag.getString("R")), + Mirror.valueOf(compoundTag.getString("M")), + new BlockPos(compoundTag.getInt("RX"), compoundTag.getInt("RY"), compoundTag.getInt("RZ"))); + + } + + private static StructurePlaceSettings makeSettings(Rotation rotation, Mirror mirror, BlockPos halfSize) { + return new StructurePlaceSettings().setRotation(rotation) + .setMirror(mirror) + .setRotationPivot(halfSize) + .addProcessor(BlockIgnoreProcessor.STRUCTURE_BLOCK); + } + + @Override + protected void addAdditionalSaveData(StructurePieceSerializationContext structurePieceSerializationContext, + CompoundTag tag) { + super.addAdditionalSaveData(structurePieceSerializationContext, tag); + tag.putString("R", this.placeSettings.getRotation().name()); + tag.putString("M", this.placeSettings.getMirror().name()); + tag.putInt("RX", this.placeSettings.getRotationPivot().getX()); + tag.putInt("RY", this.placeSettings.getRotationPivot().getY()); + tag.putInt("RZ", this.placeSettings.getRotationPivot().getZ()); + } + + @Override + protected void handleDataMarker(String string, + BlockPos blockPos, + ServerLevelAccessor serverLevelAccessor, + RandomSource randomSource, + BoundingBox boundingBox) { + + } +} + +class TemplatePiece2 extends StructurePiece { + public static final StructurePieceType INSTANCE = register("template_piece_bcl", TemplatePiece2::new); private static StructurePieceType register(String id, StructurePieceType pieceType) { return Registry.register(Registry.STRUCTURE_PIECE, BCLib.makeID(id), pieceType); } + public static void ensureStaticInitialization() { + } + public final StructureWorldNBT structure; public final BlockPos pos; public final Rotation rot; public final Mirror mir; - protected TemplatePiece(StructureWorldNBT structure, - BlockPos pos, - Rotation rot, - Mirror mir) { + protected TemplatePiece2(StructureWorldNBT structure, + BlockPos pos, + Rotation rot, + Mirror mir) { super(INSTANCE, 0, structure.boundingBox(rot, pos)); this.structure = structure; this.rot = rot; @@ -41,7 +161,7 @@ public class TemplatePiece extends StructurePiece { this.pos = pos; } - public TemplatePiece(StructurePieceSerializationContext ctx, CompoundTag compoundTag) { + public TemplatePiece2(StructurePieceSerializationContext ctx, CompoundTag compoundTag) { super(INSTANCE, compoundTag); ResourceLocation location = new ResourceLocation(compoundTag.getString("L")); @@ -64,7 +184,7 @@ public class TemplatePiece extends StructurePiece { tag.putString("L", structure.location.toString()); tag.putInt("OY", structure.offsetY); - tag.putString("T", structure.type.getSerializedName()); + tag.putString("T", structure.type.name()); tag.putString("Rot", this.rot.name()); tag.putString("Mir", this.mir.name()); tag.putInt("PX", this.pos.getX()); @@ -80,6 +200,6 @@ public class TemplatePiece extends StructurePiece { BoundingBox boundingBox, ChunkPos chunkPos, BlockPos blockPos) { - structure.generateInRandomOrientation(worldGenLevel, blockPos, randomSource); + structure.generate(worldGenLevel, this.pos, this.rot, this.mir); } } diff --git a/src/main/java/org/betterx/bclib/world/structures/TemplateStructure.java b/src/main/java/org/betterx/bclib/world/structures/TemplateStructure.java index a3a3d515..2be1597f 100644 --- a/src/main/java/org/betterx/bclib/world/structures/TemplateStructure.java +++ b/src/main/java/org/betterx/bclib/world/structures/TemplateStructure.java @@ -2,88 +2,149 @@ package org.betterx.bclib.world.structures; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.ExtraCodecs; +import net.minecraft.util.RandomSource; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.NoiseColumn; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.levelgen.WorldgenRandom; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.WorldGenerationContext; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.Structure; -import net.minecraft.world.level.levelgen.structure.pieces.StructurePiecesBuilder; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -import com.mojang.datafixers.util.Function4; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import java.util.List; import java.util.Optional; +import java.util.function.BiFunction; public abstract class TemplateStructure extends Structure { - public static Codec simpleCodec(Function4 instancer) { + protected final List configs; + + public static Codec simpleCodec(BiFunction instancer) { return RecordCodecBuilder.create((instance) -> instance - .group( - Structure.settingsCodec(instance), - ResourceLocation.CODEC - .fieldOf("location") - .forGetter((T cfg) -> cfg.structure.location), - - Codec - .INT - .fieldOf("offset_y") - .orElse(0) - .forGetter((T cfg) -> cfg.structure.offsetY), - - StructurePlacementType.CODEC - .fieldOf("placement") - .orElse(StructurePlacementType.FLOOR) - .forGetter((T cfg) -> cfg.structure.type) - ) - .apply(instance, instancer) - ); + .group( + Structure.settingsCodec(instance), + ExtraCodecs.nonEmptyList(Config.CODEC.listOf()) + .fieldOf("configs") + .forGetter((T ruinedPortalStructure) -> ruinedPortalStructure.configs) + ) + .apply(instance, instancer) + ); } - public final StructureWorldNBT structure; - protected TemplateStructure(StructureSettings structureSettings, ResourceLocation location, int offsetY, - StructurePlacementType type) { - super(structureSettings); - structure = StructureWorldNBT.create(location, offsetY, type); + StructurePlacementType type, + float chance) { + this(structureSettings, List.of(new Config(location, offsetY, type, chance))); } + protected TemplateStructure(StructureSettings structureSettings, + List configs) { + super(structureSettings); + this.configs = configs; + } + + protected Config randomConfig(RandomSource random) { + Config config = null; + if (this.configs.size() > 1) { + final float chanceSum = configs.parallelStream().map(c -> c.chance()).reduce(0.0f, (p, c) -> p + c); + float rnd = random.nextFloat() * chanceSum; + + for (Config c : configs) { + rnd -= c.chance(); + if (rnd <= 0) return c; + } + } else { + return this.configs.get(0); + } + + return null; + } @Override public Optional findGenerationPoint(GenerationContext ctx) { + WorldGenerationContext worldGenerationContext = new WorldGenerationContext(ctx.chunkGenerator(), + ctx.heightAccessor()); + final Config config = randomConfig(ctx.random()); + if (config == null) return Optional.empty(); + ChunkPos chunkPos = ctx.chunkPos(); final int x = chunkPos.getMiddleBlockX(); final int z = chunkPos.getMiddleBlockZ(); - int y = ctx - .chunkGenerator() - .getFirstOccupiedHeight(x, - z, - Heightmap.Types.WORLD_SURFACE_WG, - ctx.heightAccessor(), - ctx.randomState()); + NoiseColumn column = ctx.chunkGenerator().getBaseColumn(x, z, ctx.heightAccessor(), ctx.randomState()); + final int seaLevel = ctx.chunkGenerator().getSeaLevel(); + StructureTemplate structureTemplate = ctx.structureTemplateManager().getOrCreate(config.location); + final int maxHeight = worldGenerationContext.getGenDepth() - 4 - (structureTemplate.getSize(Rotation.NONE) + .getY() + config.offsetY); + int y = seaLevel; + BlockState state = column.getBlock(y - 1); + for (; y < maxHeight; y++) { + BlockState below = state; + state = column.getBlock(y); + if (state.is(Blocks.AIR) && below.is(Blocks.LAVA)) break; + } + if (y >= maxHeight) return Optional.empty(); + + + BlockPos halfSize = new BlockPos(structureTemplate.getSize().getX() / 2, + 0, + structureTemplate.getSize().getZ() / 2); + Rotation rotation = StructureNBT.getRandomRotation(ctx.random()); + Mirror mirror = StructureNBT.getRandomMirror(ctx.random()); BlockPos centerPos = new BlockPos(x, y, z); - Rotation rotation = Rotation.getRandom(ctx.random()); - BoundingBox bb = structure.boundingBox(rotation, centerPos); + BoundingBox boundingBox = structureTemplate.getBoundingBox(centerPos, rotation, halfSize, mirror); + + // if (!structure.canGenerate(ctx.chunkGenerator()., centerPos)) return Optional.of(new GenerationStub(centerPos, - structurePiecesBuilder -> this.generatePieces(structurePiecesBuilder, centerPos, rotation, ctx))); + structurePiecesBuilder -> + structurePiecesBuilder.addPiece( + new TemplatePiece(ctx.structureTemplateManager(), + config.location, + centerPos.offset( + 0, + config.offsetY, + 0), + rotation, + mirror, + halfSize)) + )); } - private void generatePieces(StructurePiecesBuilder structurePiecesBuilder, - BlockPos centerPos, - Rotation rotation, - Structure.GenerationContext generationContext) { - WorldgenRandom worldgenRandom = generationContext.random(); + public record Config(ResourceLocation location, int offsetY, StructurePlacementType type, float chance) { + public static final Codec CODEC = + RecordCodecBuilder.create((instance) -> + instance.group( + ResourceLocation.CODEC + .fieldOf("location") + .forGetter((cfg) -> cfg.location), - Mirror mirror = Mirror.values()[worldgenRandom.nextInt(3)]; + Codec + .INT + .fieldOf("offset_y") + .orElse(0) + .forGetter((cfg) -> cfg.offsetY), - structurePiecesBuilder.addPiece(new TemplatePiece(structure, centerPos, rotation, mirror)); + StructurePlacementType.CODEC + .fieldOf("placement") + .orElse(StructurePlacementType.FLOOR) + .forGetter((cfg) -> cfg.type), + Codec + .FLOAT + .fieldOf("chance") + .orElse(1.0f) + .forGetter((cfg) -> cfg.chance) + ) + .apply(instance, Config::new) + ); } - - }