Started TemplateStructure class

This commit is contained in:
Frank 2022-05-31 00:10:46 +02:00
parent 95434107ec
commit 9ac0d78d30
8 changed files with 248 additions and 24 deletions

View file

@ -29,6 +29,7 @@ import org.betterx.bclib.world.processors.DestructionStructureProcessor;
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 extends DefaultFeature { public abstract class NBTFeature extends DefaultFeature {
private final BlockState defaultBlock; private final BlockState defaultBlock;
@ -107,7 +108,7 @@ public abstract class NBTFeature extends DefaultFeature {
mirror, mirror,
rotation, rotation,
BlockPos.ZERO BlockPos.ZERO
); );
center = center.offset(0, getYOffset(structure, world, center, random) + 0.5, 0); center = center.offset(0, getYOffset(structure, world, center, random) + 0.5, 0);
BoundingBox bounds = makeBox(center); BoundingBox bounds = makeBox(center);

View file

@ -39,7 +39,11 @@ public abstract class SurfaceFeature<T extends FeatureConfiguration> extends Fea
if (pos.isPresent()) { if (pos.isPresent()) {
int y2 = ctx.level().getHeight(Heightmap.Types.WORLD_SURFACE_WG, ctx.origin().getX(), ctx.origin().getZ()); 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()); 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); generate(pos.get(), ctx);
return true; return true;

View file

@ -40,6 +40,6 @@ 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.generate(ctx.level(), ctx.origin(), ctx.random()); return ctx.config().structure.generateInRandomOrientation(ctx.level(), ctx.origin(), ctx.random());
} }
} }

View file

@ -31,6 +31,6 @@ public class TemplateFeatureConfig implements FeatureConfiguration {
public final StructureWorldNBT structure; public final StructureWorldNBT structure;
public TemplateFeatureConfig(ResourceLocation location, int offsetY, StructurePlacementType type) { public TemplateFeatureConfig(ResourceLocation location, int offsetY, StructurePlacementType type) {
structure = new StructureWorldNBT(location, offsetY, type); structure = StructureWorldNBT.create(location, offsetY, type);
} }
} }

View file

@ -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.StructurePlaceSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import com.google.common.collect.Maps;
import org.betterx.bclib.BCLib; import org.betterx.bclib.BCLib;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Map;
public class StructureNBT { public class StructureNBT {
public final ResourceLocation location; public final ResourceLocation location;
@ -27,7 +29,7 @@ public class StructureNBT {
protected Mirror mirror = Mirror.NONE; protected Mirror mirror = Mirror.NONE;
protected Rotation rotation = Rotation.NONE; protected Rotation rotation = Rotation.NONE;
public StructureNBT(ResourceLocation location) { protected StructureNBT(ResourceLocation location) {
this.location = location; this.location = location;
this.structure = readStructureFromJar(location); this.structure = readStructureFromJar(location);
} }
@ -37,6 +39,12 @@ public class StructureNBT {
this.structure = structure; this.structure = structure;
} }
private static final Map<ResourceLocation, StructureNBT> STRUCTURE_CACHE = Maps.newHashMap();
public static StructureNBT create(ResourceLocation location) {
return STRUCTURE_CACHE.computeIfAbsent(location, r -> new StructureNBT(r));
}
public StructureNBT setRotation(Rotation rotation) { public StructureNBT setRotation(Rotation rotation) {
this.rotation = rotation; this.rotation = rotation;
return this; return this;
@ -81,7 +89,13 @@ public class StructureNBT {
return true; return true;
} }
private static final Map<ResourceLocation, StructureTemplate> READER_CACHE = Maps.newHashMap();
private static StructureTemplate readStructureFromJar(ResourceLocation resource) { 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 ns = resource.getNamespace();
String nm = resource.getPath(); String nm = resource.getPath();

View file

@ -7,37 +7,53 @@ 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.Rotation;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import com.google.common.collect.Maps;
import org.betterx.bclib.util.BlocksHelper; import org.betterx.bclib.util.BlocksHelper;
import java.util.Map;
public class StructureWorldNBT extends StructureNBT { public class StructureWorldNBT extends StructureNBT {
public final StructurePlacementType type; public final StructurePlacementType type;
public final int offsetY; public final int offsetY;
public StructureWorldNBT(ResourceLocation location, int offsetY, StructurePlacementType type) { protected StructureWorldNBT(ResourceLocation location, int offsetY, StructurePlacementType type) {
super(location); super(location);
this.offsetY = offsetY; this.offsetY = offsetY;
this.type = type; this.type = type;
} }
private static final Map<String, StructureWorldNBT> 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); randomRM(random);
return generate(level, pos);
}
public boolean generate(ServerLevelAccessor level, BlockPos pos) {
if (canGenerate(level, pos)) { if (canGenerate(level, pos)) {
return generateCentered(level, pos.above(offsetY)); return generateCentered(level, pos.above(offsetY));
} }
return false; return false;
} }
protected boolean canGenerate(LevelAccessor world, BlockPos pos) { protected boolean canGenerate(LevelAccessor level, BlockPos pos) {
if (type == StructurePlacementType.FLOOR) if (type == StructurePlacementType.FLOOR)
return canGenerateFloor(world, pos); return canGenerateFloor(level, pos);
else if (type == StructurePlacementType.LAVA) else if (type == StructurePlacementType.LAVA)
return canGenerateLava(world, pos); return canGenerateLava(level, pos);
else if (type == StructurePlacementType.UNDER) else if (type == StructurePlacementType.UNDER)
return canGenerateUnder(world, pos); return canGenerateUnder(level, pos);
else if (type == StructurePlacementType.CEIL) else if (type == StructurePlacementType.CEIL)
return canGenerateCeil(world, pos); return canGenerateCeil(level, pos);
else else
return false; return false;
} }
@ -75,16 +91,31 @@ public class StructureWorldNBT extends StructureNBT {
return getAirFractionBottom(world, pos) > 0.8 && getAirFraction(world, pos) < 0.6; 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) { protected float getAirFraction(LevelAccessor world, BlockPos pos) {
final MutableBlockPos POS = new MutableBlockPos(); final MutableBlockPos POS = new MutableBlockPos();
int airCount = 0; int airCount = 0;
MutableBlockPos size = new MutableBlockPos().set(new BlockPos(structure.getSize()).rotate(rotation)); MutableBlockPos size = new MutableBlockPos().set(new BlockPos(structure.getSize()).rotate(rotation));
size.setX(Math.abs(size.getX())); size.setX(Math.abs(size.getX()) >> 1);
size.setZ(Math.abs(size.getZ())); size.setZ(Math.abs(size.getZ()) >> 1);
BlockPos start = pos.offset(-(size.getX() >> 1), 0, -(size.getZ() >> 1)); BlockPos start = pos.offset(-size.getX(), 0, -size.getZ());
BlockPos end = pos.offset(size.getX() >> 1, size.getY() + offsetY, size.getZ() >> 1); BlockPos end = pos.offset(size.getX(), size.getY() + offsetY, size.getZ());
int count = 0; int count = 0;
for (int x = start.getX(); x <= end.getX(); x++) { for (int x = start.getX(); x <= end.getX(); x++) {
@ -108,11 +139,11 @@ public class StructureWorldNBT extends StructureNBT {
int lavaCount = 0; int lavaCount = 0;
MutableBlockPos size = new MutableBlockPos().set(new BlockPos(structure.getSize()).rotate(rotation)); MutableBlockPos size = new MutableBlockPos().set(new BlockPos(structure.getSize()).rotate(rotation));
size.setX(Math.abs(size.getX())); size.setX(Math.abs(size.getX()) >> 1);
size.setZ(Math.abs(size.getZ())); size.setZ(Math.abs(size.getZ()) >> 1);
BlockPos start = pos.offset(-(size.getX() >> 1), 0, -(size.getZ() >> 1)); BlockPos start = pos.offset(-(size.getX()), 0, -(size.getZ()));
BlockPos end = pos.offset(size.getX() >> 1, 0, size.getZ() >> 1); BlockPos end = pos.offset(size.getX(), 0, size.getZ());
int count = 0; int count = 0;
POS.setY(pos.getY() - 1); POS.setY(pos.getY() - 1);
@ -135,11 +166,11 @@ public class StructureWorldNBT extends StructureNBT {
int airCount = 0; int airCount = 0;
MutableBlockPos size = new MutableBlockPos().set(new BlockPos(structure.getSize()).rotate(rotation)); MutableBlockPos size = new MutableBlockPos().set(new BlockPos(structure.getSize()).rotate(rotation));
size.setX(Math.abs(size.getX())); size.setX(Math.abs(size.getX()) >> 1);
size.setZ(Math.abs(size.getZ())); size.setZ(Math.abs(size.getZ()) >> 1);
BlockPos start = pos.offset(-(size.getX() >> 1), -1, -(size.getZ() >> 1)); BlockPos start = pos.offset(-(size.getX()), -1, -(size.getZ()));
BlockPos end = pos.offset(size.getX() >> 1, 0, size.getZ() >> 1); BlockPos end = pos.offset(size.getX(), 0, size.getZ());
int count = 0; int count = 0;
for (int x = start.getX(); x <= end.getX(); x++) { for (int x = start.getX(); x <= end.getX(); x++) {

View file

@ -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);
}
}

View file

@ -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 <T extends TemplateStructure> Codec<T> 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<GenerationStub> 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));
}
}