Template Structures (but missaligned)

This commit is contained in:
Frank 2022-05-31 13:52:08 +02:00
parent 86a92c560b
commit 38f337cd15
6 changed files with 307 additions and 137 deletions

View file

@ -25,6 +25,7 @@ import org.betterx.bclib.util.Logger;
import org.betterx.bclib.world.generator.BCLibEndBiomeSource; import org.betterx.bclib.world.generator.BCLibEndBiomeSource;
import org.betterx.bclib.world.generator.BCLibNetherBiomeSource; import org.betterx.bclib.world.generator.BCLibNetherBiomeSource;
import org.betterx.bclib.world.generator.GeneratorOptions; import org.betterx.bclib.world.generator.GeneratorOptions;
import org.betterx.bclib.world.structures.TemplatePiece;
import java.util.List; import java.util.List;
@ -49,15 +50,16 @@ public class BCLib implements ModInitializer {
AnvilRecipe.register(); AnvilRecipe.register();
DataExchangeAPI.registerDescriptors(List.of( DataExchangeAPI.registerDescriptors(List.of(
HelloClient.DESCRIPTOR, HelloClient.DESCRIPTOR,
HelloServer.DESCRIPTOR, HelloServer.DESCRIPTOR,
RequestFiles.DESCRIPTOR, RequestFiles.DESCRIPTOR,
SendFiles.DESCRIPTOR, SendFiles.DESCRIPTOR,
Chunker.DESCRIPTOR Chunker.DESCRIPTOR
) )
); );
BCLibPatch.register(); BCLibPatch.register();
TemplatePiece.ensureStaticInitialization();
Configs.save(); Configs.save();
if (isDevEnvironment()) { if (isDevEnvironment()) {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder() Biome.BiomeBuilder builder = new Biome.BiomeBuilder()

View file

@ -12,24 +12,28 @@ import net.minecraft.world.level.levelgen.placement.EnvironmentScanPlacement;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import org.betterx.bclib.api.features.BCLFeatureBuilder; import org.betterx.bclib.api.features.BCLFeatureBuilder;
import org.betterx.bclib.world.structures.StructureNBT;
public class TemplateFeature<FC extends TemplateFeatureConfig> extends Feature<FC> { public class TemplateFeature<FC extends TemplateFeatureConfig> extends Feature<FC> {
public static final Feature<TemplateFeatureConfig> INSTANCE = BCLFeature.register("template", public static final Feature<TemplateFeatureConfig> INSTANCE = BCLFeature.register("template",
new TemplateFeature(TemplateFeatureConfig.CODEC)); new TemplateFeature(
TemplateFeatureConfig.CODEC));
public static <T extends TemplateFeatureConfig> BCLFeature createAndRegister(TemplateFeatureConfig configuration, public static <T extends TemplateFeatureConfig> BCLFeature createAndRegister(TemplateFeatureConfig configuration,
int onveEveryChunk) { int onveEveryChunk) {
return BCLFeatureBuilder return BCLFeatureBuilder
.start(new ResourceLocation(configuration.structure.location.getNamespace(), .start(new ResourceLocation(configuration.structure.location.getNamespace(),
"feature_" + configuration.structure.location.getPath()), INSTANCE) "feature_" + configuration.structure.location.getPath()), INSTANCE)
.decoration(GenerationStep.Decoration.SURFACE_STRUCTURES) .decoration(GenerationStep.Decoration.SURFACE_STRUCTURES)
.oncePerChunks(onveEveryChunk) .oncePerChunks(onveEveryChunk)
.squarePlacement() .squarePlacement()
.distanceToTopAndBottom10() .distanceToTopAndBottom10()
.modifier(EnvironmentScanPlacement.scanningFor(Direction.DOWN, .modifier(EnvironmentScanPlacement.scanningFor(Direction.DOWN,
BlockPredicate.solid(), BlockPredicate.solid(),
BlockPredicate.matchesBlocks(Blocks.AIR, Blocks.WATER, Blocks.LAVA), BlockPredicate.matchesBlocks(Blocks.AIR,
12)) Blocks.WATER,
Blocks.LAVA),
12))
.modifier(BiomeFilter.biome()) .modifier(BiomeFilter.biome())
.buildAndRegister(configuration); .buildAndRegister(configuration);
} }
@ -40,6 +44,10 @@ public class TemplateFeature<FC extends TemplateFeatureConfig> extends Feature<F
@Override @Override
public boolean place(FeaturePlaceContext<FC> ctx) { public boolean place(FeaturePlaceContext<FC> 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())
);
} }
} }

View file

@ -26,8 +26,7 @@ import java.util.Map;
public class StructureNBT { public class StructureNBT {
public final ResourceLocation location; public final ResourceLocation location;
protected StructureTemplate structure; protected StructureTemplate structure;
protected Mirror mirror = Mirror.NONE;
protected Rotation rotation = Rotation.NONE;
protected StructureNBT(ResourceLocation location) { protected StructureNBT(ResourceLocation location) {
this.location = location; this.location = location;
@ -39,44 +38,33 @@ public class StructureNBT {
this.structure = structure; 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<ResourceLocation, StructureNBT> STRUCTURE_CACHE = Maps.newHashMap(); private static final Map<ResourceLocation, StructureNBT> STRUCTURE_CACHE = Maps.newHashMap();
public static StructureNBT create(ResourceLocation location) { public static StructureNBT create(ResourceLocation location) {
return STRUCTURE_CACHE.computeIfAbsent(location, r -> new StructureNBT(r)); return STRUCTURE_CACHE.computeIfAbsent(location, r -> new StructureNBT(r));
} }
public StructureNBT setRotation(Rotation rotation) { public boolean generateCentered(ServerLevelAccessor world, BlockPos pos, Rotation rotation, Mirror mirror) {
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) {
if (structure == null) { if (structure == null) {
BCLib.LOGGER.error("No structure: " + location.toString()); BCLib.LOGGER.error("No structure: " + location.toString());
return false; return false;
} }
MutableBlockPos blockpos2 = new MutableBlockPos().set(structure.getSize()); MutableBlockPos blockpos2 = new MutableBlockPos().set(structure.getSize());
if (this.mirror == Mirror.FRONT_BACK) if (mirror == Mirror.FRONT_BACK)
blockpos2.setX(-blockpos2.getX()); blockpos2.setX(-blockpos2.getX());
if (this.mirror == Mirror.LEFT_RIGHT) if (mirror == Mirror.LEFT_RIGHT)
blockpos2.setZ(-blockpos2.getZ()); blockpos2.setZ(-blockpos2.getZ());
blockpos2.set(blockpos2.rotate(rotation)); 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); BlockPos newPos = pos.offset(-blockpos2.getX() >> 1, 0, -blockpos2.getZ() >> 1);
structure.placeInWorld( structure.placeInWorld(
world, world,
@ -85,7 +73,7 @@ public class StructureNBT {
data, data,
world.getRandom(), world.getRandom(),
Block.UPDATE_CLIENTS Block.UPDATE_CLIENTS
); );
return true; return true;
} }
@ -118,7 +106,7 @@ public class StructureNBT {
return template; return template;
} }
public BlockPos getSize() { public BlockPos getSize(Rotation rotation) {
if (rotation == Rotation.NONE || rotation == Rotation.CLOCKWISE_180) if (rotation == Rotation.NONE || rotation == Rotation.CLOCKWISE_180)
return new BlockPos(structure.getSize()); return new BlockPos(structure.getSize());
else { else {
@ -133,7 +121,7 @@ public class StructureNBT {
return location.getPath(); return location.getPath();
} }
public BoundingBox getBoundingBox(BlockPos pos) { public BoundingBox getBoundingBox(BlockPos pos, Rotation rotation, Mirror mirror) {
return structure.getBoundingBox(new StructurePlaceSettings().setRotation(this.rotation).setMirror(mirror), pos); return structure.getBoundingBox(new StructurePlaceSettings().setRotation(rotation).setMirror(mirror), pos);
} }
} }

View file

@ -3,10 +3,10 @@ package org.betterx.bclib.world.structures;
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.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.block.Blocks; 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.block.Rotation;
import net.minecraft.world.level.levelgen.structure.BoundingBox; 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) { public boolean generateIfPlaceable(ServerLevelAccessor level,
randomRM(random); BlockPos pos,
return generate(level, pos); Rotation r,
} Mirror m) {
if (canGenerate(level, pos, r)) {
public boolean generate(ServerLevelAccessor level, BlockPos pos) { return generate(level, pos, r, m);
if (canGenerate(level, pos)) {
return generateCentered(level, pos.above(offsetY));
} }
return false; 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) if (type == StructurePlacementType.FLOOR)
return canGenerateFloor(level, pos); return canGenerateFloor(level, pos, rotation);
else if (type == StructurePlacementType.LAVA) else if (type == StructurePlacementType.LAVA)
return canGenerateLava(level, pos); return canGenerateLava(level, pos, rotation);
else if (type == StructurePlacementType.UNDER) else if (type == StructurePlacementType.UNDER)
return canGenerateUnder(level, pos); return canGenerateUnder(level, pos, rotation);
else if (type == StructurePlacementType.CEIL) else if (type == StructurePlacementType.CEIL)
return canGenerateCeil(level, pos); return canGenerateCeil(level, pos, rotation);
else else
return false; return false;
} }
@ -67,46 +69,35 @@ public class StructureWorldNBT extends StructureNBT {
return false; return false;
} }
protected boolean canGenerateFloor(LevelAccessor world, BlockPos pos) { protected boolean canGenerateFloor(LevelAccessor world, BlockPos pos, Rotation rotation) {
if (containsBedrock(world, pos)) return false; 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; 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; 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; 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) { public BoundingBox boundingBox(Rotation r, BlockPos p) {
MutableBlockPos size = new MutableBlockPos().set(new BlockPos(structure.getSize()).rotate(rotation)); return getBoundingBox(p, r, Mirror.NONE);
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) { protected float getAirFraction(LevelAccessor world, BlockPos pos, Rotation rotation) {
final MutableBlockPos POS = new MutableBlockPos(); final MutableBlockPos POS = new MutableBlockPos();
int airCount = 0; int airCount = 0;
@ -134,7 +125,7 @@ public class StructureWorldNBT extends StructureNBT {
return (float) airCount / count; 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(); final MutableBlockPos POS = new MutableBlockPos();
int lavaCount = 0; int lavaCount = 0;
@ -161,7 +152,7 @@ public class StructureWorldNBT extends StructureNBT {
return (float) lavaCount / count; 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(); final MutableBlockPos POS = new MutableBlockPos();
int airCount = 0; int airCount = 0;
@ -189,7 +180,7 @@ public class StructureWorldNBT extends StructureNBT {
return (float) airCount / count; 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(); final MutableBlockPos POS = new MutableBlockPos();
int airCount = 0; int airCount = 0;

View file

@ -6,34 +6,154 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.StructureManager; import net.minecraft.world.level.StructureManager;
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.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.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.StructurePiece; 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.StructurePieceSerializationContext;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceType; 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.BCLib;
import org.betterx.bclib.util.BlocksHelper;
public class TemplatePiece extends StructurePiece { public class TemplatePiece extends TemplateStructurePiece {
public static final StructurePieceType INSTANCE = register("template_piece", TemplatePiece::new); 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) { private static StructurePieceType register(String id, StructurePieceType pieceType) {
return Registry.register(Registry.STRUCTURE_PIECE, BCLib.makeID(id), pieceType); return Registry.register(Registry.STRUCTURE_PIECE, BCLib.makeID(id), pieceType);
} }
public static void ensureStaticInitialization() {
}
public final StructureWorldNBT structure; public final StructureWorldNBT structure;
public final BlockPos pos; public final BlockPos pos;
public final Rotation rot; public final Rotation rot;
public final Mirror mir; public final Mirror mir;
protected TemplatePiece(StructureWorldNBT structure, protected TemplatePiece2(StructureWorldNBT structure,
BlockPos pos, BlockPos pos,
Rotation rot, Rotation rot,
Mirror mir) { Mirror mir) {
super(INSTANCE, 0, structure.boundingBox(rot, pos)); super(INSTANCE, 0, structure.boundingBox(rot, pos));
this.structure = structure; this.structure = structure;
this.rot = rot; this.rot = rot;
@ -41,7 +161,7 @@ public class TemplatePiece extends StructurePiece {
this.pos = pos; this.pos = pos;
} }
public TemplatePiece(StructurePieceSerializationContext ctx, CompoundTag compoundTag) { public TemplatePiece2(StructurePieceSerializationContext ctx, CompoundTag compoundTag) {
super(INSTANCE, compoundTag); super(INSTANCE, compoundTag);
ResourceLocation location = new ResourceLocation(compoundTag.getString("L")); ResourceLocation location = new ResourceLocation(compoundTag.getString("L"));
@ -64,7 +184,7 @@ public class TemplatePiece extends StructurePiece {
tag.putString("L", structure.location.toString()); tag.putString("L", structure.location.toString());
tag.putInt("OY", structure.offsetY); 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("Rot", this.rot.name());
tag.putString("Mir", this.mir.name()); tag.putString("Mir", this.mir.name());
tag.putInt("PX", this.pos.getX()); tag.putInt("PX", this.pos.getX());
@ -80,6 +200,6 @@ public class TemplatePiece extends StructurePiece {
BoundingBox boundingBox, BoundingBox boundingBox,
ChunkPos chunkPos, ChunkPos chunkPos,
BlockPos blockPos) { BlockPos blockPos) {
structure.generateInRandomOrientation(worldGenLevel, blockPos, randomSource); structure.generate(worldGenLevel, this.pos, this.rot, this.mir);
} }
} }

View file

@ -2,88 +2,149 @@ package org.betterx.bclib.world.structures;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation; 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.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.Mirror;
import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.WorldgenRandom; import net.minecraft.world.level.levelgen.WorldGenerationContext;
import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.Structure; 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.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.BiFunction;
public abstract class TemplateStructure extends Structure { public abstract class TemplateStructure extends Structure {
public static <T extends TemplateStructure> Codec<T> simpleCodec(Function4 instancer) { protected final List<Config> configs;
public static <T extends TemplateStructure> Codec<T> simpleCodec(BiFunction instancer) {
return RecordCodecBuilder.create((instance) -> instance return RecordCodecBuilder.create((instance) -> instance
.group( .group(
Structure.settingsCodec(instance), Structure.settingsCodec(instance),
ResourceLocation.CODEC ExtraCodecs.nonEmptyList(Config.CODEC.listOf())
.fieldOf("location") .fieldOf("configs")
.forGetter((T cfg) -> cfg.structure.location), .forGetter((T ruinedPortalStructure) -> ruinedPortalStructure.configs)
)
Codec .apply(instance, instancer)
.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, protected TemplateStructure(StructureSettings structureSettings,
ResourceLocation location, ResourceLocation location,
int offsetY, int offsetY,
StructurePlacementType type) { StructurePlacementType type,
super(structureSettings); float chance) {
structure = StructureWorldNBT.create(location, offsetY, type); this(structureSettings, List.of(new Config(location, offsetY, type, chance)));
} }
protected TemplateStructure(StructureSettings structureSettings,
List<Config> 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 @Override
public Optional<GenerationStub> findGenerationPoint(GenerationContext ctx) { public Optional<GenerationStub> 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(); ChunkPos chunkPos = ctx.chunkPos();
final int x = chunkPos.getMiddleBlockX(); final int x = chunkPos.getMiddleBlockX();
final int z = chunkPos.getMiddleBlockZ(); final int z = chunkPos.getMiddleBlockZ();
int y = ctx NoiseColumn column = ctx.chunkGenerator().getBaseColumn(x, z, ctx.heightAccessor(), ctx.randomState());
.chunkGenerator() final int seaLevel = ctx.chunkGenerator().getSeaLevel();
.getFirstOccupiedHeight(x, StructureTemplate structureTemplate = ctx.structureTemplateManager().getOrCreate(config.location);
z, final int maxHeight = worldGenerationContext.getGenDepth() - 4 - (structureTemplate.getSize(Rotation.NONE)
Heightmap.Types.WORLD_SURFACE_WG, .getY() + config.offsetY);
ctx.heightAccessor(), int y = seaLevel;
ctx.randomState()); 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); BlockPos centerPos = new BlockPos(x, y, z);
Rotation rotation = Rotation.getRandom(ctx.random()); BoundingBox boundingBox = structureTemplate.getBoundingBox(centerPos, rotation, halfSize, mirror);
BoundingBox bb = structure.boundingBox(rotation, centerPos);
// if (!structure.canGenerate(ctx.chunkGenerator()., centerPos)) // if (!structure.canGenerate(ctx.chunkGenerator()., centerPos))
return Optional.of(new GenerationStub(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, public record Config(ResourceLocation location, int offsetY, StructurePlacementType type, float chance) {
BlockPos centerPos, public static final Codec<Config> CODEC =
Rotation rotation, RecordCodecBuilder.create((instance) ->
Structure.GenerationContext generationContext) { instance.group(
WorldgenRandom worldgenRandom = generationContext.random(); 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)
);
} }
} }