mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-08-27 12:41:43 +00:00
adding mroe of this
This commit is contained in:
@@ -39,6 +39,10 @@ public final class CarveOrphanSweep {
|
|||||||
|
|
||||||
void markCarved(int localX, int y, int localZ);
|
void markCarved(int localX, int y, int localZ);
|
||||||
|
|
||||||
|
default boolean isProtected(int localX, int y, int localZ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cheap pre-check: may any block in [minY, maxY] be carved at all? Default true keeps
|
* Cheap pre-check: may any block in [minY, maxY] be carved at all? Default true keeps
|
||||||
* every implementor correct; the mantle-backed access answers from section slice
|
* every implementor correct; the mantle-backed access answers from section slice
|
||||||
@@ -52,12 +56,20 @@ public final class CarveOrphanSweep {
|
|||||||
private CarveOrphanSweep() {
|
private CarveOrphanSweep() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sweepChunk(MantleChunk<Matter> chunk, int[] surfaceHeights, int maxSurfaceBreakDepth, int worldCeilingY) {
|
static int sweepChunk(
|
||||||
|
MantleChunk<Matter> chunk,
|
||||||
|
int[] surfaceHeights,
|
||||||
|
int maxSurfaceBreakDepth,
|
||||||
|
int worldCeilingY,
|
||||||
|
int[] surfaceFluidBoundaryStartY,
|
||||||
|
int fluidHeight
|
||||||
|
) {
|
||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sweep(surfaceHeights, maxSurfaceBreakDepth, 0, worldCeilingY, new MantleCarveAccess(chunk));
|
return sweep(surfaceHeights, maxSurfaceBreakDepth, 0, worldCeilingY,
|
||||||
|
new MantleCarveAccess(chunk, surfaceFluidBoundaryStartY, fluidHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int sweep(int[] surfaceHeights, int maxSurfaceBreakDepth, int worldFloorY, int worldCeilingY, CarveAccess access) {
|
public static int sweep(int[] surfaceHeights, int maxSurfaceBreakDepth, int worldFloorY, int worldCeilingY, CarveAccess access) {
|
||||||
@@ -141,7 +153,9 @@ public final class CarveOrphanSweep {
|
|||||||
int y = bandFloor + (current / CHUNK_AREA);
|
int y = bandFloor + (current / CHUNK_AREA);
|
||||||
|
|
||||||
if (!anchored) {
|
if (!anchored) {
|
||||||
if (localX == 0 || localX == CHUNK_SIZE - 1 || localZ == 0 || localZ == CHUNK_SIZE - 1) {
|
if (access.isProtected(localX, y, localZ)) {
|
||||||
|
anchored = true;
|
||||||
|
} else if (localX == 0 || localX == CHUNK_SIZE - 1 || localZ == 0 || localZ == CHUNK_SIZE - 1) {
|
||||||
anchored = true;
|
anchored = true;
|
||||||
} else if (y == bandFloor && isSolidBelowBand(access, surfaceHeights, columnIndex, localX, localZ, bandFloor - 1, worldFloorY)) {
|
} else if (y == bandFloor && isSolidBelowBand(access, surfaceHeights, columnIndex, localX, localZ, bandFloor - 1, worldFloorY)) {
|
||||||
anchored = true;
|
anchored = true;
|
||||||
@@ -215,11 +229,15 @@ public final class CarveOrphanSweep {
|
|||||||
|
|
||||||
private static final class MantleCarveAccess implements CarveAccess {
|
private static final class MantleCarveAccess implements CarveAccess {
|
||||||
private final MantleChunk<Matter> chunk;
|
private final MantleChunk<Matter> chunk;
|
||||||
|
private final int[] surfaceFluidBoundaryStartY;
|
||||||
|
private final int fluidHeight;
|
||||||
private MatterSlice<MatterCavern> cachedSlice;
|
private MatterSlice<MatterCavern> cachedSlice;
|
||||||
private int cachedSectionIndex = -1;
|
private int cachedSectionIndex = -1;
|
||||||
|
|
||||||
private MantleCarveAccess(MantleChunk<Matter> chunk) {
|
private MantleCarveAccess(MantleChunk<Matter> chunk, int[] surfaceFluidBoundaryStartY, int fluidHeight) {
|
||||||
this.chunk = chunk;
|
this.chunk = chunk;
|
||||||
|
this.surfaceFluidBoundaryStartY = surfaceFluidBoundaryStartY;
|
||||||
|
this.fluidHeight = fluidHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -240,6 +258,12 @@ public final class CarveOrphanSweep {
|
|||||||
cachedSlice = null;
|
cachedSlice = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isProtected(int localX, int y, int localZ) {
|
||||||
|
int columnIndex = PowerOfTwoCoordinates.packLocal16(localX, localZ);
|
||||||
|
return SurfaceFluidBoundaryPlan.protects(surfaceFluidBoundaryStartY, columnIndex, y, fluidHeight);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mayContainCarvedCells(int minY, int maxY) {
|
public boolean mayContainCarvedCells(int minY, int maxY) {
|
||||||
int minSection = Math.max(0, minY >> 4);
|
int minSection = Math.max(0, minY >> 4);
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ public class IrisCaveCarver3D {
|
|||||||
) {
|
) {
|
||||||
CaveFluidSupportPlan fluidSupportPlan = new CaveFluidSupportPlan();
|
CaveFluidSupportPlan fluidSupportPlan = new CaveFluidSupportPlan();
|
||||||
int carved = carve(writer, chunkX, chunkZ, columnWeights, minWeight, thresholdPenalty,
|
int carved = carve(writer, chunkX, chunkZ, columnWeights, minWeight, thresholdPenalty,
|
||||||
worldYRange, precomputedSurfaceHeights, overrideVerticalRange, fluidSupportPlan);
|
worldYRange, precomputedSurfaceHeights, null, overrideVerticalRange, fluidSupportPlan);
|
||||||
fluidSupportPlan.resolve(writer.acquireChunk(chunkX, chunkZ));
|
fluidSupportPlan.resolve(writer.acquireChunk(chunkX, chunkZ));
|
||||||
return carved;
|
return carved;
|
||||||
}
|
}
|
||||||
@@ -197,6 +197,7 @@ public class IrisCaveCarver3D {
|
|||||||
double thresholdPenalty,
|
double thresholdPenalty,
|
||||||
IrisRange worldYRange,
|
IrisRange worldYRange,
|
||||||
int[] precomputedSurfaceHeights,
|
int[] precomputedSurfaceHeights,
|
||||||
|
int[] surfaceFluidBoundaryStartY,
|
||||||
IrisRange overrideVerticalRange,
|
IrisRange overrideVerticalRange,
|
||||||
CaveFluidSupportPlan fluidSupportPlan
|
CaveFluidSupportPlan fluidSupportPlan
|
||||||
) {
|
) {
|
||||||
@@ -317,6 +318,7 @@ public class IrisCaveCarver3D {
|
|||||||
surfaceBreakThresholdBoost,
|
surfaceBreakThresholdBoost,
|
||||||
columnMaxY,
|
columnMaxY,
|
||||||
fluidMaxY,
|
fluidMaxY,
|
||||||
|
surfaceFluidBoundaryStartY,
|
||||||
surfaceBreakFloorY,
|
surfaceBreakFloorY,
|
||||||
surfaceBreakColumn,
|
surfaceBreakColumn,
|
||||||
columnThreshold,
|
columnThreshold,
|
||||||
@@ -339,6 +341,7 @@ public class IrisCaveCarver3D {
|
|||||||
surfaceBreakThresholdBoost,
|
surfaceBreakThresholdBoost,
|
||||||
columnMaxY,
|
columnMaxY,
|
||||||
fluidMaxY,
|
fluidMaxY,
|
||||||
|
surfaceFluidBoundaryStartY,
|
||||||
surfaceBreakFloorY,
|
surfaceBreakFloorY,
|
||||||
surfaceBreakColumn,
|
surfaceBreakColumn,
|
||||||
columnThreshold,
|
columnThreshold,
|
||||||
@@ -364,6 +367,7 @@ public class IrisCaveCarver3D {
|
|||||||
surfaceBreakThresholdBoost,
|
surfaceBreakThresholdBoost,
|
||||||
columnMaxY,
|
columnMaxY,
|
||||||
fluidMaxY,
|
fluidMaxY,
|
||||||
|
surfaceFluidBoundaryStartY,
|
||||||
surfaceBreakFloorY,
|
surfaceBreakFloorY,
|
||||||
surfaceBreakColumn,
|
surfaceBreakColumn,
|
||||||
columnThreshold,
|
columnThreshold,
|
||||||
@@ -387,6 +391,7 @@ public class IrisCaveCarver3D {
|
|||||||
surfaceBreakThresholdBoost,
|
surfaceBreakThresholdBoost,
|
||||||
columnMaxY,
|
columnMaxY,
|
||||||
fluidMaxY,
|
fluidMaxY,
|
||||||
|
surfaceFluidBoundaryStartY,
|
||||||
surfaceBreakFloorY,
|
surfaceBreakFloorY,
|
||||||
surfaceBreakColumn,
|
surfaceBreakColumn,
|
||||||
columnThreshold,
|
columnThreshold,
|
||||||
@@ -417,6 +422,7 @@ public class IrisCaveCarver3D {
|
|||||||
double surfaceBreakThresholdBoost,
|
double surfaceBreakThresholdBoost,
|
||||||
int[] columnMaxY,
|
int[] columnMaxY,
|
||||||
int[] fluidMaxY,
|
int[] fluidMaxY,
|
||||||
|
int[] surfaceFluidBoundaryStartY,
|
||||||
int[] surfaceBreakFloorY,
|
int[] surfaceBreakFloorY,
|
||||||
boolean[] surfaceBreakColumn,
|
boolean[] surfaceBreakColumn,
|
||||||
double[] columnThreshold,
|
double[] columnThreshold,
|
||||||
@@ -472,6 +478,9 @@ public class IrisCaveCarver3D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int columnIndex = activeColumnIndices[activeIndex];
|
int columnIndex = activeColumnIndices[activeIndex];
|
||||||
|
if (SurfaceFluidBoundaryPlan.protects(surfaceFluidBoundaryStartY, columnIndex, y, fluidHeight)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
planeColumnIndices[planeCount] = columnIndex;
|
planeColumnIndices[planeCount] = columnIndex;
|
||||||
double localThreshold = passThreshold[columnIndex];
|
double localThreshold = passThreshold[columnIndex];
|
||||||
if (surfaceBreakColumn[columnIndex] && y >= surfaceBreakFloorY[columnIndex]) {
|
if (surfaceBreakColumn[columnIndex] && y >= surfaceBreakFloorY[columnIndex]) {
|
||||||
@@ -544,6 +553,7 @@ public class IrisCaveCarver3D {
|
|||||||
double surfaceBreakThresholdBoost,
|
double surfaceBreakThresholdBoost,
|
||||||
int[] columnMaxY,
|
int[] columnMaxY,
|
||||||
int[] fluidMaxY,
|
int[] fluidMaxY,
|
||||||
|
int[] surfaceFluidBoundaryStartY,
|
||||||
int[] surfaceBreakFloorY,
|
int[] surfaceBreakFloorY,
|
||||||
boolean[] surfaceBreakColumn,
|
boolean[] surfaceBreakColumn,
|
||||||
double[] columnThreshold,
|
double[] columnThreshold,
|
||||||
@@ -605,6 +615,9 @@ public class IrisCaveCarver3D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int columnIndex = activeColumnIndices[activeIndex];
|
int columnIndex = activeColumnIndices[activeIndex];
|
||||||
|
if (SurfaceFluidBoundaryPlan.protects(surfaceFluidBoundaryStartY, columnIndex, y, fluidHeight)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
planeColumnIndices[planeCount] = columnIndex;
|
planeColumnIndices[planeCount] = columnIndex;
|
||||||
double localThreshold = passThreshold[columnIndex];
|
double localThreshold = passThreshold[columnIndex];
|
||||||
if (surfaceBreakColumn[columnIndex] && y >= surfaceBreakFloorY[columnIndex]) {
|
if (surfaceBreakColumn[columnIndex] && y >= surfaceBreakFloorY[columnIndex]) {
|
||||||
@@ -699,6 +712,7 @@ public class IrisCaveCarver3D {
|
|||||||
double surfaceBreakThresholdBoost,
|
double surfaceBreakThresholdBoost,
|
||||||
int[] columnMaxY,
|
int[] columnMaxY,
|
||||||
int[] fluidMaxY,
|
int[] fluidMaxY,
|
||||||
|
int[] surfaceFluidBoundaryStartY,
|
||||||
int[] surfaceBreakFloorY,
|
int[] surfaceBreakFloorY,
|
||||||
boolean[] surfaceBreakColumn,
|
boolean[] surfaceBreakColumn,
|
||||||
double[] columnThreshold,
|
double[] columnThreshold,
|
||||||
@@ -800,6 +814,9 @@ public class IrisCaveCarver3D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int index = tileIndices[columnIndex];
|
int index = tileIndices[columnIndex];
|
||||||
|
if (SurfaceFluidBoundaryPlan.protects(surfaceFluidBoundaryStartY, index, yy, fluidHeight)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
double localThreshold = passThreshold[index];
|
double localThreshold = passThreshold[index];
|
||||||
if (surfaceBreakColumn[index] && yy >= surfaceBreakFloorY[index]) {
|
if (surfaceBreakColumn[index] && yy >= surfaceBreakFloorY[index]) {
|
||||||
localThreshold += surfaceBreakThresholdBoost;
|
localThreshold += surfaceBreakThresholdBoost;
|
||||||
@@ -844,6 +861,7 @@ public class IrisCaveCarver3D {
|
|||||||
double surfaceBreakThresholdBoost,
|
double surfaceBreakThresholdBoost,
|
||||||
int[] columnMaxY,
|
int[] columnMaxY,
|
||||||
int[] fluidMaxY,
|
int[] fluidMaxY,
|
||||||
|
int[] surfaceFluidBoundaryStartY,
|
||||||
int[] surfaceBreakFloorY,
|
int[] surfaceBreakFloorY,
|
||||||
boolean[] surfaceBreakColumn,
|
boolean[] surfaceBreakColumn,
|
||||||
double[] columnThreshold,
|
double[] columnThreshold,
|
||||||
@@ -891,6 +909,9 @@ public class IrisCaveCarver3D {
|
|||||||
|
|
||||||
int carveMaxY = Math.min(columnTopY, y + sampleStep - 1);
|
int carveMaxY = Math.min(columnTopY, y + sampleStep - 1);
|
||||||
for (int yy = y; yy <= carveMaxY; yy++) {
|
for (int yy = y; yy <= carveMaxY; yy++) {
|
||||||
|
if (SurfaceFluidBoundaryPlan.protects(surfaceFluidBoundaryStartY, index, yy, fluidHeight)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
MatterCavern verticalMatter = matterByY[yy - minY];
|
MatterCavern verticalMatter = matterByY[yy - minY];
|
||||||
MatterCavern matter = resolveMatter(verticalMatter, x, yy, z,
|
MatterCavern matter = resolveMatter(verticalMatter, x, yy, z,
|
||||||
index, fluidMaxY, localThreshold);
|
index, fluidMaxY, localThreshold);
|
||||||
|
|||||||
+33
-5
@@ -30,6 +30,8 @@ import art.arcane.iris.engine.object.IrisDimensionCarvingEntry;
|
|||||||
import art.arcane.iris.engine.object.IrisDimensionCarvingResolver;
|
import art.arcane.iris.engine.object.IrisDimensionCarvingResolver;
|
||||||
import art.arcane.iris.engine.object.IrisRegion;
|
import art.arcane.iris.engine.object.IrisRegion;
|
||||||
import art.arcane.iris.engine.object.IrisRange;
|
import art.arcane.iris.engine.object.IrisRange;
|
||||||
|
import art.arcane.iris.spi.PlatformBlockState;
|
||||||
|
import art.arcane.iris.util.common.data.B;
|
||||||
import art.arcane.iris.util.project.context.ChunkContext;
|
import art.arcane.iris.util.project.context.ChunkContext;
|
||||||
import art.arcane.iris.util.project.stream.ProceduralStream;
|
import art.arcane.iris.util.project.stream.ProceduralStream;
|
||||||
import art.arcane.iris.util.project.stream.utility.ChunkFillableDoubleStream2D;
|
import art.arcane.iris.util.project.stream.utility.ChunkFillableDoubleStream2D;
|
||||||
@@ -102,9 +104,20 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
|||||||
PrecisionStopwatch resolveStopwatch = PrecisionStopwatch.start();
|
PrecisionStopwatch resolveStopwatch = PrecisionStopwatch.start();
|
||||||
List<WeightedProfile> weightedProfiles = resolveWeightedProfiles(x, z, complex, resolverState);
|
List<WeightedProfile> weightedProfiles = resolveWeightedProfiles(x, z, complex, resolverState);
|
||||||
getEngineMantle().getEngine().getMetrics().getCarveResolve().put(resolveStopwatch.getMilliseconds());
|
getEngineMantle().getEngine().getMetrics().getCarveResolve().put(resolveStopwatch.getMilliseconds());
|
||||||
|
int fluidHeight = getDimension().getFluidHeight();
|
||||||
|
int[] surfaceFluidBoundaryStartY = blendScratch.surfaceFluidBoundaryStartY;
|
||||||
|
SurfaceFluidBoundaryPlan.fill(
|
||||||
|
chunkSurfaceHeights,
|
||||||
|
blendScratch.fieldSurfaceHeights,
|
||||||
|
blendScratch.fieldHasFluid,
|
||||||
|
FIELD_SIZE,
|
||||||
|
BLEND_RADIUS,
|
||||||
|
fluidHeight,
|
||||||
|
surfaceFluidBoundaryStartY
|
||||||
|
);
|
||||||
CaveFluidSupportPlan fluidSupportPlan = new CaveFluidSupportPlan();
|
CaveFluidSupportPlan fluidSupportPlan = new CaveFluidSupportPlan();
|
||||||
for (WeightedProfile weightedProfile : weightedProfiles) {
|
for (WeightedProfile weightedProfile : weightedProfiles) {
|
||||||
carveProfile(weightedProfile, writer, x, z, chunkSurfaceHeights, fluidSupportPlan);
|
carveProfile(weightedProfile, writer, x, z, chunkSurfaceHeights, surfaceFluidBoundaryStartY, fluidSupportPlan);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpperDimensionContext upperCtx = getEngineMantle().getEngine().getUpperContext();
|
UpperDimensionContext upperCtx = getEngineMantle().getEngine().getUpperContext();
|
||||||
@@ -118,7 +131,9 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
|||||||
writer.acquireChunk(x, z),
|
writer.acquireChunk(x, z),
|
||||||
chunkSurfaceHeights,
|
chunkSurfaceHeights,
|
||||||
maxSurfaceBreakDepth(weightedProfiles),
|
maxSurfaceBreakDepth(weightedProfiles),
|
||||||
writer.getMantle().getWorldHeight() - 1
|
writer.getMantle().getWorldHeight() - 1,
|
||||||
|
surfaceFluidBoundaryStartY,
|
||||||
|
fluidHeight
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,10 +148,11 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
|||||||
|
|
||||||
@ChunkCoordinates
|
@ChunkCoordinates
|
||||||
private void carveProfile(WeightedProfile weightedProfile, MantleWriter writer, int cx, int cz,
|
private void carveProfile(WeightedProfile weightedProfile, MantleWriter writer, int cx, int cz,
|
||||||
int[] chunkSurfaceHeights, CaveFluidSupportPlan fluidSupportPlan) {
|
int[] chunkSurfaceHeights, int[] surfaceFluidBoundaryStartY,
|
||||||
|
CaveFluidSupportPlan fluidSupportPlan) {
|
||||||
IrisCaveCarver3D carver = getCarver(weightedProfile.profile);
|
IrisCaveCarver3D carver = getCarver(weightedProfile.profile);
|
||||||
carver.carve(writer, cx, cz, weightedProfile.columnWeights, MIN_WEIGHT, THRESHOLD_PENALTY,
|
carver.carve(writer, cx, cz, weightedProfile.columnWeights, MIN_WEIGHT, THRESHOLD_PENALTY,
|
||||||
weightedProfile.worldYRange, chunkSurfaceHeights, null, fluidSupportPlan);
|
weightedProfile.worldYRange, chunkSurfaceHeights, surfaceFluidBoundaryStartY, null, fluidSupportPlan);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void carveUpperTerrain(UpperDimensionContext upperCtx, List<WeightedProfile> normalProfiles,
|
private void carveUpperTerrain(UpperDimensionContext upperCtx, List<WeightedProfile> normalProfiles,
|
||||||
@@ -189,7 +205,7 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
|||||||
}
|
}
|
||||||
IrisCaveCarver3D carver = getCarver(weightedProfile.profile);
|
IrisCaveCarver3D carver = getCarver(weightedProfile.profile);
|
||||||
carver.carve(writer, cx, cz, weightedProfile.columnWeights, MIN_WEIGHT, THRESHOLD_PENALTY,
|
carver.carve(writer, cx, cz, weightedProfile.columnWeights, MIN_WEIGHT, THRESHOLD_PENALTY,
|
||||||
constrainedRange, ceilingSurfaceHeights, fullVerticalRange, fluidSupportPlan);
|
constrainedRange, ceilingSurfaceHeights, null, fullVerticalRange, fluidSupportPlan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +475,7 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
|||||||
|
|
||||||
private void prefillProfileFieldSamples(int startX, int startZ, IrisComplex complex, BlendScratch blendScratch) {
|
private void prefillProfileFieldSamples(int startX, int startZ, IrisComplex complex, BlendScratch blendScratch) {
|
||||||
fillFieldHeights(complex.getHeightStream(), startX, startZ, blendScratch.fieldSurfaceHeights);
|
fillFieldHeights(complex.getHeightStream(), startX, startZ, blendScratch.fieldSurfaceHeights);
|
||||||
|
fillFieldFluidPresence(complex.getFluidStream(), startX, startZ, blendScratch.fieldHasFluid);
|
||||||
fillFieldObjects(complex.getRegionStream(), startX, startZ, blendScratch.fieldRegions);
|
fillFieldObjects(complex.getRegionStream(), startX, startZ, blendScratch.fieldRegions);
|
||||||
fillFieldObjects(complex.getTrueBiomeStream(), startX, startZ, blendScratch.fieldSurfaceBiomes);
|
fillFieldObjects(complex.getTrueBiomeStream(), startX, startZ, blendScratch.fieldSurfaceBiomes);
|
||||||
fillFieldObjects(complex.getCaveBiomeStream(), startX, startZ, blendScratch.fieldCaveBiomes);
|
fillFieldObjects(complex.getCaveBiomeStream(), startX, startZ, blendScratch.fieldCaveBiomes);
|
||||||
@@ -482,6 +499,15 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillFieldFluidPresence(ProceduralStream<PlatformBlockState> stream, int startX, int startZ, boolean[] target) {
|
||||||
|
for (int fieldX = 0; fieldX < FIELD_SIZE; fieldX++) {
|
||||||
|
int worldX = startX + fieldX;
|
||||||
|
for (int fieldZ = 0; fieldZ < FIELD_SIZE; fieldZ++) {
|
||||||
|
target[(fieldX * FIELD_SIZE) + fieldZ] = B.isFluid(stream.get(worldX, startZ + fieldZ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private IrisCaveCarver3D getCarver(IrisCaveProfile profile) {
|
private IrisCaveCarver3D getCarver(IrisCaveProfile profile) {
|
||||||
IrisCaveCarver3D carver = profileCarvers.get(profile);
|
IrisCaveCarver3D carver = profileCarvers.get(profile);
|
||||||
if (carver != null) {
|
if (carver != null) {
|
||||||
@@ -671,10 +697,12 @@ public class MantleCarvingComponent extends IrisMantleComponent {
|
|||||||
private final IdentityHashMap<IrisCaveProfile, Boolean> activeProfiles = new IdentityHashMap<>();
|
private final IdentityHashMap<IrisCaveProfile, Boolean> activeProfiles = new IdentityHashMap<>();
|
||||||
private final List<IrisCaveProfile> profileOrder = new ArrayList<>();
|
private final List<IrisCaveProfile> profileOrder = new ArrayList<>();
|
||||||
private final double[] fieldSurfaceHeights = new double[FIELD_SIZE * FIELD_SIZE];
|
private final double[] fieldSurfaceHeights = new double[FIELD_SIZE * FIELD_SIZE];
|
||||||
|
private final boolean[] fieldHasFluid = new boolean[FIELD_SIZE * FIELD_SIZE];
|
||||||
private final IrisRegion[] fieldRegions = new IrisRegion[FIELD_SIZE * FIELD_SIZE];
|
private final IrisRegion[] fieldRegions = new IrisRegion[FIELD_SIZE * FIELD_SIZE];
|
||||||
private final IrisBiome[] fieldSurfaceBiomes = new IrisBiome[FIELD_SIZE * FIELD_SIZE];
|
private final IrisBiome[] fieldSurfaceBiomes = new IrisBiome[FIELD_SIZE * FIELD_SIZE];
|
||||||
private final IrisBiome[] fieldCaveBiomes = new IrisBiome[FIELD_SIZE * FIELD_SIZE];
|
private final IrisBiome[] fieldCaveBiomes = new IrisBiome[FIELD_SIZE * FIELD_SIZE];
|
||||||
private final int[] chunkSurfaceHeights = new int[CHUNK_AREA];
|
private final int[] chunkSurfaceHeights = new int[CHUNK_AREA];
|
||||||
|
private final int[] surfaceFluidBoundaryStartY = new int[CHUNK_AREA];
|
||||||
private final double[] chunkSurfaceHeightSamples = new double[CHUNK_AREA];
|
private final double[] chunkSurfaceHeightSamples = new double[CHUNK_AREA];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-8
@@ -57,6 +57,7 @@ import art.arcane.volmlib.util.documentation.BlockCoordinates;
|
|||||||
import art.arcane.volmlib.util.documentation.ChunkCoordinates;
|
import art.arcane.volmlib.util.documentation.ChunkCoordinates;
|
||||||
import art.arcane.volmlib.util.mantle.flag.ReservedFlag;
|
import art.arcane.volmlib.util.mantle.flag.ReservedFlag;
|
||||||
import art.arcane.volmlib.util.math.RNG;
|
import art.arcane.volmlib.util.math.RNG;
|
||||||
|
import art.arcane.volmlib.util.matter.MatterCavern;
|
||||||
import art.arcane.volmlib.util.matter.MatterStructurePOI;
|
import art.arcane.volmlib.util.matter.MatterStructurePOI;
|
||||||
import art.arcane.iris.util.project.noise.CNG;
|
import art.arcane.iris.util.project.noise.CNG;
|
||||||
import art.arcane.iris.util.project.noise.NoiseType;
|
import art.arcane.iris.util.project.noise.NoiseType;
|
||||||
@@ -77,6 +78,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||||||
public class MantleObjectComponent extends IrisMantleComponent {
|
public class MantleObjectComponent extends IrisMantleComponent {
|
||||||
private static final long CAVE_REJECT_LOG_THROTTLE_MS = 5000L;
|
private static final long CAVE_REJECT_LOG_THROTTLE_MS = 5000L;
|
||||||
private static final int BEDROCK_CLEARANCE = 6;
|
private static final int BEDROCK_CLEARANCE = 6;
|
||||||
|
private static final byte LIQUID_FORCED_AIR = 3;
|
||||||
private static final Map<String, CaveRejectLogState> CAVE_REJECT_LOG_STATE = new ConcurrentHashMap<>();
|
private static final Map<String, CaveRejectLogState> CAVE_REJECT_LOG_STATE = new ConcurrentHashMap<>();
|
||||||
private static final Set<String> MISSING_LOAD_KEY_WARNED = ConcurrentHashMap.newKeySet();
|
private static final Set<String> MISSING_LOAD_KEY_WARNED = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
@@ -384,11 +386,11 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
private void placeProceduralObjects(MantleWriter writer, RNG rng, int x, int z, IrisBiome surfaceBiome, IrisBiome caveBiome, IrisRegion region) {
|
private void placeProceduralObjects(MantleWriter writer, RNG rng, int x, int z, IrisBiome surfaceBiome, IrisBiome caveBiome, IrisRegion region) {
|
||||||
IrisCaveProfile surfaceCaveProfile = resolveCaveProfile(surfaceBiome.getCaveProfile(), region.getCaveProfile());
|
IrisCaveProfile surfaceCaveProfile = resolveCaveProfile(surfaceBiome.getCaveProfile(), region.getCaveProfile());
|
||||||
IrisCaveProfile regionCaveProfile = resolveCaveProfile(region.getCaveProfile(), caveBiome == null ? null : caveBiome.getCaveProfile());
|
IrisCaveProfile regionCaveProfile = resolveCaveProfile(region.getCaveProfile(), caveBiome == null ? null : caveBiome.getCaveProfile());
|
||||||
placeProceduralFrom(writer, rng, x, z, surfaceBiome.getProceduralObjects(), surfaceBiome.getName(), surfaceCaveProfile);
|
placeProceduralFrom(writer, rng, x, z, surfaceBiome.getProceduralObjects(), surfaceBiome.getName(), surfaceCaveProfile, surfaceBiome.getLoadKey());
|
||||||
placeProceduralFrom(writer, rng, x, z, region.getProceduralObjects(), region.getName(), regionCaveProfile);
|
placeProceduralFrom(writer, rng, x, z, region.getProceduralObjects(), region.getName(), regionCaveProfile, null);
|
||||||
if (caveBiome != null && caveBiome != surfaceBiome) {
|
if (caveBiome != null && caveBiome != surfaceBiome) {
|
||||||
IrisCaveProfile caveProfile = resolveCaveProfile(caveBiome.getCaveProfile(), region.getCaveProfile());
|
IrisCaveProfile caveProfile = resolveCaveProfile(caveBiome.getCaveProfile(), region.getCaveProfile());
|
||||||
placeProceduralFrom(writer, rng, x, z, caveBiome.getProceduralObjects(), caveBiome.getName(), caveProfile);
|
placeProceduralFrom(writer, rng, x, z, caveBiome.getProceduralObjects(), caveBiome.getName(), caveProfile, caveBiome.getLoadKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,7 +402,8 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
int z,
|
int z,
|
||||||
IrisProceduralObjects proceduralObjects,
|
IrisProceduralObjects proceduralObjects,
|
||||||
String scope,
|
String scope,
|
||||||
IrisCaveProfile caveProfile
|
IrisCaveProfile caveProfile,
|
||||||
|
String expectedCaveBiomeKey
|
||||||
) {
|
) {
|
||||||
if (proceduralObjects == null || proceduralObjects.isEmpty()) {
|
if (proceduralObjects == null || proceduralObjects.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -457,7 +460,8 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
anchorScanStep,
|
anchorScanStep,
|
||||||
minDepthBelowSurface,
|
minDepthBelowSurface,
|
||||||
anchorSearchAttempts,
|
anchorSearchAttempts,
|
||||||
null,
|
expectedCaveBiomeKey,
|
||||||
|
placement.isUnderwater(),
|
||||||
caveAnchorCache
|
caveAnchorCache
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -561,6 +565,7 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
int minDepthBelowSurface,
|
int minDepthBelowSurface,
|
||||||
int searchAttempts,
|
int searchAttempts,
|
||||||
String expectedCaveBiomeKey,
|
String expectedCaveBiomeKey,
|
||||||
|
boolean underwater,
|
||||||
CaveAnchorCache anchorCache
|
CaveAnchorCache anchorCache
|
||||||
) {
|
) {
|
||||||
for (int search = 0; search < searchAttempts; search++) {
|
for (int search = 0; search < searchAttempts; search++) {
|
||||||
@@ -576,7 +581,13 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
minDepthBelowSurface,
|
minDepthBelowSurface,
|
||||||
anchorCache
|
anchorCache
|
||||||
);
|
);
|
||||||
if (candidateY < 0 || caveAnchorBiomeConflicts(candidateX, candidateY, candidateZ, expectedCaveBiomeKey)) {
|
if (candidateY < 0
|
||||||
|
|| caveAnchorBiomeConflicts(candidateX, candidateY, candidateZ, expectedCaveBiomeKey)
|
||||||
|
|| !acceptsCaveAnchorFluid(
|
||||||
|
underwater,
|
||||||
|
writer.getDataIfPresent(candidateX, candidateY, candidateZ, MatterCavern.class),
|
||||||
|
candidateY,
|
||||||
|
getDimension().getCaveLavaHeight())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return new CavePlacementAnchor(candidateX, candidateY, candidateZ);
|
return new CavePlacementAnchor(candidateX, candidateY, candidateZ);
|
||||||
@@ -584,6 +595,16 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean acceptsCaveAnchorFluid(boolean underwater, MatterCavern cavern, int y, int lavaHeight) {
|
||||||
|
if (cavern == null || !cavern.isCavern()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (underwater || cavern.getLiquid() == LIQUID_FORCED_AIR) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return cavern.isAir() && y > lavaHeight;
|
||||||
|
}
|
||||||
|
|
||||||
private ContainedPlacementResult placeContainedCaveObject(
|
private ContainedPlacementResult placeContainedCaveObject(
|
||||||
IObjectPlacer placer,
|
IObjectPlacer placer,
|
||||||
IrisObject object,
|
IrisObject object,
|
||||||
@@ -732,14 +753,18 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
}
|
}
|
||||||
Engine engine = getEngineMantle().getEngine();
|
Engine engine = getEngineMantle().getEngine();
|
||||||
IrisBiome at = engine.getCaveBiome(x, y, z);
|
IrisBiome at = engine.getCaveBiome(x, y, z);
|
||||||
if (at == null) {
|
IrisBiome surface = engine.getSurfaceBiome(x, z);
|
||||||
|
return caveAnchorBiomeConflicts(at, surface, expectedCaveBiomeKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean caveAnchorBiomeConflicts(IrisBiome at, IrisBiome surface, String expectedCaveBiomeKey) {
|
||||||
|
if (expectedCaveBiomeKey == null || at == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String atKey = at.getLoadKey();
|
String atKey = at.getLoadKey();
|
||||||
if (atKey == null || atKey.equals(expectedCaveBiomeKey)) {
|
if (atKey == null || atKey.equals(expectedCaveBiomeKey)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
IrisBiome surface = engine.getSurfaceBiome(x, z);
|
|
||||||
if (surface != null && atKey.equals(surface.getLoadKey())) {
|
if (surface != null && atKey.equals(surface.getLoadKey())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -818,6 +843,7 @@ public class MantleObjectComponent extends IrisMantleComponent {
|
|||||||
objectMinDepthBelowSurface,
|
objectMinDepthBelowSurface,
|
||||||
anchorSearchAttempts,
|
anchorSearchAttempts,
|
||||||
expectedCaveBiomeKey,
|
expectedCaveBiomeKey,
|
||||||
|
objectPlacement.isUnderwater(),
|
||||||
anchorCache
|
anchorCache
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package art.arcane.iris.engine.mantle.components;
|
||||||
|
|
||||||
|
import art.arcane.volmlib.util.math.PowerOfTwoCoordinates;
|
||||||
|
|
||||||
|
final class SurfaceFluidBoundaryPlan {
|
||||||
|
static final int NO_BOUNDARY = Integer.MAX_VALUE;
|
||||||
|
private static final int CHUNK_SIZE = 16;
|
||||||
|
private static final int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
|
||||||
|
|
||||||
|
private SurfaceFluidBoundaryPlan() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill(
|
||||||
|
int[] chunkSurfaceHeights,
|
||||||
|
double[] fieldSurfaceHeights,
|
||||||
|
boolean[] fieldHasFluid,
|
||||||
|
int fieldSize,
|
||||||
|
int padding,
|
||||||
|
int fluidHeight,
|
||||||
|
int[] boundaryStartY
|
||||||
|
) {
|
||||||
|
if (chunkSurfaceHeights == null || chunkSurfaceHeights.length < CHUNK_AREA
|
||||||
|
|| boundaryStartY == null || boundaryStartY.length < CHUNK_AREA
|
||||||
|
|| padding < 1 || fieldSize < CHUNK_SIZE + (padding * 2)
|
||||||
|
|| fieldSurfaceHeights == null || fieldSurfaceHeights.length < fieldSize * fieldSize
|
||||||
|
|| fieldHasFluid == null || fieldHasFluid.length < fieldSize * fieldSize) {
|
||||||
|
throw new IllegalArgumentException("Surface fluid boundary fields do not cover a padded chunk");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int localX = 0; localX < CHUNK_SIZE; localX++) {
|
||||||
|
int fieldX = localX + padding;
|
||||||
|
for (int localZ = 0; localZ < CHUNK_SIZE; localZ++) {
|
||||||
|
int fieldZ = localZ + padding;
|
||||||
|
int columnIndex = PowerOfTwoCoordinates.packLocal16(localX, localZ);
|
||||||
|
int boundaryY = NO_BOUNDARY;
|
||||||
|
int surfaceY = chunkSurfaceHeights[columnIndex];
|
||||||
|
int fieldIndex = (fieldX * fieldSize) + fieldZ;
|
||||||
|
if (fieldHasFluid[fieldIndex] && surfaceY < fluidHeight) {
|
||||||
|
boundaryY = surfaceY;
|
||||||
|
}
|
||||||
|
|
||||||
|
boundaryY = lowerBoundary(boundaryY, fieldSurfaceHeights, fieldHasFluid,
|
||||||
|
((fieldX - 1) * fieldSize) + fieldZ, fluidHeight);
|
||||||
|
boundaryY = lowerBoundary(boundaryY, fieldSurfaceHeights, fieldHasFluid,
|
||||||
|
((fieldX + 1) * fieldSize) + fieldZ, fluidHeight);
|
||||||
|
boundaryY = lowerBoundary(boundaryY, fieldSurfaceHeights, fieldHasFluid,
|
||||||
|
(fieldX * fieldSize) + fieldZ - 1, fluidHeight);
|
||||||
|
boundaryY = lowerBoundary(boundaryY, fieldSurfaceHeights, fieldHasFluid,
|
||||||
|
(fieldX * fieldSize) + fieldZ + 1, fluidHeight);
|
||||||
|
boundaryStartY[columnIndex] = boundaryY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean protects(int[] boundaryStartY, int columnIndex, int y, int fluidHeight) {
|
||||||
|
return boundaryStartY != null
|
||||||
|
&& columnIndex >= 0
|
||||||
|
&& columnIndex < boundaryStartY.length
|
||||||
|
&& y >= boundaryStartY[columnIndex]
|
||||||
|
&& y <= fluidHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int lowerBoundary(
|
||||||
|
int currentBoundaryY,
|
||||||
|
double[] fieldSurfaceHeights,
|
||||||
|
boolean[] fieldHasFluid,
|
||||||
|
int fieldIndex,
|
||||||
|
int fluidHeight
|
||||||
|
) {
|
||||||
|
int neighborSurfaceY = (int) Math.round(fieldSurfaceHeights[fieldIndex]);
|
||||||
|
if (!fieldHasFluid[fieldIndex] || neighborSurfaceY >= fluidHeight) {
|
||||||
|
return currentBoundaryY;
|
||||||
|
}
|
||||||
|
return Math.min(currentBoundaryY, neighborSurfaceY + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,6 @@ import art.arcane.iris.spi.PlatformBlockState;
|
|||||||
public class IrisPostModifier extends EngineAssignedModifier<PlatformBlockState> {
|
public class IrisPostModifier extends EngineAssignedModifier<PlatformBlockState> {
|
||||||
private static final class States {
|
private static final class States {
|
||||||
private static final PlatformBlockState AIR = B.getState("AIR");
|
private static final PlatformBlockState AIR = B.getState("AIR");
|
||||||
private static final PlatformBlockState WATER = B.getState("WATER");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final RNG rng;
|
private final RNG rng;
|
||||||
@@ -245,10 +244,6 @@ public class IrisPostModifier extends EngineAssignedModifier<PlatformBlockState>
|
|||||||
if (w != "true".equals(IrisProceduralBlocks.propertyValue(b, "waterlogged"))) {
|
if (w != "true".equals(IrisProceduralBlocks.propertyValue(b, "waterlogged"))) {
|
||||||
setPostBlock(x, h, z, b.withProperty("waterlogged", String.valueOf(w)), originX, originZ, currentData);
|
setPostBlock(x, h, z, b.withProperty("waterlogged", String.valueOf(w)), originX, originZ, currentData);
|
||||||
}
|
}
|
||||||
} else if (IrisProceduralBlocks.materialKey(b).equals("minecraft:air") && h <= fluidHeight) {
|
|
||||||
if ((isWaterOrWaterlogged(x + 1, h, z, originX, originZ, currentData) || isWaterOrWaterlogged(x - 1, h, z, originX, originZ, currentData) || isWaterOrWaterlogged(x, h, z + 1, originX, originZ, currentData) || isWaterOrWaterlogged(x, h, z - 1, originX, originZ, currentData))) {
|
|
||||||
setPostBlock(x, h, z, States.WATER, originX, originZ, currentData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Foliage
|
// Foliage
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
package art.arcane.iris.engine.object;
|
package art.arcane.iris.engine.object;
|
||||||
|
|
||||||
|
import art.arcane.iris.engine.object.annotations.Desc;
|
||||||
|
|
||||||
|
@Desc("Selects which biome identity is checked by a deposit's include and exclude filters.")
|
||||||
public enum IrisDepositBiomeScope {
|
public enum IrisDepositBiomeScope {
|
||||||
|
@Desc("Checks the surface biome selected for the deposit column.")
|
||||||
SURFACE,
|
SURFACE,
|
||||||
|
@Desc("Checks the cave biome selected at the deposit origin.")
|
||||||
CAVE
|
CAVE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
package art.arcane.iris.engine.object;
|
package art.arcane.iris.engine.object;
|
||||||
|
|
||||||
|
import art.arcane.iris.engine.object.annotations.Desc;
|
||||||
|
|
||||||
|
@Desc("Controls how a deposit chooses its origin height within the configured vertical band.")
|
||||||
public enum IrisDepositHeightDistribution {
|
public enum IrisDepositHeightDistribution {
|
||||||
|
@Desc("Samples uniformly after clipping the configured band to the terrain and build-height bounds.")
|
||||||
CLIPPED_UNIFORM,
|
CLIPPED_UNIFORM,
|
||||||
|
@Desc("Samples uniformly from the configured band, then rejects origins outside the terrain or build-height bounds.")
|
||||||
UNIFORM,
|
UNIFORM,
|
||||||
|
@Desc("Samples toward the middle of the configured band with a triangular distribution, then rejects invalid origins.")
|
||||||
TRIANGLE
|
TRIANGLE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
package art.arcane.iris.engine.object;
|
package art.arcane.iris.engine.object;
|
||||||
|
|
||||||
|
import art.arcane.iris.engine.object.annotations.Desc;
|
||||||
|
|
||||||
|
@Desc("Controls which vertical part of the world may contain a deposit origin.")
|
||||||
public enum IrisDepositPlacementScope {
|
public enum IrisDepositPlacementScope {
|
||||||
|
@Desc("Places in solid terrain below the generated surface while preserving the configured surface clearance.")
|
||||||
TERRAIN,
|
TERRAIN,
|
||||||
|
@Desc("Places only in existing solid hosts above the generated terrain surface.")
|
||||||
ABOVE_TERRAIN,
|
ABOVE_TERRAIN,
|
||||||
|
@Desc("Places in existing solid hosts anywhere within the dimension build height.")
|
||||||
FULL_HEIGHT
|
FULL_HEIGHT
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
package art.arcane.iris.engine.object;
|
package art.arcane.iris.engine.object;
|
||||||
|
|
||||||
|
import art.arcane.iris.engine.object.annotations.Desc;
|
||||||
|
|
||||||
|
@Desc("Selects the geometry used to build each deposit clump.")
|
||||||
public enum IrisDepositShape {
|
public enum IrisDepositShape {
|
||||||
|
@Desc("Builds the traditional Iris fixed-block-count cube clump.")
|
||||||
IRIS,
|
IRIS,
|
||||||
|
@Desc("Builds a chain of overlapping ellipsoids matching Minecraft's ordinary ore-vein geometry.")
|
||||||
VANILLA_ELLIPSOID,
|
VANILLA_ELLIPSOID,
|
||||||
|
@Desc("Builds sparse candidate offsets matching Minecraft's scattered-ore geometry.")
|
||||||
VANILLA_SCATTERED
|
VANILLA_SCATTERED
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,6 +125,19 @@ public class CarveOrphanSweepTest {
|
|||||||
assertTrue(fixture.wasMarked(6, 30, 6));
|
assertTrue(fixture.wasMarked(6, 30, 6));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void protectedSurfaceFluidSupportIsNotMarkedCarved() {
|
||||||
|
Fixture fixture = new Fixture();
|
||||||
|
fixture.carveBox(1, 14, 25, 35, 1, 14);
|
||||||
|
fixture.uncarve(7, 30, 7);
|
||||||
|
fixture.protect(7, 30, 7);
|
||||||
|
|
||||||
|
int marked = fixture.sweep();
|
||||||
|
|
||||||
|
assertEquals(0, marked);
|
||||||
|
assertFalse(fixture.wasMarked(7, 30, 7));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sweepIsDeterministicAndIdempotent() {
|
public void sweepIsDeterministicAndIdempotent() {
|
||||||
Fixture first = new Fixture();
|
Fixture first = new Fixture();
|
||||||
@@ -166,6 +179,7 @@ public class CarveOrphanSweepTest {
|
|||||||
private final boolean[] carved = new boolean[16 * WORLD_HEIGHT * 16];
|
private final boolean[] carved = new boolean[16 * WORLD_HEIGHT * 16];
|
||||||
private final int[] surfaceHeights = new int[256];
|
private final int[] surfaceHeights = new int[256];
|
||||||
private final List<Integer> marks = new ArrayList<>();
|
private final List<Integer> marks = new ArrayList<>();
|
||||||
|
private int protectedCell = -1;
|
||||||
|
|
||||||
private Fixture() {
|
private Fixture() {
|
||||||
Arrays.fill(surfaceHeights, SURFACE_Y);
|
Arrays.fill(surfaceHeights, SURFACE_Y);
|
||||||
@@ -193,6 +207,10 @@ public class CarveOrphanSweepTest {
|
|||||||
return marks.contains(index(localX, y, localZ));
|
return marks.contains(index(localX, y, localZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void protect(int localX, int y, int localZ) {
|
||||||
|
protectedCell = index(localX, y, localZ);
|
||||||
|
}
|
||||||
|
|
||||||
private List<Integer> marks() {
|
private List<Integer> marks() {
|
||||||
return marks;
|
return marks;
|
||||||
}
|
}
|
||||||
@@ -215,5 +233,10 @@ public class CarveOrphanSweepTest {
|
|||||||
carved[index(localX, y, localZ)] = true;
|
carved[index(localX, y, localZ)] = true;
|
||||||
marks.add(index(localX, y, localZ));
|
marks.add(index(localX, y, localZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isProtected(int localX, int y, int localZ) {
|
||||||
|
return protectedCell == index(localX, y, localZ);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+47
-3
@@ -286,6 +286,13 @@ public class IrisCaveCarver3DNearParityTest {
|
|||||||
assertTrue(containsLiquidInRange(capture.carvedLiquids, 65, 70, (byte) 0));
|
assertTrue(containsLiquidInRange(capture.carvedLiquids, 65, 70, (byte) 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void surfaceFluidBoundaryProtectsReservoirWithoutFloodingDeeperCaves() {
|
||||||
|
assertSurfaceFluidBoundaryForProfile(createFluidProfile().setAdaptiveSampling(false).setSampleStep(1));
|
||||||
|
assertSurfaceFluidBoundaryForProfile(createFluidProfile().setAdaptiveSampling(true).setSampleStep(1));
|
||||||
|
assertSurfaceFluidBoundaryForProfile(createFluidProfile().setAdaptiveSampling(false).setSampleStep(4));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void floorRequiredFluidResolvesAfterTheCompleteCarveMask() {
|
public void floorRequiredFluidResolvesAfterTheCompleteCarveMask() {
|
||||||
Engine engine = createEngine(80, 70);
|
Engine engine = createEngine(80, 70);
|
||||||
@@ -301,7 +308,7 @@ public class IrisCaveCarver3DNearParityTest {
|
|||||||
WriterCapture firstCapture = createWriterCapture(80);
|
WriterCapture firstCapture = createWriterCapture(80);
|
||||||
CaveFluidSupportPlan supportPlan = new CaveFluidSupportPlan();
|
CaveFluidSupportPlan supportPlan = new CaveFluidSupportPlan();
|
||||||
new IrisCaveCarver3D(engine, supportedProfile).carve(
|
new IrisCaveCarver3D(engine, supportedProfile).carve(
|
||||||
firstCapture.writer, chunkX, chunkZ, fullWeights(), 0D, 0D, null, surfaceHeights, null, supportPlan);
|
firstCapture.writer, chunkX, chunkZ, fullWeights(), 0D, 0D, null, surfaceHeights, null, null, supportPlan);
|
||||||
int candidateCount = countLiquid(firstCapture, (byte) 1);
|
int candidateCount = countLiquid(firstCapture, (byte) 1);
|
||||||
supportPlan.resolve(firstCapture.writer.acquireChunk(chunkX, chunkZ));
|
supportPlan.resolve(firstCapture.writer.acquireChunk(chunkX, chunkZ));
|
||||||
|
|
||||||
@@ -362,13 +369,13 @@ public class IrisCaveCarver3DNearParityTest {
|
|||||||
|
|
||||||
new IrisCaveCarver3D(engine, fluidProfile).carve(
|
new IrisCaveCarver3D(engine, fluidProfile).carve(
|
||||||
capture.writer, 0, 0, fullWeights(), 0D, 0D, null, surfaceHeights,
|
capture.writer, 0, 0, fullWeights(), 0D, 0D, null, surfaceHeights,
|
||||||
new IrisRange(20D, 64D), fluidSupportPlan);
|
null, new IrisRange(20D, 64D), fluidSupportPlan);
|
||||||
String fluidCell = firstCellWithLiquid(capture, (byte) 1);
|
String fluidCell = firstCellWithLiquid(capture, (byte) 1);
|
||||||
assertTrue(fluidCell != null);
|
assertTrue(fluidCell != null);
|
||||||
int fluidY = coordinate(fluidCell, 1);
|
int fluidY = coordinate(fluidCell, 1);
|
||||||
new IrisCaveCarver3D(engine, airProfile).carve(
|
new IrisCaveCarver3D(engine, airProfile).carve(
|
||||||
capture.writer, 0, 0, fullWeights(), 0D, 0D, null, surfaceHeights,
|
capture.writer, 0, 0, fullWeights(), 0D, 0D, null, surfaceHeights,
|
||||||
new IrisRange(fluidY - 1D, fluidY - 1D), fluidSupportPlan);
|
null, new IrisRange(fluidY - 1D, fluidY - 1D), fluidSupportPlan);
|
||||||
|
|
||||||
assertEquals(Byte.valueOf((byte) 1), capture.carvedLiquids.get(fluidCell));
|
assertEquals(Byte.valueOf((byte) 1), capture.carvedLiquids.get(fluidCell));
|
||||||
fluidSupportPlan.resolve(capture.writer.acquireChunk(0, 0));
|
fluidSupportPlan.resolve(capture.writer.acquireChunk(0, 0));
|
||||||
@@ -732,6 +739,43 @@ public class IrisCaveCarver3DNearParityTest {
|
|||||||
.setAllowLava(true);
|
.setAllowLava(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertSurfaceFluidBoundaryForProfile(IrisCaveProfile profile) {
|
||||||
|
Engine engine = createEngine(80, 70);
|
||||||
|
int[] surfaceHeights = filledHeights(70);
|
||||||
|
surfaceHeights[0] = 60;
|
||||||
|
int[] boundaryStartY = new int[256];
|
||||||
|
Arrays.fill(boundaryStartY, SurfaceFluidBoundaryPlan.NO_BOUNDARY);
|
||||||
|
boundaryStartY[0] = 60;
|
||||||
|
boundaryStartY[16] = 61;
|
||||||
|
WriterCapture capture = createWriterCapture(80);
|
||||||
|
CaveFluidSupportPlan supportPlan = new CaveFluidSupportPlan();
|
||||||
|
|
||||||
|
new IrisCaveCarver3D(engine, profile.setFluidMinDepthBelowSurface(0).setFluidRequiresFloor(false)).carve(
|
||||||
|
capture.writer,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
fullWeights(),
|
||||||
|
0D,
|
||||||
|
0D,
|
||||||
|
null,
|
||||||
|
surfaceHeights,
|
||||||
|
boundaryStartY,
|
||||||
|
null,
|
||||||
|
supportPlan
|
||||||
|
);
|
||||||
|
|
||||||
|
assertTrue(capture.carvedCells.contains(cellKey(0, 56, 0)));
|
||||||
|
assertFalse(capture.carvedCells.contains(cellKey(0, 60, 0)));
|
||||||
|
assertTrue(capture.carvedCells.contains(cellKey(1, 60, 0)));
|
||||||
|
for (int y = 61; y <= 64; y++) {
|
||||||
|
assertFalse(capture.carvedCells.contains(cellKey(1, y, 0)));
|
||||||
|
}
|
||||||
|
assertTrue(capture.carvedCells.contains(cellKey(1, 65, 0)));
|
||||||
|
assertTrue(capture.carvedCells.contains(cellKey(2, 64, 0)));
|
||||||
|
assertTrue(countLiquid(capture, (byte) 1) > 0);
|
||||||
|
assertTrue(countLiquid(capture, (byte) 0) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
private WriterCapture createWriterCapture(int worldHeight) {
|
private WriterCapture createWriterCapture(int worldHeight) {
|
||||||
MantleWriter writer = mock(MantleWriter.class);
|
MantleWriter writer = mock(MantleWriter.class);
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package art.arcane.iris.engine.mantle.components;
|
||||||
|
|
||||||
|
import art.arcane.iris.engine.object.IrisBiome;
|
||||||
|
import art.arcane.volmlib.util.matter.MatterCavern;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class MantleObjectComponentCaveAnchorTest {
|
||||||
|
@Test
|
||||||
|
public void biomeOwnedPlacementsRejectForeignCaveBands() {
|
||||||
|
IrisBiome frozen = biome("carving/ice");
|
||||||
|
IrisBiome deepDark = biome("carving/standard-deepdark");
|
||||||
|
IrisBiome surface = biome("frozen/ice-spikes");
|
||||||
|
|
||||||
|
assertFalse(MantleObjectComponent.caveAnchorBiomeConflicts(frozen, surface, "carving/ice"));
|
||||||
|
assertTrue(MantleObjectComponent.caveAnchorBiomeConflicts(deepDark, surface, "carving/ice"));
|
||||||
|
assertFalse(MantleObjectComponent.caveAnchorBiomeConflicts(deepDark, surface, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dryPlacementsRejectFluidAndDefaultLavaCells() {
|
||||||
|
MatterCavern air = new MatterCavern(true, "", (byte) 0);
|
||||||
|
MatterCavern water = new MatterCavern(true, "", (byte) 1);
|
||||||
|
MatterCavern lava = new MatterCavern(true, "", (byte) 2);
|
||||||
|
|
||||||
|
assertFalse(MantleObjectComponent.acceptsCaveAnchorFluid(false, water, 20, 8));
|
||||||
|
assertFalse(MantleObjectComponent.acceptsCaveAnchorFluid(false, lava, 20, 8));
|
||||||
|
assertFalse(MantleObjectComponent.acceptsCaveAnchorFluid(false, air, 8, 8));
|
||||||
|
assertTrue(MantleObjectComponent.acceptsCaveAnchorFluid(false, air, 9, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void explicitWetAndForcedAirPlacementsRemainEligible() {
|
||||||
|
MatterCavern water = new MatterCavern(true, "", (byte) 1);
|
||||||
|
MatterCavern forcedAir = new MatterCavern(true, "", (byte) 3);
|
||||||
|
|
||||||
|
assertTrue(MantleObjectComponent.acceptsCaveAnchorFluid(true, water, 20, 8));
|
||||||
|
assertTrue(MantleObjectComponent.acceptsCaveAnchorFluid(false, forcedAir, 0, 8));
|
||||||
|
assertFalse(MantleObjectComponent.acceptsCaveAnchorFluid(
|
||||||
|
true,
|
||||||
|
new MatterCavern(false, "", (byte) 0),
|
||||||
|
20,
|
||||||
|
8
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IrisBiome biome(String loadKey) {
|
||||||
|
IrisBiome biome = new IrisBiome();
|
||||||
|
biome.setLoadKey(loadKey);
|
||||||
|
return biome;
|
||||||
|
}
|
||||||
|
}
|
||||||
+160
@@ -0,0 +1,160 @@
|
|||||||
|
package art.arcane.iris.engine.mantle.components;
|
||||||
|
|
||||||
|
import art.arcane.volmlib.util.math.PowerOfTwoCoordinates;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class SurfaceFluidBoundaryPlanTest {
|
||||||
|
private static final int CHUNK_SIZE = 16;
|
||||||
|
private static final int FIELD_SIZE = 22;
|
||||||
|
private static final int PADDING = 3;
|
||||||
|
private static final int FLUID_HEIGHT = 64;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void submergedColumnProtectsItsSeabedWithoutBlockingTheCaveBelow() {
|
||||||
|
Fixture fixture = new Fixture();
|
||||||
|
fixture.setChunkSurface(8, 8, 60);
|
||||||
|
|
||||||
|
fixture.resolve();
|
||||||
|
|
||||||
|
int boundaryY = fixture.boundary(8, 8);
|
||||||
|
assertEquals(60, boundaryY);
|
||||||
|
assertFalse(SurfaceFluidBoundaryPlan.protects(fixture.boundaryStartY, fixture.index(8, 8), 59, FLUID_HEIGHT));
|
||||||
|
assertTrue(SurfaceFluidBoundaryPlan.protects(fixture.boundaryStartY, fixture.index(8, 8), 60, FLUID_HEIGHT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dryCoastProtectsOnlyTheAdjacentFluidBand() {
|
||||||
|
Fixture fixture = new Fixture();
|
||||||
|
fixture.setFieldSurface(7, 8, 60D);
|
||||||
|
|
||||||
|
fixture.resolve();
|
||||||
|
|
||||||
|
int columnIndex = fixture.index(8, 8);
|
||||||
|
assertEquals(61, fixture.boundary(8, 8));
|
||||||
|
assertFalse(SurfaceFluidBoundaryPlan.protects(fixture.boundaryStartY, columnIndex, 60, FLUID_HEIGHT));
|
||||||
|
assertTrue(SurfaceFluidBoundaryPlan.protects(fixture.boundaryStartY, columnIndex, 61, FLUID_HEIGHT));
|
||||||
|
assertTrue(SurfaceFluidBoundaryPlan.protects(fixture.boundaryStartY, columnIndex, 64, FLUID_HEIGHT));
|
||||||
|
assertFalse(SurfaceFluidBoundaryPlan.protects(fixture.boundaryStartY, columnIndex, 65, FLUID_HEIGHT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void lowestCardinalReservoirBoundaryWins() {
|
||||||
|
Fixture fixture = new Fixture();
|
||||||
|
fixture.setFieldSurface(7, 8, 62D);
|
||||||
|
fixture.setFieldSurface(9, 8, 58D);
|
||||||
|
|
||||||
|
fixture.resolve();
|
||||||
|
|
||||||
|
assertEquals(59, fixture.boundary(8, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void roundedWaterlineAndDiagonalReservoirDoNotOverprotect() {
|
||||||
|
Fixture wetRoundedDown = new Fixture();
|
||||||
|
wetRoundedDown.setFieldSurface(7, 8, 63.49D);
|
||||||
|
wetRoundedDown.resolve();
|
||||||
|
assertEquals(64, wetRoundedDown.boundary(8, 8));
|
||||||
|
|
||||||
|
Fixture dryRoundedUp = new Fixture();
|
||||||
|
dryRoundedUp.setFieldSurface(7, 8, 63.5D);
|
||||||
|
dryRoundedUp.setFieldSurface(7, 7, 40D);
|
||||||
|
dryRoundedUp.resolve();
|
||||||
|
assertEquals(SurfaceFluidBoundaryPlan.NO_BOUNDARY, dryRoundedUp.boundary(8, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nonFluidPaletteDoesNotCreateAReservoirBoundary() {
|
||||||
|
Fixture fixture = new Fixture();
|
||||||
|
fixture.setFieldSurface(7, 8, 40D);
|
||||||
|
fixture.setFieldHasFluid(7, 8, false);
|
||||||
|
|
||||||
|
fixture.resolve();
|
||||||
|
|
||||||
|
assertEquals(SurfaceFluidBoundaryPlan.NO_BOUNDARY, fixture.boundary(8, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void paddedHaloProtectsEveryChunkEdge() {
|
||||||
|
assertEdgeBoundary(0, 8, -1, 8);
|
||||||
|
assertEdgeBoundary(15, 8, 16, 8);
|
||||||
|
assertEdgeBoundary(8, 0, 8, -1);
|
||||||
|
assertEdgeBoundary(8, 15, 8, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invalidFieldShapeIsRejected() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> SurfaceFluidBoundaryPlan.fill(
|
||||||
|
new int[CHUNK_SIZE * CHUNK_SIZE],
|
||||||
|
new double[FIELD_SIZE * FIELD_SIZE],
|
||||||
|
new boolean[FIELD_SIZE * FIELD_SIZE],
|
||||||
|
FIELD_SIZE,
|
||||||
|
0,
|
||||||
|
FLUID_HEIGHT,
|
||||||
|
new int[CHUNK_SIZE * CHUNK_SIZE]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertEdgeBoundary(int localX, int localZ, int neighborLocalX, int neighborLocalZ) {
|
||||||
|
Fixture fixture = new Fixture();
|
||||||
|
fixture.setFieldSurface(neighborLocalX, neighborLocalZ, 60D);
|
||||||
|
fixture.resolve();
|
||||||
|
assertEquals(61, fixture.boundary(localX, localZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class Fixture {
|
||||||
|
private final int[] chunkSurfaceHeights = new int[CHUNK_SIZE * CHUNK_SIZE];
|
||||||
|
private final double[] fieldSurfaceHeights = new double[FIELD_SIZE * FIELD_SIZE];
|
||||||
|
private final boolean[] fieldHasFluid = new boolean[FIELD_SIZE * FIELD_SIZE];
|
||||||
|
private final int[] boundaryStartY = new int[CHUNK_SIZE * CHUNK_SIZE];
|
||||||
|
|
||||||
|
private Fixture() {
|
||||||
|
Arrays.fill(chunkSurfaceHeights, 70);
|
||||||
|
Arrays.fill(fieldSurfaceHeights, 70D);
|
||||||
|
Arrays.fill(fieldHasFluid, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setChunkSurface(int localX, int localZ, int surfaceY) {
|
||||||
|
chunkSurfaceHeights[index(localX, localZ)] = surfaceY;
|
||||||
|
setFieldSurface(localX, localZ, surfaceY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFieldSurface(int localX, int localZ, double surfaceY) {
|
||||||
|
int fieldX = localX + PADDING;
|
||||||
|
int fieldZ = localZ + PADDING;
|
||||||
|
fieldSurfaceHeights[(fieldX * FIELD_SIZE) + fieldZ] = surfaceY;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFieldHasFluid(int localX, int localZ, boolean hasFluid) {
|
||||||
|
int fieldX = localX + PADDING;
|
||||||
|
int fieldZ = localZ + PADDING;
|
||||||
|
fieldHasFluid[(fieldX * FIELD_SIZE) + fieldZ] = hasFluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resolve() {
|
||||||
|
SurfaceFluidBoundaryPlan.fill(
|
||||||
|
chunkSurfaceHeights,
|
||||||
|
fieldSurfaceHeights,
|
||||||
|
fieldHasFluid,
|
||||||
|
FIELD_SIZE,
|
||||||
|
PADDING,
|
||||||
|
FLUID_HEIGHT,
|
||||||
|
boundaryStartY
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int boundary(int localX, int localZ) {
|
||||||
|
return boundaryStartY[index(localX, localZ)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private int index(int localX, int localZ) {
|
||||||
|
return PowerOfTwoCoordinates.packLocal16(localX, localZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,44 @@
|
|||||||
package art.arcane.iris.engine.object;
|
package art.arcane.iris.engine.object;
|
||||||
|
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
|
import art.arcane.iris.engine.object.annotations.Desc;
|
||||||
import art.arcane.iris.spi.PlatformBlockState;
|
import art.arcane.iris.spi.PlatformBlockState;
|
||||||
import art.arcane.volmlib.util.math.RNG;
|
import art.arcane.volmlib.util.math.RNG;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotEquals;
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public class IrisDepositTuningTest {
|
public class IrisDepositTuningTest {
|
||||||
|
@Test
|
||||||
|
public void everyDepositEnumAndValueHasSchemaDescription() throws ReflectiveOperationException {
|
||||||
|
for (Field modelField : IrisDepositGenerator.class.getDeclaredFields()) {
|
||||||
|
Class<?> enumType = modelField.getType();
|
||||||
|
if (!enumType.isEnum()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Desc typeDescription = enumType.getAnnotation(Desc.class);
|
||||||
|
assertNotNull(enumType.getSimpleName(), typeDescription);
|
||||||
|
assertFalse(typeDescription.value().isBlank());
|
||||||
|
|
||||||
|
Object[] constants = enumType.getEnumConstants();
|
||||||
|
for (Object constant : constants) {
|
||||||
|
String constantName = ((Enum<?>) constant).name();
|
||||||
|
Desc constantDescription = enumType.getField(constantName).getAnnotation(Desc.class);
|
||||||
|
assertNotNull(enumType.getSimpleName() + "." + constantName, constantDescription);
|
||||||
|
assertFalse(constantDescription.value().isBlank());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void depositSizesScaleAndRemainWithinSchemaLimit() {
|
public void depositSizesScaleAndRemainWithinSchemaLimit() {
|
||||||
assertEquals(8, IrisDepositGenerator.scaledDepositSize(4, 2D));
|
assertEquals(8, IrisDepositGenerator.scaledDepositSize(4, 2D));
|
||||||
|
|||||||
@@ -113,12 +113,12 @@ public final class StubPlatform implements IrisPlatform {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAir() {
|
public boolean isAir() {
|
||||||
return key.endsWith("air");
|
return blockKey().endsWith("air");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSolid() {
|
public boolean isSolid() {
|
||||||
return !isAir();
|
return !isAir() && !isFluid();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -133,12 +133,16 @@ public final class StubPlatform implements IrisPlatform {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFluid() {
|
public boolean isFluid() {
|
||||||
return false;
|
String blockKey = blockKey();
|
||||||
|
return blockKey.equals("minecraft:water")
|
||||||
|
|| blockKey.equals("minecraft:lava")
|
||||||
|
|| blockKey.equals("minecraft:bubble_column");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isWater() {
|
public boolean isWater() {
|
||||||
return false;
|
String blockKey = blockKey();
|
||||||
|
return blockKey.equals("minecraft:water") || blockKey.equals("minecraft:bubble_column");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -163,11 +167,7 @@ public final class StubPlatform implements IrisPlatform {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTreeBlock() {
|
public boolean isTreeBlock() {
|
||||||
String blockKey = key;
|
String blockKey = blockKey();
|
||||||
int properties = blockKey.indexOf('[');
|
|
||||||
if (properties >= 0) {
|
|
||||||
blockKey = blockKey.substring(0, properties);
|
|
||||||
}
|
|
||||||
return blockKey.endsWith("_log")
|
return blockKey.endsWith("_log")
|
||||||
|| blockKey.endsWith("_wood")
|
|| blockKey.endsWith("_wood")
|
||||||
|| blockKey.endsWith("_stem")
|
|| blockKey.endsWith("_stem")
|
||||||
@@ -236,6 +236,11 @@ public final class StubPlatform implements IrisPlatform {
|
|||||||
public Object nativeHandle() {
|
public Object nativeHandle() {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String blockKey() {
|
||||||
|
int properties = key.indexOf('[');
|
||||||
|
return properties >= 0 ? key.substring(0, properties) : key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PlatformBlockState rotateState(IrisObjectRotation rotation, PlatformBlockState state,
|
private static PlatformBlockState rotateState(IrisObjectRotation rotation, PlatformBlockState state,
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import org.junit.BeforeClass;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public final class StubPlatformStateTest {
|
public final class StubPlatformStateTest {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
@@ -41,6 +43,22 @@ public final class StubPlatformStateTest {
|
|||||||
assertEquals("minecraft:oak_leaves[distance=7,persistent=true]", merged.key());
|
assertEquals("minecraft:oak_leaves[distance=7,persistent=true]", merged.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void classifiesVanillaFluidStates() {
|
||||||
|
PlatformBlockState water = state("minecraft:water[level=0]");
|
||||||
|
PlatformBlockState lava = state("minecraft:lava[level=0]");
|
||||||
|
PlatformBlockState stone = state("minecraft:stone");
|
||||||
|
|
||||||
|
assertTrue(water.isFluid());
|
||||||
|
assertTrue(water.isWater());
|
||||||
|
assertFalse(water.isSolid());
|
||||||
|
assertTrue(lava.isFluid());
|
||||||
|
assertFalse(lava.isWater());
|
||||||
|
assertFalse(lava.isSolid());
|
||||||
|
assertFalse(stone.isFluid());
|
||||||
|
assertTrue(stone.isSolid());
|
||||||
|
}
|
||||||
|
|
||||||
private PlatformBlockState state(String key) {
|
private PlatformBlockState state(String key) {
|
||||||
return IrisPlatforms.get().registries().block(key);
|
return IrisPlatforms.get().registries().block(key);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user