diff --git a/src/main/java/org/betterx/bclib/world/features/NBTFeature.java b/src/main/java/org/betterx/bclib/world/features/NBTFeature.java index 751b5219..0f0ed637 100644 --- a/src/main/java/org/betterx/bclib/world/features/NBTFeature.java +++ b/src/main/java/org/betterx/bclib/world/features/NBTFeature.java @@ -29,6 +29,7 @@ import org.betterx.bclib.world.processors.DestructionStructureProcessor; import java.io.IOException; import java.io.InputStream; +//TODO: 1.19 Check if we can merge this with the new TemplateFeature! public abstract class NBTFeature extends DefaultFeature { private final BlockState defaultBlock; @@ -107,7 +108,7 @@ public abstract class NBTFeature extends DefaultFeature { mirror, rotation, BlockPos.ZERO - ); + ); center = center.offset(0, getYOffset(structure, world, center, random) + 0.5, 0); BoundingBox bounds = makeBox(center); diff --git a/src/main/java/org/betterx/bclib/world/features/SurfaceFeature.java b/src/main/java/org/betterx/bclib/world/features/SurfaceFeature.java index bc6108a6..59c4d4c1 100644 --- a/src/main/java/org/betterx/bclib/world/features/SurfaceFeature.java +++ b/src/main/java/org/betterx/bclib/world/features/SurfaceFeature.java @@ -39,7 +39,11 @@ public abstract class SurfaceFeature extends Fea if (pos.isPresent()) { int y2 = ctx.level().getHeight(Heightmap.Types.WORLD_SURFACE_WG, ctx.origin().getX(), ctx.origin().getZ()); int y3 = ctx.level().getHeight(Heightmap.Types.WORLD_SURFACE, ctx.origin().getX(), ctx.origin().getZ()); - System.out.println("Surfaces:" + pos.get().getY() + ", " + y2 + ", " + y3 + ", " + ctx.origin().getY()); + int y4 = ctx.level().getHeight(Heightmap.Types.OCEAN_FLOOR, ctx.origin().getX(), ctx.origin().getZ()); + int y5 = ctx.level().getHeight(Heightmap.Types.OCEAN_FLOOR_WG, ctx.origin().getX(), ctx.origin().getZ()); + System.out.println("Surfaces:" + pos + .get() + .getY() + ", " + y2 + ", " + y3 + ", " + y4 + ", " + y5 + ", " + ctx.origin().getY()); generate(pos.get(), ctx); return true; 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 d721f423..6e4b40c6 100644 --- a/src/main/java/org/betterx/bclib/world/features/TemplateFeature.java +++ b/src/main/java/org/betterx/bclib/world/features/TemplateFeature.java @@ -40,6 +40,6 @@ public class TemplateFeature extends Feature ctx) { - return ctx.config().structure.generate(ctx.level(), ctx.origin(), ctx.random()); + return ctx.config().structure.generateInRandomOrientation(ctx.level(), ctx.origin(), ctx.random()); } } diff --git a/src/main/java/org/betterx/bclib/world/features/TemplateFeatureConfig.java b/src/main/java/org/betterx/bclib/world/features/TemplateFeatureConfig.java index 18d2642e..e9c4addb 100644 --- a/src/main/java/org/betterx/bclib/world/features/TemplateFeatureConfig.java +++ b/src/main/java/org/betterx/bclib/world/features/TemplateFeatureConfig.java @@ -31,6 +31,6 @@ public class TemplateFeatureConfig implements FeatureConfiguration { public final StructureWorldNBT structure; public TemplateFeatureConfig(ResourceLocation location, int offsetY, StructurePlacementType type) { - structure = new StructureWorldNBT(location, offsetY, type); + structure = StructureWorldNBT.create(location, offsetY, type); } } 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 fbb47d96..576fb7dd 100644 --- a/src/main/java/org/betterx/bclib/world/structures/StructureNBT.java +++ b/src/main/java/org/betterx/bclib/world/structures/StructureNBT.java @@ -16,10 +16,12 @@ import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import com.google.common.collect.Maps; import org.betterx.bclib.BCLib; import java.io.IOException; import java.io.InputStream; +import java.util.Map; public class StructureNBT { public final ResourceLocation location; @@ -27,7 +29,7 @@ public class StructureNBT { protected Mirror mirror = Mirror.NONE; protected Rotation rotation = Rotation.NONE; - public StructureNBT(ResourceLocation location) { + protected StructureNBT(ResourceLocation location) { this.location = location; this.structure = readStructureFromJar(location); } @@ -37,6 +39,12 @@ public class StructureNBT { this.structure = structure; } + 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; @@ -81,7 +89,13 @@ public class StructureNBT { return true; } + private static final Map READER_CACHE = Maps.newHashMap(); + private static StructureTemplate readStructureFromJar(ResourceLocation resource) { + return READER_CACHE.computeIfAbsent(resource, r -> _readStructureFromJar(r)); + } + + private static StructureTemplate _readStructureFromJar(ResourceLocation resource) { String ns = resource.getNamespace(); String nm = resource.getPath(); 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 dcd47285..436c0a4c 100644 --- a/src/main/java/org/betterx/bclib/world/structures/StructureWorldNBT.java +++ b/src/main/java/org/betterx/bclib/world/structures/StructureWorldNBT.java @@ -7,37 +7,53 @@ 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.Rotation; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import com.google.common.collect.Maps; import org.betterx.bclib.util.BlocksHelper; +import java.util.Map; + public class StructureWorldNBT extends StructureNBT { public final StructurePlacementType type; public final int offsetY; - public StructureWorldNBT(ResourceLocation location, int offsetY, StructurePlacementType type) { + protected StructureWorldNBT(ResourceLocation location, int offsetY, StructurePlacementType type) { super(location); this.offsetY = offsetY; this.type = type; } + private static final Map READER_CACHE = Maps.newHashMap(); - public boolean generate(ServerLevelAccessor level, BlockPos pos, RandomSource random) { + public static StructureWorldNBT create(ResourceLocation location, int offsetY, StructurePlacementType type) { + String key = location.toString() + "::" + offsetY + "::" + type.getSerializedName(); + return READER_CACHE.computeIfAbsent(key, r -> new StructureWorldNBT(location, offsetY, type)); + } + + + 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)); } return false; } - protected boolean canGenerate(LevelAccessor world, BlockPos pos) { + protected boolean canGenerate(LevelAccessor level, BlockPos pos) { if (type == StructurePlacementType.FLOOR) - return canGenerateFloor(world, pos); + return canGenerateFloor(level, pos); else if (type == StructurePlacementType.LAVA) - return canGenerateLava(world, pos); + return canGenerateLava(level, pos); else if (type == StructurePlacementType.UNDER) - return canGenerateUnder(world, pos); + return canGenerateUnder(level, pos); else if (type == StructurePlacementType.CEIL) - return canGenerateCeil(world, pos); + return canGenerateCeil(level, pos); else return false; } @@ -75,16 +91,31 @@ public class StructureWorldNBT extends StructureNBT { return getAirFractionBottom(world, pos) > 0.8 && getAirFraction(world, pos) < 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() + ); + } + protected float getAirFraction(LevelAccessor world, BlockPos pos) { final MutableBlockPos POS = new MutableBlockPos(); int airCount = 0; MutableBlockPos size = new MutableBlockPos().set(new BlockPos(structure.getSize()).rotate(rotation)); - size.setX(Math.abs(size.getX())); - size.setZ(Math.abs(size.getZ())); + size.setX(Math.abs(size.getX()) >> 1); + size.setZ(Math.abs(size.getZ()) >> 1); - BlockPos start = pos.offset(-(size.getX() >> 1), 0, -(size.getZ() >> 1)); - BlockPos end = pos.offset(size.getX() >> 1, size.getY() + offsetY, size.getZ() >> 1); + BlockPos start = pos.offset(-size.getX(), 0, -size.getZ()); + BlockPos end = pos.offset(size.getX(), size.getY() + offsetY, size.getZ()); int count = 0; for (int x = start.getX(); x <= end.getX(); x++) { @@ -108,11 +139,11 @@ public class StructureWorldNBT extends StructureNBT { int lavaCount = 0; MutableBlockPos size = new MutableBlockPos().set(new BlockPos(structure.getSize()).rotate(rotation)); - size.setX(Math.abs(size.getX())); - size.setZ(Math.abs(size.getZ())); + size.setX(Math.abs(size.getX()) >> 1); + size.setZ(Math.abs(size.getZ()) >> 1); - BlockPos start = pos.offset(-(size.getX() >> 1), 0, -(size.getZ() >> 1)); - BlockPos end = pos.offset(size.getX() >> 1, 0, size.getZ() >> 1); + BlockPos start = pos.offset(-(size.getX()), 0, -(size.getZ())); + BlockPos end = pos.offset(size.getX(), 0, size.getZ()); int count = 0; POS.setY(pos.getY() - 1); @@ -135,11 +166,11 @@ public class StructureWorldNBT extends StructureNBT { int airCount = 0; MutableBlockPos size = new MutableBlockPos().set(new BlockPos(structure.getSize()).rotate(rotation)); - size.setX(Math.abs(size.getX())); - size.setZ(Math.abs(size.getZ())); + size.setX(Math.abs(size.getX()) >> 1); + size.setZ(Math.abs(size.getZ()) >> 1); - BlockPos start = pos.offset(-(size.getX() >> 1), -1, -(size.getZ() >> 1)); - BlockPos end = pos.offset(size.getX() >> 1, 0, size.getZ() >> 1); + BlockPos start = pos.offset(-(size.getX()), -1, -(size.getZ())); + BlockPos end = pos.offset(size.getX(), 0, size.getZ()); int count = 0; for (int x = start.getX(); x <= end.getX(); x++) { diff --git a/src/main/java/org/betterx/bclib/world/structures/TemplatePiece.java b/src/main/java/org/betterx/bclib/world/structures/TemplatePiece.java new file mode 100644 index 00000000..b7d9ddbb --- /dev/null +++ b/src/main/java/org/betterx/bclib/world/structures/TemplatePiece.java @@ -0,0 +1,85 @@ +package org.betterx.bclib.world.structures; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +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.StructureManager; +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.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.pieces.StructurePieceSerializationContext; +import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceType; + +import org.betterx.bclib.BCLib; + +public class TemplatePiece extends StructurePiece { + public static final StructurePieceType INSTANCE = register("template_piece", TemplatePiece::new); + + private static StructurePieceType register(String id, StructurePieceType pieceType) { + return Registry.register(Registry.STRUCTURE_PIECE, BCLib.makeID(id), pieceType); + } + + 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) { + super(INSTANCE, 0, structure.boundingBox(rot, pos)); + this.structure = structure; + this.rot = rot; + this.mir = mir; + this.pos = pos; + } + + public TemplatePiece(StructurePieceSerializationContext ctx, CompoundTag compoundTag) { + super(INSTANCE, compoundTag); + + ResourceLocation location = new ResourceLocation(compoundTag.getString("L")); + int offsetY = compoundTag.getInt("OY"); + StructurePlacementType type = StructurePlacementType.valueOf(compoundTag.getString("T")); + this.structure = new StructureWorldNBT(location, offsetY, type); + + this.rot = Rotation.valueOf(compoundTag.getString("Rot")); + this.mir = Mirror.valueOf(compoundTag.getString("Mir")); + this.pos = new BlockPos( + compoundTag.getInt("PX"), + compoundTag.getInt("PY"), + compoundTag.getInt("PZ") + ); + } + + @Override + protected void addAdditionalSaveData(StructurePieceSerializationContext structurePieceSerializationContext, + CompoundTag tag) { + + tag.putString("L", structure.location.toString()); + tag.putInt("OY", structure.offsetY); + tag.putString("T", structure.type.getSerializedName()); + tag.putString("Rot", this.rot.name()); + tag.putString("Mir", this.mir.name()); + tag.putInt("PX", this.pos.getX()); + tag.putInt("PY", this.pos.getY()); + tag.putInt("PZ", this.pos.getZ()); + } + + @Override + public void postProcess(WorldGenLevel worldGenLevel, + StructureManager structureManager, + ChunkGenerator chunkGenerator, + RandomSource randomSource, + BoundingBox boundingBox, + ChunkPos chunkPos, + BlockPos blockPos) { + structure.generateInRandomOrientation(worldGenLevel, blockPos, randomSource); + } +} diff --git a/src/main/java/org/betterx/bclib/world/structures/TemplateStructure.java b/src/main/java/org/betterx/bclib/world/structures/TemplateStructure.java new file mode 100644 index 00000000..a3a3d515 --- /dev/null +++ b/src/main/java/org/betterx/bclib/world/structures/TemplateStructure.java @@ -0,0 +1,89 @@ +package org.betterx.bclib.world.structures; + +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.ChunkPos; +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.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.pieces.StructurePiecesBuilder; + +import com.mojang.datafixers.util.Function4; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import java.util.Optional; + +public abstract class TemplateStructure extends Structure { + public static Codec simpleCodec(Function4 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) + ); + } + + public final StructureWorldNBT structure; + + protected TemplateStructure(StructureSettings structureSettings, + ResourceLocation location, + int offsetY, + StructurePlacementType type) { + super(structureSettings); + structure = StructureWorldNBT.create(location, offsetY, type); + } + + + @Override + public Optional findGenerationPoint(GenerationContext ctx) { + 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()); + + BlockPos centerPos = new BlockPos(x, y, z); + Rotation rotation = Rotation.getRandom(ctx.random()); + BoundingBox bb = structure.boundingBox(rotation, centerPos); + // if (!structure.canGenerate(ctx.chunkGenerator()., centerPos)) + return Optional.of(new GenerationStub(centerPos, + structurePiecesBuilder -> this.generatePieces(structurePiecesBuilder, centerPos, rotation, ctx))); + + } + + private void generatePieces(StructurePiecesBuilder structurePiecesBuilder, + BlockPos centerPos, + Rotation rotation, + Structure.GenerationContext generationContext) { + WorldgenRandom worldgenRandom = generationContext.random(); + + Mirror mirror = Mirror.values()[worldgenRandom.nextInt(3)]; + + structurePiecesBuilder.addPiece(new TemplatePiece(structure, centerPos, rotation, mirror)); + } + + +}