[Change] Improved Placement of Template Structure
This commit is contained in:
parent
37a26f25bb
commit
ae5b3e1417
1 changed files with 92 additions and 20 deletions
|
@ -17,10 +17,13 @@ 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.templatesystem.StructureTemplate;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.BiPredicate;
|
import java.util.function.BiPredicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public abstract class TemplateStructure extends Structure {
|
public abstract class TemplateStructure extends Structure {
|
||||||
protected final List<Config> configs;
|
protected final List<Config> configs;
|
||||||
|
@ -73,16 +76,15 @@ public abstract class TemplateStructure extends Structure {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isLavaPlaceable(BlockState state, BlockState before) {
|
protected boolean isLavaPlaceable(BlockState state, BlockState before) {
|
||||||
return state.is(Blocks.AIR) && before.is(Blocks.LAVA);
|
return (state == null || state.is(Blocks.AIR)) && before.is(Blocks.LAVA);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isFloorPlaceable(BlockState state, BlockState before) {
|
protected boolean isFloorPlaceable(BlockState state, BlockState before) {
|
||||||
return state.is(Blocks.AIR) && before.getMaterial().isSolid();
|
return (state == null || state.is(Blocks.AIR)) && before.getMaterial().isSolid();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<GenerationStub> findGenerationPoint(GenerationContext ctx) {
|
public Optional<GenerationStub> findGenerationPoint(GenerationContext ctx) {
|
||||||
|
|
||||||
WorldGenerationContext worldGenerationContext = new WorldGenerationContext(
|
WorldGenerationContext worldGenerationContext = new WorldGenerationContext(
|
||||||
ctx.chunkGenerator(),
|
ctx.chunkGenerator(),
|
||||||
ctx.heightAccessor()
|
ctx.heightAccessor()
|
||||||
|
@ -90,22 +92,26 @@ public abstract class TemplateStructure extends Structure {
|
||||||
final Config config = randomConfig(ctx.random());
|
final Config config = randomConfig(ctx.random());
|
||||||
if (config == null) return Optional.empty();
|
if (config == null) return Optional.empty();
|
||||||
ChunkPos chunkPos = ctx.chunkPos();
|
ChunkPos chunkPos = ctx.chunkPos();
|
||||||
final int x = chunkPos.getMiddleBlockX();
|
final int x = chunkPos.getMinBlockX();
|
||||||
final int z = chunkPos.getMiddleBlockZ();
|
final int z = chunkPos.getMinBlockZ();
|
||||||
NoiseColumn column = ctx.chunkGenerator().getBaseColumn(x, z, ctx.heightAccessor(), ctx.randomState());
|
|
||||||
StructureTemplate structureTemplate = ctx.structureTemplateManager().getOrCreate(config.location);
|
StructureTemplate structureTemplate = ctx.structureTemplateManager().getOrCreate(config.location);
|
||||||
|
|
||||||
|
|
||||||
BiPredicate<BlockState, BlockState> isCorrectBase;
|
final BiPredicate<BlockState, BlockState> isCorrectBase;
|
||||||
int searchStep;
|
final int searchStep;
|
||||||
|
final int minBaseCount;
|
||||||
|
final float minAirRatio = 0.6f;
|
||||||
if (config.type == StructurePlacementType.LAVA) {
|
if (config.type == StructurePlacementType.LAVA) {
|
||||||
isCorrectBase = this::isLavaPlaceable;
|
isCorrectBase = this::isLavaPlaceable;
|
||||||
|
minBaseCount = 5;
|
||||||
searchStep = 1;
|
searchStep = 1;
|
||||||
} else if (config.type == StructurePlacementType.CEIL) {
|
} else if (config.type == StructurePlacementType.CEIL) {
|
||||||
isCorrectBase = this::isFloorPlaceable;
|
isCorrectBase = this::isFloorPlaceable;
|
||||||
|
minBaseCount = 3;
|
||||||
searchStep = -1;
|
searchStep = -1;
|
||||||
} else {
|
} else {
|
||||||
isCorrectBase = this::isFloorPlaceable;
|
isCorrectBase = this::isFloorPlaceable;
|
||||||
|
minBaseCount = 3;
|
||||||
searchStep = 1;
|
searchStep = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,16 +123,6 @@ public abstract class TemplateStructure extends Structure {
|
||||||
worldGenerationContext.getGenDepth()
|
worldGenerationContext.getGenDepth()
|
||||||
- 4
|
- 4
|
||||||
- (searchStep > 0 ? (structureTemplate.getSize(Rotation.NONE).getY() + config.offsetY) : 0);
|
- (searchStep > 0 ? (structureTemplate.getSize(Rotation.NONE).getY() + config.offsetY) : 0);
|
||||||
int y = searchStep > 0 ? seaLevel : maxHeight - 1;
|
|
||||||
BlockState state = column.getBlock(y - searchStep);
|
|
||||||
|
|
||||||
for (; y < maxHeight && y >= seaLevel; y += searchStep) {
|
|
||||||
BlockState before = state;
|
|
||||||
state = column.getBlock(y);
|
|
||||||
if (isCorrectBase.test(state, before)) break;
|
|
||||||
}
|
|
||||||
if (y >= maxHeight || y < seaLevel) return Optional.empty();
|
|
||||||
if (!BCLStructure.isValidBiome(ctx, y)) return Optional.empty();
|
|
||||||
|
|
||||||
BlockPos halfSize = new BlockPos(
|
BlockPos halfSize = new BlockPos(
|
||||||
structureTemplate.getSize().getX() / 2,
|
structureTemplate.getSize().getX() / 2,
|
||||||
|
@ -135,13 +131,58 @@ public abstract class TemplateStructure extends Structure {
|
||||||
);
|
);
|
||||||
Rotation rotation = StructureNBT.getRandomRotation(ctx.random());
|
Rotation rotation = StructureNBT.getRandomRotation(ctx.random());
|
||||||
Mirror mirror = StructureNBT.getRandomMirror(ctx.random());
|
Mirror mirror = StructureNBT.getRandomMirror(ctx.random());
|
||||||
BlockPos centerPos = new BlockPos(
|
BlockPos.MutableBlockPos centerPos = new BlockPos.MutableBlockPos(
|
||||||
x,
|
x,
|
||||||
y - (searchStep == 1 ? 0 : (structureTemplate.getSize(Rotation.NONE).getY())),
|
0,
|
||||||
z
|
z
|
||||||
);
|
);
|
||||||
BoundingBox boundingBox = structureTemplate.getBoundingBox(centerPos, rotation, halfSize, mirror);
|
BoundingBox boundingBox = structureTemplate.getBoundingBox(centerPos, rotation, halfSize, mirror);
|
||||||
|
|
||||||
|
var noiseColumns = ImmutableList
|
||||||
|
.of(
|
||||||
|
new BlockPos(boundingBox.getCenter().getX(), 0, boundingBox.getCenter().getZ()),
|
||||||
|
new BlockPos(boundingBox.minX(), 0, boundingBox.minZ()),
|
||||||
|
new BlockPos(boundingBox.maxX(), 0, boundingBox.minZ()),
|
||||||
|
new BlockPos(boundingBox.minX(), 0, boundingBox.maxZ()),
|
||||||
|
new BlockPos(boundingBox.maxX(), 0, boundingBox.maxZ())
|
||||||
|
)
|
||||||
|
.stream()
|
||||||
|
.map(blockPos -> ctx.chunkGenerator().getBaseColumn(
|
||||||
|
blockPos.getX(),
|
||||||
|
blockPos.getZ(),
|
||||||
|
ctx.heightAccessor(),
|
||||||
|
ctx.randomState()
|
||||||
|
))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
int y = noiseColumns
|
||||||
|
.stream()
|
||||||
|
.map(column -> findY(column, isCorrectBase, searchStep, seaLevel, maxHeight))
|
||||||
|
.reduce(
|
||||||
|
searchStep > 0 ? Integer.MAX_VALUE : Integer.MIN_VALUE,
|
||||||
|
(p, c) -> searchStep > 0 ? Math.min(p, c) : Math.max(p, c)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (y >= maxHeight || y < seaLevel) return Optional.empty();
|
||||||
|
if (!BCLStructure.isValidBiome(ctx, y)) return Optional.empty();
|
||||||
|
|
||||||
|
int baseCount = noiseColumns
|
||||||
|
.stream()
|
||||||
|
.map(column -> isCorrectBase.test(null, column.getBlock(y - searchStep)))
|
||||||
|
.filter(b -> b)
|
||||||
|
.map(b -> 1)
|
||||||
|
.reduce(0, (p, c) -> p + c);
|
||||||
|
|
||||||
|
if (baseCount < minBaseCount) return Optional.empty();
|
||||||
|
|
||||||
|
float airRatio = noiseColumns
|
||||||
|
.stream()
|
||||||
|
.map(column -> airRatio(column, y, boundingBox.getYSpan(), searchStep))
|
||||||
|
.reduce(0.0f, (p, c) -> p + c) / noiseColumns.size();
|
||||||
|
|
||||||
|
if (airRatio < minAirRatio) return Optional.empty();
|
||||||
|
|
||||||
|
centerPos.setY(y - (searchStep == 1 ? 0 : (structureTemplate.getSize(Rotation.NONE).getY())));
|
||||||
|
|
||||||
// if (!structure.canGenerate(ctx.chunkGenerator()., centerPos))
|
// if (!structure.canGenerate(ctx.chunkGenerator()., centerPos))
|
||||||
return Optional.of(new GenerationStub(
|
return Optional.of(new GenerationStub(
|
||||||
|
@ -164,6 +205,37 @@ public abstract class TemplateStructure extends Structure {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float airRatio(NoiseColumn column, int y, int height, int searchStep) {
|
||||||
|
int airCount = 0;
|
||||||
|
for (int i = y; i < y + height && i > y - height; i += searchStep) {
|
||||||
|
BlockState state = column.getBlock(i);
|
||||||
|
if (state.isAir() || state.getMaterial().isReplaceable()) {
|
||||||
|
airCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return airCount / (float) height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int findY(
|
||||||
|
NoiseColumn column,
|
||||||
|
BiPredicate<BlockState, BlockState> isCorrectBase,
|
||||||
|
int searchStep,
|
||||||
|
int seaLevel,
|
||||||
|
int maxHeight
|
||||||
|
) {
|
||||||
|
int y = searchStep > 0 ? seaLevel : maxHeight - 1;
|
||||||
|
BlockState state = column.getBlock(y - searchStep);
|
||||||
|
|
||||||
|
for (; y < maxHeight && y >= seaLevel; y += searchStep) {
|
||||||
|
BlockState before = state;
|
||||||
|
state = column.getBlock(y);
|
||||||
|
if (isCorrectBase.test(state, before)) break;
|
||||||
|
}
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public record Config(ResourceLocation location, int offsetY, StructurePlacementType type, float chance) {
|
public record Config(ResourceLocation location, int offsetY, StructurePlacementType type, float chance) {
|
||||||
public static final Codec<Config> CODEC =
|
public static final Codec<Config> CODEC =
|
||||||
RecordCodecBuilder.create((instance) ->
|
RecordCodecBuilder.create((instance) ->
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue