This commit is contained in:
Brian Neumann-Fopiano
2026-04-23 22:44:52 -04:00
parent 1968ef2f2c
commit 821cc027db
15 changed files with 1123 additions and 279 deletions
@@ -8,7 +8,7 @@ import java.lang.reflect.Constructor;
import static org.junit.Assert.assertEquals;
public class MantleFloatingObjectComponentInvertedCountersTest {
public class MantleFloatingObjectComponentInvertedPlacementTest {
private FloatingObjectFootprint footprint(int lowestSolidKeyY, int highestSolidKeyY, int tallestKx, int tallestKz) throws Exception {
Constructor<FloatingObjectFootprint> constructor = FloatingObjectFootprint.class.getDeclaredConstructor(
@@ -38,40 +38,6 @@ public class MantleFloatingObjectComponentInvertedCountersTest {
);
}
@Test
public void resetObjectCounters_resetsAllInvertedCountersToZero() {
MantleFloatingObjectComponent.objectsInvertedAttempted.set(5);
MantleFloatingObjectComponent.objectsInvertedPlaced.set(3);
MantleFloatingObjectComponent.objectsInvertedSkippedNoFlat.set(2);
MantleFloatingObjectComponent.objectsInvertedFallbackNoInterior.set(1);
MantleFloatingObjectComponent.objectsInvertedSkippedShrink.set(4);
MantleFloatingObjectComponent.objectsInvertedSkippedNullObj.set(7);
MantleFloatingObjectComponent.writesDroppedAboveBottomTotal.set(11);
MantleFloatingObjectComponent.writesDroppedBottomOverhangTotal.set(9);
MantleFloatingObjectComponent.resetObjectCounters();
assertEquals(0, MantleFloatingObjectComponent.objectsInvertedAttempted.get());
assertEquals(0, MantleFloatingObjectComponent.objectsInvertedPlaced.get());
assertEquals(0, MantleFloatingObjectComponent.objectsInvertedSkippedNoFlat.get());
assertEquals(0, MantleFloatingObjectComponent.objectsInvertedFallbackNoInterior.get());
assertEquals(0, MantleFloatingObjectComponent.objectsInvertedSkippedShrink.get());
assertEquals(0, MantleFloatingObjectComponent.objectsInvertedSkippedNullObj.get());
assertEquals(0, MantleFloatingObjectComponent.writesDroppedAboveBottomTotal.get());
assertEquals(0, MantleFloatingObjectComponent.writesDroppedBottomOverhangTotal.get());
}
@Test
public void resetObjectCounters_alsoResetsExistingCounters_noRegression() {
MantleFloatingObjectComponent.objectsAttempted.set(99);
MantleFloatingObjectComponent.objectsPlaced.set(88);
MantleFloatingObjectComponent.resetObjectCounters();
assertEquals(0, MantleFloatingObjectComponent.objectsAttempted.get());
assertEquals(0, MantleFloatingObjectComponent.objectsPlaced.get());
}
@Test
public void invertedBaseY_anchorsOriginalLowestSolidBelowBottomFace() throws Exception {
FloatingObjectFootprint footprint = footprint(5, 30, 2, 3);
@@ -6,6 +6,9 @@ import art.arcane.volmlib.util.math.RNG;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
public class FloatingIslandSampleBottomYTest {
private FloatingIslandSample buildSample(int islandBaseY, boolean[] solidMask) {
@@ -55,6 +58,20 @@ public class FloatingIslandSampleBottomYTest {
assertEquals(first, second);
}
@Test
public void mergedEntryMask_preservesTopAndBottomOwners() {
IrisFloatingChildBiomes bottom = new IrisFloatingChildBiomes();
IrisFloatingChildBiomes top = new IrisFloatingChildBiomes();
boolean[] mask = {true, true, false, true};
IrisFloatingChildBiomes[] entryMask = {bottom, bottom, null, top};
FloatingIslandSample sample = FloatingIslandSample.constructForTest(top, 80, mask.length, 3, 3, mask, entryMask);
assertSame(top, sample.entry);
assertSame(bottom, sample.bottomEntry());
assertSame(bottom, sample.entryAt(1));
assertSame(top, sample.entryAt(3));
}
@Test
public void solidifyUncarvedInterior_fillsGapsBetweenSolids() {
boolean[] mask = {false, true, false, false, true, false};
@@ -124,6 +141,173 @@ public class FloatingIslandSampleBottomYTest {
assertEquals(false, mask[5]);
}
@Test
public void footprintPinholeFill_acceptsSingleColumnHoleWithSolidRing() {
CNG footprint = new CNG(new RNG(4)) {
@Override
public double noise(double x, double z) {
return x == 0 && z == 0 ? 0.46 : 1.0;
}
@Override
public double noise(double x, double y, double z) {
return noise(x, z);
}
};
FloatingIslandSample.NeighborSupport support = FloatingIslandSample.footprintNeighborSupport(footprint, 0, 0, 0.0);
assertTrue(FloatingIslandSample.isFootprintPinholeRepairable(-0.08, 0.0, support));
}
@Test
public void footprintPinholeFill_keepsBroadHoleOpen() {
CNG footprint = new CNG(new RNG(5)) {
@Override
public double noise(double x, double z) {
return Math.abs(x) <= 1 && Math.abs(z) <= 1 ? 0.0 : 1.0;
}
@Override
public double noise(double x, double y, double z) {
return noise(x, z);
}
};
FloatingIslandSample.NeighborSupport support = FloatingIslandSample.footprintNeighborSupport(footprint, 0, 0, 0.0);
assertFalse(FloatingIslandSample.isFootprintPinholeRepairable(-1.0, 0.0, support));
}
@Test
public void layerSupport_rejectsIsolatedSolidProtrusion() {
CNG footprint = new CNG(new RNG(6)) {
@Override
public double noise(double x, double z) {
return x == 0 && z == 0 ? 1.0 : 0.0;
}
@Override
public double noise(double x, double y, double z) {
return noise(x, z);
}
};
assertTrue(FloatingIslandSample.layerFootprintSolid(footprint, null, false, 0.0, 0, 64, 0, 0.0));
assertFalse(FloatingIslandSample.layerNeighborSupport(footprint, null, false, 0.0, 0, 64, 0, 0.0).hasSolidSupport());
}
@Test
public void layerSupport_fillsSingleColumnAirGap() {
CNG footprint = new CNG(new RNG(7)) {
@Override
public double noise(double x, double z) {
return x == 0 && z == 0 ? 0.0 : 1.0;
}
@Override
public double noise(double x, double y, double z) {
return noise(x, z);
}
};
assertFalse(FloatingIslandSample.layerFootprintSolid(footprint, null, false, 0.0, 0, 64, 0, 0.0));
assertTrue(FloatingIslandSample.layerNeighborSupport(footprint, null, false, 0.0, 0, 64, 0, 0.0).canFillPinhole());
}
@Test
public void carveSolidInterior_rejectsIsolatedCarveAir() {
boolean[] mask = {true, true, true, true, true};
CNG carve = new CNG(new RNG(8), new NoiseGenerator() {
@Override
public double noise(double x) {
return 0.0;
}
@Override
public double noise(double x, double z) {
return x == 0 && z == 0 ? 1.0 : 0.0;
}
@Override
public double noise(double x, double y, double z) {
return noise(x, z);
}
}, 1.0, 1);
int count = FloatingIslandSample.carveSolidInterior(mask, 100, 0, 0, carve, 0.5);
assertEquals(5, count);
assertEquals(true, mask[1]);
assertEquals(true, mask[2]);
assertEquals(true, mask[3]);
}
@Test
public void carveSolidInterior_capsBroadVerticalCarveSheet() {
boolean[] mask = new boolean[30];
for (int i = 0; i < mask.length; i++) {
mask[i] = true;
}
CNG carve = new CNG(new RNG(10), new NoiseGenerator() {
@Override
public double noise(double x) {
return 1.0;
}
@Override
public double noise(double x, double z) {
return 1.0;
}
@Override
public double noise(double x, double y, double z) {
return 1.0;
}
}, 1.0, 1);
int count = FloatingIslandSample.carveSolidInterior(mask, 100, 0, 0, carve, 0.5);
assertEquals(25, count);
for (int i = 0; i < FloatingIslandSample.carveShellThickness(mask.length); i++) {
assertTrue(mask[i]);
assertTrue(mask[mask.length - 1 - i]);
}
int longestAirRun = 0;
int currentAirRun = 0;
for (boolean solid : mask) {
if (solid) {
currentAirRun = 0;
continue;
}
currentAirRun++;
longestAirRun = Math.max(longestAirRun, currentAirRun);
}
assertEquals(FloatingIslandSample.maxVerticalCarveRun(mask.length), longestAirRun);
}
@Test
public void clampVerticalCarveRuns_keepsMiddleOfOversizedRunOnly() {
boolean[] carveMask = new boolean[12];
for (int i = 1; i <= 10; i++) {
carveMask[i] = true;
}
FloatingIslandSample.clampVerticalCarveRuns(carveMask, 1, 10, 4);
assertEquals(false, carveMask[2]);
assertEquals(true, carveMask[4]);
assertEquals(true, carveMask[7]);
assertEquals(false, carveMask[9]);
}
@Test
public void directCarveEnabled_respectsCarvingReferenceOverride() {
IrisFloatingChildBiomes entry = new IrisFloatingChildBiomes();
entry.setCarving("carving/mushroom");
CNG carve = new CNG(new RNG(9));
assertFalse(FloatingIslandSample.directCarveEnabled(entry, null, carve, 0.5));
}
@Test
public void hasFootprintNeighborSupport_rejectsSingleIsolatedColumn() {
CNG footprint = new CNG(new RNG(2)) {
@@ -0,0 +1,104 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.core.loader.ResourceLoader;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.volmlib.util.collection.KList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.block.data.BlockData;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import static org.junit.Assert.assertSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
public class IrisFloatingChildBiomesCarvingResolutionTest {
@BeforeClass
public static void setupBukkit() {
if (Bukkit.getServer() != null) {
return;
}
Server server = mock(Server.class);
BlockData emptyBlockData = mock(BlockData.class);
doReturn(Logger.getLogger("IrisTest")).when(server).getLogger();
doReturn("IrisTestServer").when(server).getName();
doReturn("1.0").when(server).getVersion();
doReturn("1.0").when(server).getBukkitVersion();
doReturn(emptyBlockData).when(server).createBlockData(any(Material.class));
doReturn(emptyBlockData).when(server).createBlockData(anyString());
Bukkit.setServer(server);
}
@Test
public void resolveCarvingBiome_loadsBiomeKeyWhenEntryIdMissing() {
IrisBiome biome = mock(IrisBiome.class);
Fixture fixture = createFixture(Map.of(), Map.of("carving/mushroom", biome));
IrisBiome resolved = IrisFloatingChildBiomes.resolveCarvingBiome("carving/mushroom", fixture.engine, fixture.data);
assertSame(biome, resolved);
}
@Test
public void resolveCarvingBiome_prefersDimensionCarvingEntryId() {
IrisBiome entryBiome = mock(IrisBiome.class);
IrisBiome sameKeyBiome = mock(IrisBiome.class);
IrisDimensionCarvingEntry entry = new IrisDimensionCarvingEntry();
entry.setId("global-deepdark-band");
entry.setBiome("carving/standard-deepdark");
Map<String, IrisDimensionCarvingEntry> entries = new HashMap<>();
entries.put("global-deepdark-band", entry);
Map<String, IrisBiome> biomes = new HashMap<>();
biomes.put("carving/standard-deepdark", entryBiome);
biomes.put("global-deepdark-band", sameKeyBiome);
Fixture fixture = createFixture(entries, biomes);
IrisBiome resolved = IrisFloatingChildBiomes.resolveCarvingBiome("global-deepdark-band", fixture.engine, fixture.data);
assertSame(entryBiome, resolved);
}
private Fixture createFixture(Map<String, IrisDimensionCarvingEntry> entries, Map<String, IrisBiome> biomes) {
@SuppressWarnings("unchecked")
ResourceLoader<IrisBiome> biomeLoader = mock(ResourceLoader.class);
for (Map.Entry<String, IrisBiome> biome : biomes.entrySet()) {
doReturn(biome.getValue()).when(biomeLoader).load(biome.getKey());
}
IrisData data = mock(IrisData.class);
doReturn(biomeLoader).when(data).getBiomeLoader();
IrisDimension dimension = mock(IrisDimension.class);
doReturn(entries).when(dimension).getCarvingEntryIndex();
doReturn(new KList<>(entries.values())).when(dimension).getCarving();
Engine engine = mock(Engine.class);
doReturn(data).when(engine).getData();
doReturn(dimension).when(engine).getDimension();
return new Fixture(engine, data);
}
private static final class Fixture {
private final Engine engine;
private final IrisData data;
private Fixture(Engine engine, IrisData data) {
this.engine = engine;
this.data = data;
}
}
}
@@ -0,0 +1,121 @@
package art.arcane.iris.engine.object;
import art.arcane.volmlib.util.collection.KList;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
public class IrisObjectPlacementToPlacementTest {
@Test
public void toPlacement_preservesInheritedPlacementMetadata() {
IrisObjectPlacement source = new IrisObjectPlacement();
IrisObjectRotation rotation = new IrisObjectRotation();
IrisObjectLimit clamp = new IrisObjectLimit();
IrisStyledRange densityStyle = new IrisStyledRange();
densityStyle.setMin(7D);
densityStyle.setMax(7D);
IrisStiltSettings stiltSettings = new IrisStiltSettings();
KList<IrisObjectMarker> markers = new KList<>();
IrisNoiseGenerator heightmap = new IrisNoiseGenerator(false);
IrisGeneratorStyle warp = NoiseStyle.SIMPLEX.style();
KList<IrisObjectReplace> edit = new KList<>();
IrisObjectTranslate translate = new IrisObjectTranslate();
IrisObjectScale scale = new IrisObjectScale();
KList<IrisObjectLoot> loot = new KList<>();
KList<IrisObjectVanillaLoot> vanillaLoot = new KList<>();
KList<IrisTree> trees = new KList<>();
KList<String> allowedCollisions = new KList<>();
KList<String> forbiddenCollisions = new KList<>();
IrisSlopeClip slopeCondition = new IrisSlopeClip();
markers.add(new IrisObjectMarker());
edit.add(new IrisObjectReplace());
loot.add(new IrisObjectLoot());
vanillaLoot.add(new IrisObjectVanillaLoot());
trees.add(new IrisTree());
allowedCollisions.add("objects/allowed");
forbiddenCollisions.add("objects/forbidden");
source.setRotation(rotation);
source.setClamp(clamp);
source.setSnow(0.4D);
source.setDolphinTarget(true);
source.setSlopeCondition(slopeCondition);
source.setRotateTowardsSlope(true);
source.setChance(0.25D);
source.setDensity(7);
source.setDensityStyle(densityStyle);
source.setStiltSettings(stiltSettings);
source.setBoreExtendMaxY(8);
source.setMarkers(markers);
source.setBoreExtendMinY(3);
source.setUnderwater(true);
source.setCarvingSupport(CarvingMode.ANYWHERE);
source.setCaveAnchorMode(IrisCaveAnchorMode.CEILING);
source.setHeightmap(heightmap);
source.setSmartBore(true);
source.setWaterloggable(true);
source.setOnwater(true);
source.setMeld(true);
source.setFromBottom(true);
source.setBottom(true);
source.setBore(true);
source.setWarp(warp);
source.setTranslateCenter(true);
source.setMode(ObjectPlaceMode.FAST_MIN_STILT);
source.setEdit(edit);
source.setTranslate(translate);
source.setScale(scale);
source.setLoot(loot);
source.setVanillaLoot(vanillaLoot);
source.setOverrideGlobalLoot(true);
source.setTrees(trees);
source.setAllowedCollisions(allowedCollisions);
source.setForbiddenCollisions(forbiddenCollisions);
source.setForcePlace(true);
IrisObjectPlacement copy = source.toPlacement("objects/replaced");
assertEquals(1, copy.getPlace().size());
assertEquals("objects/replaced", copy.getPlace().get(0));
assertSame(rotation, copy.getRotation());
assertSame(clamp, copy.getClamp());
assertEquals(0.4D, copy.getSnow(), 0.0D);
assertTrue(copy.isDolphinTarget());
assertSame(slopeCondition, copy.getSlopeCondition());
assertTrue(copy.isRotateTowardsSlope());
assertEquals(0.25D, copy.getChance(), 0.0D);
assertEquals(7, copy.getDensity());
assertSame(densityStyle, copy.getDensityStyle());
assertSame(stiltSettings, copy.getStiltSettings());
assertEquals(8, copy.getBoreExtendMaxY());
assertSame(markers, copy.getMarkers());
assertEquals(3, copy.getBoreExtendMinY());
assertTrue(copy.isUnderwater());
assertEquals(CarvingMode.ANYWHERE, copy.getCarvingSupport());
assertEquals(IrisCaveAnchorMode.CEILING, copy.getCaveAnchorMode());
assertSame(heightmap, copy.getHeightmap());
assertTrue(copy.isSmartBore());
assertTrue(copy.isWaterloggable());
assertTrue(copy.isOnwater());
assertTrue(copy.isMeld());
assertTrue(copy.isFromBottom());
assertTrue(copy.isBottom());
assertTrue(copy.isBore());
assertSame(warp, copy.getWarp());
assertTrue(copy.isTranslateCenter());
assertEquals(ObjectPlaceMode.FAST_MIN_STILT, copy.getMode());
assertSame(edit, copy.getEdit());
assertSame(translate, copy.getTranslate());
assertSame(scale, copy.getScale());
assertSame(loot, copy.getLoot());
assertSame(vanillaLoot, copy.getVanillaLoot());
assertTrue(copy.isOverrideGlobalLoot());
assertSame(trees, copy.getTrees());
assertSame(allowedCollisions, copy.getAllowedCollisions());
assertSame(forbiddenCollisions, copy.getForbiddenCollisions());
assertTrue(copy.isForcePlace());
}
}
@@ -17,7 +17,7 @@ public class IslandObjectPlacerAnchorFaceTest {
@Test
public void bottomFace_getHighest_inFootprint_returnsSampleBottomY() {
FloatingIslandSample[] samples = new FloatingIslandSample[256];
samples[0] = sampleWithBottomAt(100, 0); // bottomY = 100
samples[0] = sampleWithBottomAt(100, 0);
IslandObjectPlacer placer = new IslandObjectPlacer(null, samples, 0, 0, 100, IslandObjectPlacer.AnchorFace.BOTTOM);
@@ -28,43 +28,37 @@ public class IslandObjectPlacerAnchorFaceTest {
@Test
public void bottomFace_getHighest_offFootprint_returnsChunkMinBottomY() {
FloatingIslandSample[] samples = new FloatingIslandSample[256];
samples[0] = sampleWithBottomAt(100, 0); // bottomY = 100, only sample
samples[0] = sampleWithBottomAt(100, 0);
IslandObjectPlacer placer = new IslandObjectPlacer(null, samples, 0, 0, 100, IslandObjectPlacer.AnchorFace.BOTTOM);
// No sample at (15, 15) → falls back to chunkMinIslandBottomY = 100
int result = placer.getHighest(15, 15, null);
assertEquals(100, result);
}
@Test
public void bottomFace_set_aboveAnchor_dropsWrite_andIncrementsDroppedAboveBottom() {
public void bottomFace_set_aboveAnchor_dropsWrite() {
FloatingIslandSample[] samples = new FloatingIslandSample[256];
samples[0] = sampleWithBottomAt(100, 0); // bottomY = 100
samples[0] = sampleWithBottomAt(100, 0);
IslandObjectPlacer placer = new IslandObjectPlacer(null, samples, 0, 0, 100, IslandObjectPlacer.AnchorFace.BOTTOM);
// y=101 >= anchorBottomY=100 → in-footprint but above/at anchor → dropped
assertEquals(false, placer.canWriteObjectBlock(0, 101, 0));
placer.set(0, 101, 0, null);
assertEquals(1, placer.getWritesAttempted());
assertEquals(1, placer.getWritesDroppedAboveBottom());
}
@Test
public void bottomFace_canWriteObjectBlock_allowsBelowAnchorWithoutCounting() {
public void bottomFace_canWriteObjectBlock_allowsBelowAnchor() {
FloatingIslandSample[] samples = new FloatingIslandSample[256];
samples[0] = sampleWithBottomAt(100, 0);
IslandObjectPlacer placer = new IslandObjectPlacer(null, samples, 0, 0, 100, IslandObjectPlacer.AnchorFace.BOTTOM);
assertEquals(true, placer.canWriteObjectBlock(0, 99, 0));
assertEquals(0, placer.getWritesAttempted());
assertEquals(0, placer.getWritesDroppedAboveBottom());
}
@Test
public void bottomFace_canWriteObjectBlock_blocksAnchorAndAboveWithoutCounting() {
public void bottomFace_canWriteObjectBlock_blocksAnchorAndAbove() {
FloatingIslandSample[] samples = new FloatingIslandSample[256];
samples[0] = sampleWithBottomAt(100, 0);
@@ -72,23 +66,16 @@ public class IslandObjectPlacerAnchorFaceTest {
assertEquals(false, placer.canWriteObjectBlock(0, 100, 0));
assertEquals(false, placer.canWriteObjectBlock(0, 101, 0));
assertEquals(0, placer.getWritesAttempted());
assertEquals(0, placer.getWritesDroppedAboveBottom());
}
@Test
public void topFace_existingConstructor_dropsBelowAnchor_noRegression() {
FloatingIslandSample[] samples = new FloatingIslandSample[256];
samples[0] = sampleWithBottomAt(100, 0);
// No sample at x=1, z=0 (idx=1)
// Existing single-face constructor defaults to TOP
IslandObjectPlacer placer = new IslandObjectPlacer(null, samples, 0, 0, 105);
// Off-footprint column, y=104 <= anchorTopY=105 → dropped below
assertEquals(false, placer.canWriteObjectBlock(1, 104, 0));
placer.set(1, 104, 0, null);
assertEquals(1, placer.getWritesAttempted());
assertEquals(1, placer.getWritesDroppedBelow());
}
}
@@ -0,0 +1,49 @@
package art.arcane.iris.engine.platform;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
public class BukkitChunkGeneratorOverlayPolicyTest {
@Test
public void skipsAirOverlayBlocks() {
BlockData air = mock(BlockData.class);
doReturn(Material.AIR).when(air).getMaterial();
assertFalse(BukkitChunkGenerator.shouldApplyMantleOverlayBlock(air));
}
@Test
public void skipsCaveAirOverlayBlocks() {
BlockData air = mock(BlockData.class);
doReturn(Material.CAVE_AIR).when(air).getMaterial();
assertFalse(BukkitChunkGenerator.shouldApplyMantleOverlayBlock(air));
}
@Test
public void skipsVoidAirOverlayBlocks() {
BlockData air = mock(BlockData.class);
doReturn(Material.VOID_AIR).when(air).getMaterial();
assertFalse(BukkitChunkGenerator.shouldApplyMantleOverlayBlock(air));
}
@Test
public void appliesSolidOverlayBlocks() {
BlockData stone = mock(BlockData.class);
doReturn(Material.STONE).when(stone).getMaterial();
assertTrue(BukkitChunkGenerator.shouldApplyMantleOverlayBlock(stone));
}
@Test
public void skipsNullOverlayBlocks() {
assertFalse(BukkitChunkGenerator.shouldApplyMantleOverlayBlock(null));
}
}