mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-08-27 04:37:47 +00:00
d
This commit is contained in:
+12
-7
@@ -528,7 +528,7 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
int steps = GenerationStep.Decoration.values().length;
|
||||
List<NativePlacementGroup> placementGroups = new ArrayList<>();
|
||||
List<StructureStart> heightmapStarts = new ArrayList<>();
|
||||
List<NativeStructureVegetationClearer.VegetationTarget> vegetationTargets = new ArrayList<>();
|
||||
List<StructureStart> vegetationTargets = new ArrayList<>();
|
||||
List<NativeStructureTerrainIntegrator.TerrainTarget> terrainTargets = new ArrayList<>();
|
||||
for (int step = 0; step < steps; step++) {
|
||||
int index = 0;
|
||||
@@ -559,11 +559,7 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
structureId, start,
|
||||
NativeStructureTerrainIntegrator.resolveNativeTerrain(
|
||||
start, decision.terrain())));
|
||||
boolean clearEntireFootprint = NativeStructureVegetationClearer
|
||||
.shouldClearEntireVegetationFootprint(
|
||||
structure.step(), decision.clearVegetation());
|
||||
vegetationTargets.add(new NativeStructureVegetationClearer.VegetationTarget(
|
||||
start, clearEntireFootprint));
|
||||
vegetationTargets.add(start);
|
||||
}
|
||||
if (!resolvedPlacements.isEmpty()) {
|
||||
placementGroups.add(new NativePlacementGroup(
|
||||
@@ -592,8 +588,9 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
"vegetation cleanup", nativeStructureBatchContext(placementGroups),
|
||||
chunkPos.x(), chunkPos.z(), error);
|
||||
}
|
||||
NativeStructureSurfaceFitter.VacuumFoundationPlan vacuumFoundationPlan;
|
||||
try {
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
vacuumFoundationPlan = NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world, area, terrainTargets,
|
||||
(x, z) -> engine.getHeight(x, z, true) + engine.getMinHeight());
|
||||
} catch (Throwable error) {
|
||||
@@ -621,6 +618,14 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
"placement", group.structureId(), chunkPos.x(), chunkPos.z(), error);
|
||||
}
|
||||
}
|
||||
try {
|
||||
NativeStructureSurfaceFitter.repairVacuumFoundations(
|
||||
world, area, vacuumFoundationPlan);
|
||||
} catch (Throwable error) {
|
||||
throw NativeStructureGenerationException.failure(
|
||||
"foundation repair", nativeStructureBatchContext(placementGroups),
|
||||
chunkPos.x(), chunkPos.z(), error);
|
||||
}
|
||||
}
|
||||
|
||||
private static String nativeStructureBatchContext(List<NativePlacementGroup> placementGroups) {
|
||||
|
||||
+3
@@ -45,6 +45,7 @@ public class IrisChunkGeneratorFailureContractTest {
|
||||
assertTrue(placement.contains("\"resolution\""));
|
||||
assertTrue(placement.contains("\"terrain integration\""));
|
||||
assertTrue(placement.contains("\"terrain preparation\""));
|
||||
assertTrue(placement.contains("\"foundation repair\""));
|
||||
assertFalse(placement.contains("\"terrain carving\""));
|
||||
assertTrue(placement.contains("\"vegetation cleanup\""));
|
||||
assertTrue(placement.contains("\"placement\""));
|
||||
@@ -55,6 +56,8 @@ public class IrisChunkGeneratorFailureContractTest {
|
||||
< placement.indexOf("prepareSurfaceStructures"));
|
||||
assertTrue(placement.indexOf("prepareSurfaceStructures")
|
||||
< placement.indexOf("for (NativePlacementGroup group"));
|
||||
assertTrue(placement.indexOf("repairVacuumFoundations")
|
||||
> placement.indexOf("for (NativePlacementGroup group"));
|
||||
assertFalse(placement.contains("IrisLogging.reportError"));
|
||||
}
|
||||
|
||||
|
||||
+482
-9
@@ -40,6 +40,7 @@ import net.minecraft.world.level.levelgen.structure.StructurePiece;
|
||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
import net.minecraft.world.level.levelgen.structure.TerrainAdjustment;
|
||||
import net.minecraft.world.level.levelgen.structure.pieces.PiecesContainer;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.JigsawJunction;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.LegacySinglePoolElement;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.ListPoolElement;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.SinglePoolElement;
|
||||
@@ -54,6 +55,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProc
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -131,7 +133,7 @@ public class NativeStructurePostProcessorSurfaceTerrainTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void explicitVacuumForcesThinSurfaceFittingWithoutAuthoredAdaptation() {
|
||||
public void explicitVacuumUsesIndependentTerrainFittingWithoutAuthoredAdaptation() {
|
||||
StructureStart none = desertStart(TerrainAdjustment.NONE);
|
||||
StructureStart box = desertStart(TerrainAdjustment.BEARD_BOX);
|
||||
NativeStructureTerrainIntegrator.TerrainTarget sourceNone =
|
||||
@@ -150,11 +152,7 @@ public class NativeStructurePostProcessorSurfaceTerrainTest {
|
||||
assertFalse(NativeStructureSurfaceFitter.requiresSurfaceTerrain(sourceNone));
|
||||
assertTrue(NativeStructureSurfaceFitter.requiresSurfaceTerrain(vacuumNone));
|
||||
assertTrue(NativeStructureSurfaceFitter.requiresSurfaceTerrain(vacuumBox));
|
||||
assertEquals(TerrainAdjustment.BEARD_THIN,
|
||||
NativeStructureSurfaceFitter.effectiveSurfaceAdjustment(vacuumNone));
|
||||
assertEquals(TerrainAdjustment.BEARD_THIN,
|
||||
NativeStructureSurfaceFitter.effectiveSurfaceAdjustment(vacuumBox));
|
||||
assertTrue(NativeStructureTerrainIntegrator.clearsLegacyTemplateAir(
|
||||
assertFalse(NativeStructureTerrainIntegrator.clearsLegacyTemplateAir(
|
||||
none, vacuumNone.terrain()));
|
||||
}
|
||||
|
||||
@@ -263,6 +261,476 @@ public class NativeStructurePostProcessorSurfaceTerrainTest {
|
||||
assertEquals(Blocks.DIRT.defaultBlockState(), state(blocks, 11, 70, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumFitsOnlyProcessedSolidTemplateColumns() throws Exception {
|
||||
StructureTemplate sparseTemplate = template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState()),
|
||||
block(15, 0, 0, Blocks.STONE.defaultBlockState())));
|
||||
InlineSinglePoolElement element = new InlineSinglePoolElement(
|
||||
sparseTemplate, List.of(new ReplaceBlockProcessor(
|
||||
Blocks.STONE.defaultBlockState(), Blocks.AIR.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
element, new BoundingBox(0, 64, 0, 15, 70, 3), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 56, 0, 15, 72, 3);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 0, 64, 0));
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 0, 63, 0));
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 15, 60, 0));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 15, 61, 0));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 15, 64, 0));
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 15, 60, 3));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 15, 64, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumSupportsGroundDeltaZeroFoundations() throws Exception {
|
||||
StructureTemplate template = template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(template),
|
||||
new BoundingBox(0, 66, 0, 0, 70, 0), 0, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 3, 72, 3);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 0, 65, 0));
|
||||
assertEquals(Blocks.DIRT.defaultBlockState(), state(blocks, 0, 64, 0));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 0, 66, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumFindsActualTerrainBelowNominalOpenAirSurface() throws Exception {
|
||||
StructureTemplate template = template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(template),
|
||||
new BoundingBox(0, 75, 0, 0, 81, 0), 2, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 3, 84, 3);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 80);
|
||||
|
||||
for (int y = 61; y <= 74; y++) {
|
||||
assertFalse(state(blocks, 0, y, 0).isAir());
|
||||
}
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 0, 74, 0));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 0, 75, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumSupportsFoundationBelowHigherNaturalSurface() throws Exception {
|
||||
StructureTemplate template = template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
new InlineLegacyPoolElement(template),
|
||||
new BoundingBox(0, 75, 0, 0, 81, 0), 2, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 15, 84, 3);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
put(blocks, 0, 78, 0, Blocks.DIRT.defaultBlockState());
|
||||
put(blocks, 0, 79, 0, Blocks.GRASS_BLOCK.defaultBlockState());
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 79);
|
||||
|
||||
for (int y = 61; y <= 74; y++) {
|
||||
assertFalse(state(blocks, 0, y, 0).isAir());
|
||||
}
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 0, 75, 0));
|
||||
assertEquals(Blocks.DIRT.defaultBlockState(), state(blocks, 0, 78, 0));
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 0, 79, 0));
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 15, 60, 0));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 15, 61, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumRepairUsesOnlyProcessedSolidFoundationColumns() throws Exception {
|
||||
StructureTemplate template = template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState()),
|
||||
block(1, 0, 0, Blocks.STONE.defaultBlockState()),
|
||||
block(2, 0, 0, Blocks.AIR.defaultBlockState()),
|
||||
block(2, 2, 0, Blocks.COBBLESTONE.defaultBlockState())));
|
||||
InlineSinglePoolElement element = new InlineSinglePoolElement(
|
||||
template, List.of(new ReplaceBlockProcessor(
|
||||
Blocks.STONE.defaultBlockState(), Blocks.AIR.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
element, new BoundingBox(0, 65, 0, 2, 72, 0), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 3, 74, 3);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
|
||||
NativeStructureSurfaceFitter.VacuumFoundationPlan plan =
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
for (int y = 61; y <= 64; y++) {
|
||||
put(blocks, 0, y, 0, Blocks.CAVE_AIR.defaultBlockState());
|
||||
}
|
||||
put(blocks, 0, 65, 0, Blocks.COBBLESTONE.defaultBlockState());
|
||||
put(blocks, 1, 65, 0, Blocks.COBBLESTONE.defaultBlockState());
|
||||
put(blocks, 2, 67, 0, Blocks.COBBLESTONE.defaultBlockState());
|
||||
BlockState processorAirSupport = state(blocks, 1, 64, 0);
|
||||
BlockState authoredAirSupport = state(blocks, 2, 66, 0);
|
||||
|
||||
NativeStructureSurfaceFitter.repairVacuumFoundations(
|
||||
world(blocks), area, plan);
|
||||
|
||||
for (int y = 61; y <= 64; y++) {
|
||||
assertFalse(state(blocks, 0, y, 0).isAir());
|
||||
}
|
||||
assertEquals(processorAirSupport, state(blocks, 1, 64, 0));
|
||||
assertEquals(authoredAirSupport, state(blocks, 2, 66, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumRepairPreservesOverlappingAuthoredInterior() throws Exception {
|
||||
PoolElementStructurePiece lower = rigidTemplatePiece(
|
||||
new InlineLegacyPoolElement(template(List.of(
|
||||
block(0, 0, 0, Blocks.AIR.defaultBlockState()),
|
||||
block(0, 1, 0, Blocks.AIR.defaultBlockState())))),
|
||||
new BoundingBox(0, 61, 0, 0, 62, 0), 0, Rotation.NONE);
|
||||
PoolElementStructurePiece upper = rigidTemplatePiece(
|
||||
new InlineLegacyPoolElement(template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState())))),
|
||||
new BoundingBox(0, 65, 0, 0, 70, 0), 0, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(
|
||||
List.of(lower, upper), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 3, 72, 3);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
|
||||
NativeStructureSurfaceFitter.VacuumFoundationPlan plan =
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
put(blocks, 0, 65, 0, Blocks.COBBLESTONE.defaultBlockState());
|
||||
|
||||
NativeStructureSurfaceFitter.repairVacuumFoundations(
|
||||
world(blocks), area, plan);
|
||||
|
||||
for (int y = 61; y <= 64; y++) {
|
||||
assertTrue(state(blocks, 0, y, 0).isAir());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumRepairIsStableAcrossSplitChunkAreas() throws Exception {
|
||||
StructureTemplate template = template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState()),
|
||||
block(1, 0, 0, Blocks.COBBLESTONE.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
new InlineLegacyPoolElement(template),
|
||||
new BoundingBox(15, 65, 0, 16, 70, 0), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
NativeStructureTerrainIntegrator.TerrainTarget target =
|
||||
surfaceTarget(start, IrisStructureTerrainMode.VACUUM);
|
||||
BoundingBox wideArea = new BoundingBox(0, 54, 0, 31, 72, 15);
|
||||
BoundingBox westArea = new BoundingBox(0, 54, 0, 15, 72, 15);
|
||||
BoundingBox eastArea = new BoundingBox(16, 54, 0, 31, 72, 15);
|
||||
Map<BlockPos, BlockState> wideBlocks = flatTerrain(wideArea, 60);
|
||||
Map<BlockPos, BlockState> splitBlocks = flatTerrain(wideArea, 60);
|
||||
|
||||
NativeStructureSurfaceFitter.VacuumFoundationPlan widePlan =
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(wideBlocks), wideArea, List.of(target), (x, z) -> 60);
|
||||
NativeStructureSurfaceFitter.VacuumFoundationPlan westPlan =
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(splitBlocks), westArea, List.of(target), (x, z) -> 60);
|
||||
NativeStructureSurfaceFitter.VacuumFoundationPlan eastPlan =
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(splitBlocks), eastArea, List.of(target), (x, z) -> 60);
|
||||
for (int x = 15; x <= 16; x++) {
|
||||
for (int y = 61; y <= 64; y++) {
|
||||
put(wideBlocks, x, y, 0, Blocks.CAVE_AIR.defaultBlockState());
|
||||
put(splitBlocks, x, y, 0, Blocks.CAVE_AIR.defaultBlockState());
|
||||
}
|
||||
put(wideBlocks, x, 65, 0, Blocks.COBBLESTONE.defaultBlockState());
|
||||
put(splitBlocks, x, 65, 0, Blocks.COBBLESTONE.defaultBlockState());
|
||||
}
|
||||
|
||||
NativeStructureSurfaceFitter.repairVacuumFoundations(
|
||||
world(wideBlocks), wideArea, widePlan);
|
||||
NativeStructureSurfaceFitter.repairVacuumFoundations(
|
||||
world(splitBlocks), eastArea, eastPlan);
|
||||
NativeStructureSurfaceFitter.repairVacuumFoundations(
|
||||
world(splitBlocks), westArea, westPlan);
|
||||
|
||||
assertEquals(wideBlocks, splitBlocks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumNeverLowersExistingTerrainAroundSparsePieces() throws Exception {
|
||||
StructureTemplate sparseTemplate = template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(sparseTemplate),
|
||||
new BoundingBox(0, 56, 0, 7, 62, 7), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 48, 0, 7, 70, 7);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
Map<BlockPos, BlockState> originalBlocks = new HashMap<>(blocks);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
|
||||
assertEquals(originalBlocks, blocks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumDoesNotRaiseTerrainToRoofsAboveLegacyAir() throws Exception {
|
||||
StructureTemplate template = template(List.of(
|
||||
block(0, 0, 0, Blocks.AIR.defaultBlockState()),
|
||||
block(0, 2, 0, Blocks.COBBLESTONE.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
new InlineLegacyPoolElement(template),
|
||||
new BoundingBox(0, 66, 0, 7, 72, 7), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 15, 74, 15);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
Map<BlockPos, BlockState> originalBlocks = new HashMap<>(blocks);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
|
||||
assertEquals(originalBlocks, blocks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumCapsNeighborTaperAtAuthoredAirGroundPlanes() throws Exception {
|
||||
PoolElementStructurePiece roof = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(template(List.of(
|
||||
block(0, 0, 0, Blocks.AIR.defaultBlockState()),
|
||||
block(0, 2, 0, Blocks.COBBLESTONE.defaultBlockState())))),
|
||||
new BoundingBox(1, 66, 0, 1, 72, 0), 1, Rotation.NONE);
|
||||
PoolElementStructurePiece highChild = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState())))),
|
||||
new BoundingBox(0, 90, 0, 0, 94, 0), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(
|
||||
List.of(roof, highChild), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 15, 96, 15);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 1, 66, 0));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 1, 67, 0));
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 0, 89, 0));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 0, 90, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumDoesNotAnchorRoofsAboveProcessorCreatedAir() throws Exception {
|
||||
StructureTemplate template = template(List.of(
|
||||
block(0, 0, 0, Blocks.STONE.defaultBlockState()),
|
||||
block(0, 2, 0, Blocks.COBBLESTONE.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(template, List.of(new ReplaceBlockProcessor(
|
||||
Blocks.STONE.defaultBlockState(), Blocks.AIR.defaultBlockState()))),
|
||||
new BoundingBox(0, 66, 0, 7, 72, 7), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 15, 74, 15);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
Map<BlockPos, BlockState> originalBlocks = new HashMap<>(blocks);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
|
||||
assertEquals(originalBlocks, blocks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumDoesNotTreatSparseRoofCellsAsFoundations() throws Exception {
|
||||
StructureTemplate template = template(List.of(
|
||||
block(0, 0, 0, Blocks.SANDSTONE.defaultBlockState()),
|
||||
block(1, 20, 0, Blocks.SANDSTONE.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(template),
|
||||
new BoundingBox(0, 66, 0, 20, 100, 20), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 20, 102, 20);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 0, 65, 0));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 0, 66, 0));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 1, 67, 0));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 1, 86, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumDoesNotFlattenTerrainMatchingPoolPieces() throws Exception {
|
||||
StructureTemplate template = template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(
|
||||
template, List.of(),
|
||||
StructureTemplatePool.Projection.TERRAIN_MATCHING),
|
||||
new BoundingBox(0, 68, 0, 15, 72, 15), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 15, 74, 15);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
Map<BlockPos, BlockState> originalBlocks = new HashMap<>(blocks);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
|
||||
assertEquals(originalBlocks, blocks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumRetainsJunctionSmoothingForRigidFeaturePieces() {
|
||||
StructurePoolElement feature = StructurePoolElement.feature(
|
||||
Holder.<PlacedFeature>direct(null))
|
||||
.apply(StructureTemplatePool.Projection.RIGID);
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
feature, new BoundingBox(4, 66, 4, 4, 70, 4), 1, Rotation.NONE);
|
||||
piece.addJunction(new JigsawJunction(
|
||||
4, 66, 4, 0, StructureTemplatePool.Projection.RIGID));
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 15, 72, 15);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 4, 61, 4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumDoesNotInventNonPoolBoundingBoxFootprints() {
|
||||
StructureStart start = desertStart(TerrainAdjustment.NONE);
|
||||
BoundingBox bounds = start.getBoundingBox();
|
||||
BoundingBox area = new BoundingBox(
|
||||
bounds.minX() - 12, 40, bounds.minZ() - 12,
|
||||
bounds.maxX() + 12, bounds.maxY() + 12, bounds.maxZ() + 12);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 50);
|
||||
Map<BlockPos, BlockState> originalBlocks = new HashMap<>(blocks);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 50);
|
||||
|
||||
assertEquals(originalBlocks, blocks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumBudgetExhaustionSkipsFittingWithoutFailing() throws Exception {
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState())))),
|
||||
new BoundingBox(0, 66, 0, 0, 70, 0), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 15, 72, 15);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
Map<BlockPos, BlockState> originalBlocks = new HashMap<>(blocks);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60, 1);
|
||||
|
||||
assertEquals(originalBlocks, blocks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumContinuouslySupportsProcessedChildBases() throws Exception {
|
||||
PoolElementStructurePiece center = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState())))),
|
||||
new BoundingBox(0, 60, 0, 0, 64, 0), 1, Rotation.NONE);
|
||||
StructureTemplate childTemplate = template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState())));
|
||||
PoolElementStructurePiece child = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(childTemplate),
|
||||
new BoundingBox(10, 66, 0, 10, 72, 0), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(
|
||||
List.of(center, child), TerrainAdjustment.NONE);
|
||||
BoundingBox area = new BoundingBox(0, 54, 0, 15, 74, 3);
|
||||
Map<BlockPos, BlockState> blocks = flatTerrain(area, 60);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(blocks), area,
|
||||
List.of(surfaceTarget(start, IrisStructureTerrainMode.VACUUM)),
|
||||
(x, z) -> 60);
|
||||
|
||||
for (int y = 61; y <= 65; y++) {
|
||||
assertFalse(state(blocks, 10, y, 0).isAir());
|
||||
}
|
||||
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(blocks, 10, 65, 0));
|
||||
assertEquals(Blocks.AIR.defaultBlockState(), state(blocks, 10, 66, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vacuumSurfaceFittingIsStableAcrossSplitChunkAreas() throws Exception {
|
||||
StructureTemplate template = template(List.of(
|
||||
block(0, 0, 0, Blocks.COBBLESTONE.defaultBlockState()),
|
||||
block(1, 0, 0, Blocks.COBBLESTONE.defaultBlockState())));
|
||||
PoolElementStructurePiece piece = rigidTemplatePiece(
|
||||
new InlineSinglePoolElement(template),
|
||||
new BoundingBox(15, 66, 0, 16, 72, 0), 1, Rotation.NONE);
|
||||
StructureStart start = rigidSurfaceStart(List.of(piece), TerrainAdjustment.NONE);
|
||||
NativeStructureTerrainIntegrator.TerrainTarget target =
|
||||
surfaceTarget(start, IrisStructureTerrainMode.VACUUM);
|
||||
BoundingBox wideArea = new BoundingBox(0, 54, 0, 31, 74, 15);
|
||||
BoundingBox westArea = new BoundingBox(0, 54, 0, 15, 74, 15);
|
||||
BoundingBox eastArea = new BoundingBox(16, 54, 0, 31, 74, 15);
|
||||
Map<BlockPos, BlockState> wideBlocks = flatTerrain(wideArea, 60);
|
||||
Map<BlockPos, BlockState> splitBlocks = flatTerrain(wideArea, 60);
|
||||
Map<BlockPos, BlockState> reverseSplitBlocks = flatTerrain(wideArea, 60);
|
||||
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(wideBlocks), wideArea, List.of(target), (x, z) -> 60);
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(splitBlocks), westArea, List.of(target), (x, z) -> 60);
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(splitBlocks), eastArea, List.of(target), (x, z) -> 60);
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(reverseSplitBlocks), eastArea, List.of(target), (x, z) -> 60);
|
||||
NativeStructureSurfaceFitter.prepareSurfaceStructures(
|
||||
world(reverseSplitBlocks), westArea, List.of(target), (x, z) -> 60);
|
||||
|
||||
assertEquals(wideBlocks, splitBlocks);
|
||||
assertEquals(wideBlocks, reverseSplitBlocks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void surfaceAnchorIsFlushInsideAndUnchangedAtRadius() {
|
||||
NativeStructureSurfaceFitter.SurfaceAnchor anchor = anchor(72, 2);
|
||||
@@ -863,8 +1331,7 @@ public class NativeStructurePostProcessorSurfaceTerrainTest {
|
||||
BoundingBox area = new BoundingBox(0, 63, 0, 0, 68, 0);
|
||||
|
||||
NativeStructureVegetationClearer.clearIntersectingVegetation(
|
||||
world, chunk, area, List.of(
|
||||
new NativeStructureVegetationClearer.VegetationTarget(desertStart(), false)));
|
||||
world, chunk, area, List.of(desertStart()));
|
||||
NativeStructureSurfaceFitter.applySurfaceColumn(
|
||||
world, new BlockPos.MutableBlockPos(),
|
||||
0, 0, 64, 68, -64, 319);
|
||||
@@ -1642,9 +2109,15 @@ public class NativeStructurePostProcessorSurfaceTerrainTest {
|
||||
|
||||
private InlineSinglePoolElement(
|
||||
StructureTemplate template, List<StructureProcessor> processors) {
|
||||
this(template, processors, StructureTemplatePool.Projection.RIGID);
|
||||
}
|
||||
|
||||
private InlineSinglePoolElement(
|
||||
StructureTemplate template, List<StructureProcessor> processors,
|
||||
StructureTemplatePool.Projection projection) {
|
||||
super(Either.right(template),
|
||||
Holder.direct(new StructureProcessorList(processors)),
|
||||
StructureTemplatePool.Projection.RIGID,
|
||||
projection,
|
||||
Optional.<LiquidSettings>empty());
|
||||
}
|
||||
}
|
||||
|
||||
+215
-30
@@ -1,27 +1,55 @@
|
||||
package art.arcane.iris.nativegen;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.IdMapper;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.chunk.PalettedContainerFactory;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import net.minecraft.world.level.chunk.Strategy;
|
||||
import net.minecraft.world.level.chunk.UpgradeData;
|
||||
import net.minecraft.world.level.levelgen.GenerationStep;
|
||||
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
import net.minecraft.world.level.levelgen.structure.TerrainAdjustment;
|
||||
import net.minecraft.world.level.levelgen.structure.pieces.PiecesContainer;
|
||||
import net.minecraft.world.level.levelgen.structure.structures.DesertPyramidPiece;
|
||||
import net.minecraft.world.level.levelgen.structure.structures.DesertPyramidStructure;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class NativeStructurePostProcessorVegetationTest {
|
||||
private static final long TEST_SEED = 1234L;
|
||||
private static final int MIN_Y = -64;
|
||||
private static final int MAX_Y = 319;
|
||||
private static final int GROUND_Y = 64;
|
||||
private static final BoundingBox AREA = new BoundingBox(0, MIN_Y, 0, 15, MAX_Y, 15);
|
||||
|
||||
@BeforeClass
|
||||
public static void bootstrapMinecraftRegistries() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
@@ -29,52 +57,108 @@ public class NativeStructurePostProcessorVegetationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void surfaceStructuresClearTreeColumnsAutomatically() {
|
||||
assertTrue(NativeStructureVegetationClearer.shouldClearVegetationColumn(100, 100, false));
|
||||
assertTrue(NativeStructureVegetationClearer.shouldClearVegetationColumn(116, 100, false));
|
||||
public void canopyAboveTheStructureRoofSurvivesVegetationClearing() {
|
||||
ProtoChunk chunk = chunk();
|
||||
StructureStart start = desertStart(0, 0, GROUND_Y + 15);
|
||||
BoundingBox bounds = start.getBoundingBox();
|
||||
for (int y = bounds.maxY() - 1; y <= GROUND_Y + 40; y++) {
|
||||
fillLayer(chunk, y, leaves());
|
||||
}
|
||||
write(chunk, 4, bounds.minY() - 1, 4, log());
|
||||
|
||||
clearVegetation(chunk, start);
|
||||
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
assertEquals(leaves(), chunk.getBlockState(new BlockPos(x, GROUND_Y + 40, z)));
|
||||
assertEquals(leaves(), chunk.getBlockState(new BlockPos(x, bounds.maxY() + 1, z)));
|
||||
assertEquals(air(), chunk.getBlockState(new BlockPos(x, bounds.maxY(), z)));
|
||||
assertEquals(air(), chunk.getBlockState(new BlockPos(x, bounds.maxY() - 1, z)));
|
||||
}
|
||||
}
|
||||
assertEquals(air(), chunk.getBlockState(new BlockPos(4, bounds.minY() - 1, 4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buriedStructuresPreserveUnrelatedSurfaceForest() {
|
||||
assertFalse(NativeStructureVegetationClearer.shouldClearVegetationColumn(99, 100, false));
|
||||
assertFalse(NativeStructureVegetationClearer.shouldClearVegetationColumn(20, 100, false));
|
||||
public void buriedStructuresPreserveTheForestAboveThem() {
|
||||
ProtoChunk chunk = chunk();
|
||||
StructureStart start = desertStart(0, 0, -20);
|
||||
write(chunk, 8, GROUND_Y + 1, 8, log());
|
||||
write(chunk, 8, GROUND_Y + 2, 8, log());
|
||||
write(chunk, 8, GROUND_Y + 3, 8, log());
|
||||
write(chunk, 8, GROUND_Y + 4, 8, leaves());
|
||||
|
||||
clearVegetation(chunk, start);
|
||||
|
||||
assertEquals(log(), chunk.getBlockState(new BlockPos(8, GROUND_Y + 1, 8)));
|
||||
assertEquals(log(), chunk.getBlockState(new BlockPos(8, GROUND_Y + 2, 8)));
|
||||
assertEquals(log(), chunk.getBlockState(new BlockPos(8, GROUND_Y + 3, 8)));
|
||||
assertEquals(leaves(), chunk.getBlockState(new BlockPos(8, GROUND_Y + 4, 8)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void explicitVegetationOptionForcesUnusualPlacementCleanup() {
|
||||
assertTrue(NativeStructureVegetationClearer.shouldClearVegetationColumn(20, 100, true));
|
||||
public void columnsOutsideThePieceFootprintKeepEveryTreeBlock() {
|
||||
ProtoChunk chunk = chunk();
|
||||
StructureStart start = desertStart(8, 8, GROUND_Y + 15);
|
||||
BoundingBox bounds = start.getBoundingBox();
|
||||
int inside = bounds.minY() + 4;
|
||||
write(chunk, 0, inside, 0, log());
|
||||
write(chunk, 0, GROUND_Y + 40, 0, leaves());
|
||||
write(chunk, 12, inside, 12, log());
|
||||
write(chunk, 12, GROUND_Y + 40, 12, leaves());
|
||||
|
||||
clearVegetation(chunk, start);
|
||||
|
||||
assertEquals(log(), chunk.getBlockState(new BlockPos(0, inside, 0)));
|
||||
assertEquals(leaves(), chunk.getBlockState(new BlockPos(0, GROUND_Y + 40, 0)));
|
||||
assertEquals(air(), chunk.getBlockState(new BlockPos(12, inside, 12)));
|
||||
assertEquals(leaves(), chunk.getBlockState(new BlockPos(12, GROUND_Y + 40, 12)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonForcedValidTargetsReachIntersectionProcessing() {
|
||||
Structure structure = new DesertPyramidStructure(
|
||||
new Structure.StructureSettings(HolderSet.empty()));
|
||||
StructureStart start = new StructureStart(
|
||||
structure, new ChunkPos(0, 0), 0,
|
||||
new PiecesContainer(List.of(
|
||||
new DesertPyramidPiece(RandomSource.create(1L), 0, 0))));
|
||||
public void clearingStopsAtThePieceEnvelopeBoundaries() {
|
||||
ProtoChunk chunk = chunk();
|
||||
StructureStart start = desertStart(0, 0, GROUND_Y + 15);
|
||||
BoundingBox bounds = start.getBoundingBox();
|
||||
write(chunk, 4, bounds.maxY() + 1, 4, log());
|
||||
write(chunk, 4, bounds.maxY(), 4, log());
|
||||
write(chunk, 4, bounds.minY() - 1, 4, log());
|
||||
write(chunk, 4, bounds.minY() - 2, 4, log());
|
||||
|
||||
assertTrue(NativeStructureVegetationClearer.shouldProcessTarget(
|
||||
new NativeStructureVegetationClearer.VegetationTarget(start, false)));
|
||||
assertFalse(NativeStructureVegetationClearer.shouldProcessTarget(
|
||||
new NativeStructureVegetationClearer.VegetationTarget(
|
||||
StructureStart.INVALID_START, true)));
|
||||
clearVegetation(chunk, start);
|
||||
|
||||
assertEquals(log(), chunk.getBlockState(new BlockPos(4, bounds.maxY() + 1, 4)));
|
||||
assertEquals(air(), chunk.getBlockState(new BlockPos(4, bounds.maxY(), 4)));
|
||||
assertEquals(air(), chunk.getBlockState(new BlockPos(4, bounds.minY() - 1, 4)));
|
||||
assertEquals(log(), chunk.getBlockState(new BlockPos(4, bounds.minY() - 2, 4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void surfaceStructuresPreserveVegetationUnlessConfigured() {
|
||||
assertFalse(NativeStructureVegetationClearer.shouldClearEntireVegetationFootprint(
|
||||
GenerationStep.Decoration.SURFACE_STRUCTURES, false));
|
||||
assertTrue(NativeStructureVegetationClearer.shouldClearEntireVegetationFootprint(
|
||||
GenerationStep.Decoration.SURFACE_STRUCTURES, true));
|
||||
public void overlappingPieceEnvelopesMergeIntoOneClearedRange() {
|
||||
ProtoChunk chunk = chunk();
|
||||
StructureStart low = desertStart(0, 0, GROUND_Y);
|
||||
StructureStart high = desertStart(0, 0, GROUND_Y + 40);
|
||||
int between = GROUND_Y + 20;
|
||||
write(chunk, 4, between, 4, log());
|
||||
write(chunk, 4, high.getBoundingBox().maxY() + 1, 4, log());
|
||||
write(chunk, 4, low.getBoundingBox().minY() - 2, 4, log());
|
||||
|
||||
NativeStructureVegetationClearer.clearIntersectingVegetation(
|
||||
world(chunk), chunk, AREA, List.of(low, high));
|
||||
|
||||
assertEquals(air(), chunk.getBlockState(new BlockPos(4, between, 4)));
|
||||
assertEquals(log(), chunk.getBlockState(
|
||||
new BlockPos(4, high.getBoundingBox().maxY() + 1, 4)));
|
||||
assertEquals(log(), chunk.getBlockState(
|
||||
new BlockPos(4, low.getBoundingBox().minY() - 2, 4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undergroundStructuresPreserveSurfaceVegetationUnlessConfigured() {
|
||||
assertFalse(NativeStructureVegetationClearer.shouldClearEntireVegetationFootprint(
|
||||
GenerationStep.Decoration.UNDERGROUND_STRUCTURES, false));
|
||||
assertTrue(NativeStructureVegetationClearer.shouldClearEntireVegetationFootprint(
|
||||
GenerationStep.Decoration.UNDERGROUND_STRUCTURES, true));
|
||||
public void validStartsReachIntersectionProcessing() {
|
||||
assertTrue(NativeStructureVegetationClearer.shouldProcessStart(
|
||||
desertStart(0, 0, GROUND_Y + 15)));
|
||||
assertFalse(NativeStructureVegetationClearer.shouldProcessStart(
|
||||
StructureStart.INVALID_START));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,4 +187,105 @@ public class NativeStructurePostProcessorVegetationTest {
|
||||
assertEquals(-2, NativeStructureVerticalPlacer.resolveBuriedOffset(
|
||||
bounds, 0, 58, 320, (x, z) -> x == 1 ? 76 : 100));
|
||||
}
|
||||
|
||||
private static void clearVegetation(ProtoChunk chunk, StructureStart start) {
|
||||
NativeStructureVegetationClearer.clearIntersectingVegetation(
|
||||
world(chunk), chunk, AREA, List.of(start));
|
||||
}
|
||||
|
||||
private static StructureStart desertStart(int originX, int originZ, int topY) {
|
||||
Structure structure = new DesertPyramidStructure(
|
||||
new Structure.StructureSettings(
|
||||
HolderSet.empty(), Map.of(),
|
||||
GenerationStep.Decoration.SURFACE_STRUCTURES, TerrainAdjustment.NONE));
|
||||
DesertPyramidPiece piece = new DesertPyramidPiece(RandomSource.create(7L), originX, originZ);
|
||||
piece.move(0, topY - piece.getBoundingBox().maxY(), 0);
|
||||
return new StructureStart(
|
||||
structure, new ChunkPos(0, 0), 0, new PiecesContainer(List.of(piece)));
|
||||
}
|
||||
|
||||
private static ProtoChunk chunk() {
|
||||
return new ProtoChunk(
|
||||
new ChunkPos(0, 0), UpgradeData.EMPTY,
|
||||
LevelHeightAccessor.create(MIN_Y, MAX_Y - MIN_Y + 1), containerFactory(), null);
|
||||
}
|
||||
|
||||
private static void fillLayer(ProtoChunk chunk, int y, BlockState state) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
write(chunk, x, y, z, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void write(ProtoChunk chunk, int x, int y, int z, BlockState state) {
|
||||
LevelChunkSection section = chunk.getSection(chunk.getSectionIndex(y));
|
||||
section.setBlockState(x, y & 15, z, state, false);
|
||||
}
|
||||
|
||||
private static BlockState log() {
|
||||
return Blocks.OAK_LOG.defaultBlockState();
|
||||
}
|
||||
|
||||
private static BlockState leaves() {
|
||||
return Blocks.OAK_LEAVES.defaultBlockState();
|
||||
}
|
||||
|
||||
private static BlockState air() {
|
||||
return Blocks.AIR.defaultBlockState();
|
||||
}
|
||||
|
||||
private static WorldGenLevel world(ChunkAccess chunk) {
|
||||
InvocationHandler handler = (proxy, method, arguments) -> {
|
||||
String methodName = method.getName();
|
||||
if (methodName.equals("getBlockState")) {
|
||||
return chunk.getBlockState((BlockPos) arguments[0]);
|
||||
}
|
||||
if (methodName.equals("setBlock")) {
|
||||
return chunk.setBlockState(
|
||||
((BlockPos) arguments[0]).immutable(),
|
||||
(BlockState) arguments[1], (int) arguments[2]) != null;
|
||||
}
|
||||
if (methodName.equals("getSeed")) {
|
||||
return TEST_SEED;
|
||||
}
|
||||
if (methodName.equals("getLevel")) {
|
||||
return null;
|
||||
}
|
||||
if (methodName.equals("holderLookup")) {
|
||||
return BuiltInRegistries.BLOCK;
|
||||
}
|
||||
if (methodName.equals("hashCode")) {
|
||||
return System.identityHashCode(proxy);
|
||||
}
|
||||
if (methodName.equals("equals")) {
|
||||
return proxy == arguments[0];
|
||||
}
|
||||
if (methodName.equals("toString")) {
|
||||
return "vegetation-test-world";
|
||||
}
|
||||
throw new UnsupportedOperationException(method.toString());
|
||||
};
|
||||
return (WorldGenLevel) Proxy.newProxyInstance(
|
||||
WorldGenLevel.class.getClassLoader(), new Class<?>[]{WorldGenLevel.class}, handler);
|
||||
}
|
||||
|
||||
private static PalettedContainerFactory containerFactory() {
|
||||
Strategy<BlockState> blockStates = Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY);
|
||||
BlockState air = Blocks.AIR.defaultBlockState();
|
||||
IdMapper<Holder<Biome>> biomeIds = new IdMapper<>();
|
||||
Holder<Biome> defaultBiome = Holder.direct((Biome) null);
|
||||
biomeIds.add(defaultBiome);
|
||||
Strategy<Holder<Biome>> biomes = Strategy.createForBiomes(biomeIds);
|
||||
Codec<Holder<Biome>> biomeCodec = Codec.STRING.xmap(
|
||||
name -> defaultBiome, holder -> "iris-test-biome");
|
||||
return new PalettedContainerFactory(
|
||||
blockStates,
|
||||
air,
|
||||
PalettedContainer.codecRW(BlockState.CODEC, blockStates, air),
|
||||
biomes,
|
||||
defaultBiome,
|
||||
PalettedContainer.codecRO(biomeCodec, biomes, defaultBiome),
|
||||
PalettedContainer.codecRW(biomeCodec, biomes, defaultBiome));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -258,6 +258,6 @@ public class IrisStructureLocateCommandContractTest {
|
||||
|
||||
private static IrisNativeStructureDecision decision(NativeStructureGenerationStatus status) {
|
||||
return new IrisNativeStructureDecision(
|
||||
status, 0, null, false, false, null, null);
|
||||
status, 0, null, false, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user