Fixing a handfull of issues!

This commit is contained in:
Brian Neumann-Fopiano committed 2026-10-21 18:07:10 -04:00
1 parent 1132242c58
commit c3359e0a16
30 files changed
+1324 -282

No files matched your search

@@ -316,6 +316,11 @@ public class IrisCaveCarver3D {
for (int lz = 0; lz < 16; lz++) {
int z = z0 + lz;
int index = PowerOfTwoCoordinates.packLocal16(lx, lz);
clampedWeights[index] = clampColumnWeight(columnWeights[index]);
if (clampedWeights[index] <= resolvedMinWeight) {
columnMaxY[index] = minY - 1;
continue;
}
int columnSurfaceY;
if (precomputedSurfaceHeights != null && precomputedSurfaceHeights.length > index) {
columnSurfaceY = precomputedSurfaceHeights[index];
@@ -340,7 +345,6 @@ public class IrisCaveCarver3D {
columnThreshold[index] = (thresholdDensity == null
? constantThreshold
: thresholdDensity.fitDouble(thresholdMin, thresholdMax, x, z)) - thresholdBias;
clampedWeights[index] = clampColumnWeight(columnWeights[index]);
}
}
@@ -56,7 +56,6 @@ public class MantleCarvingComponent extends IrisMantleComponent {
private static final int FIELD_SIZE = CHUNK_SIZE + (BLEND_RADIUS * 2);
private static final double MIN_WEIGHT = 0.08D;
private static final double THRESHOLD_PENALTY = 0.24D;
private static final int MAX_BLENDED_PROFILE_PASSES = 2;
private static final int MAX_POOLED_WEIGHT_BUFFERS = 64;
/** Lattice columns kept for neighbouring chunks: about 3 KB each on land, roughly 50 MB when full. */
private static final int DENSITY_GRID_COLUMNS = 16_384;
@@ -348,9 +347,9 @@ public class MantleCarvingComponent extends IrisMantleComponent {
columnWeightedProfiles.add(new WeightedProfile(profile, weights, averageWeight, null, columnWeightedProfiles.size()));
}
List<WeightedProfile> blendedProfiles = limitAndMergeBlendedProfiles(columnWeightedProfiles, MAX_BLENDED_PROFILE_PASSES, CHUNK_AREA);
columnWeightedProfiles.sort(MantleCarvingComponent::compareByCarveOrder);
List<WeightedProfile> resolvedProfiles = resolveDimensionCarvingProfiles(chunkX, chunkZ, resolverState, blendScratch);
resolvedProfiles.addAll(blendedProfiles);
resolvedProfiles.addAll(columnWeightedProfiles);
return resolvedProfiles;
}
@@ -619,67 +618,6 @@ public class MantleCarvingComponent extends IrisMantleComponent {
return surfaceHeights;
}
private static List<WeightedProfile> limitAndMergeBlendedProfiles(List<WeightedProfile> blendedProfiles, int maxProfiles) {
return limitAndMergeBlendedProfiles(blendedProfiles, maxProfiles, CHUNK_AREA);
}
private static List<WeightedProfile> limitAndMergeBlendedProfiles(List<WeightedProfile> blendedProfiles, int maxProfiles, int areaSize) {
if (blendedProfiles == null || blendedProfiles.isEmpty()) {
return new ArrayList<>();
}
int clampedLimit = Math.max(1, maxProfiles);
List<WeightedProfile> rankedProfiles = new ArrayList<>(blendedProfiles);
rankedProfiles.sort(MantleCarvingComponent::compareBySelectionRank);
List<WeightedProfile> keptProfiles = new ArrayList<>();
int keptCount = Math.min(clampedLimit, rankedProfiles.size());
for (int index = 0; index < keptCount; index++) {
keptProfiles.add(rankedProfiles.get(index));
}
if (rankedProfiles.size() > keptCount) {
for (int columnIndex = 0; columnIndex < areaSize; columnIndex++) {
int dominantIndex = 0;
double dominantWeight = Double.NEGATIVE_INFINITY;
for (int keptIndex = 0; keptIndex < keptProfiles.size(); keptIndex++) {
double keptWeight = keptProfiles.get(keptIndex).columnWeights[columnIndex];
if (keptWeight > dominantWeight) {
dominantWeight = keptWeight;
dominantIndex = keptIndex;
}
}
double droppedWeight = 0D;
for (int droppedIndex = keptCount; droppedIndex < rankedProfiles.size(); droppedIndex++) {
droppedWeight += rankedProfiles.get(droppedIndex).columnWeights[columnIndex];
}
if (droppedWeight <= 0D) {
continue;
}
WeightedProfile dominantProfile = keptProfiles.get(dominantIndex);
double mergedWeight = dominantProfile.columnWeights[columnIndex] + droppedWeight;
dominantProfile.columnWeights[columnIndex] = clampWeight(mergedWeight);
}
}
List<WeightedProfile> mergedProfiles = new ArrayList<>();
for (WeightedProfile keptProfile : keptProfiles) {
double averageWeight = computeAverageWeight(keptProfile.columnWeights, areaSize);
mergedProfiles.add(new WeightedProfile(keptProfile.profile, keptProfile.columnWeights, averageWeight, keptProfile.worldYRange, keptProfile.sequence));
}
mergedProfiles.sort(MantleCarvingComponent::compareByCarveOrder);
return mergedProfiles;
}
private static int compareBySelectionRank(WeightedProfile a, WeightedProfile b) {
int weightOrder = Double.compare(b.averageWeight, a.averageWeight);
if (weightOrder != 0) {
return weightOrder;
}
return Integer.compare(a.sequence, b.sequence);
}
private static int compareByCarveOrder(WeightedProfile a, WeightedProfile b) {
int weightOrder = Double.compare(a.averageWeight, b.averageWeight);
if (weightOrder != 0) {
@@ -689,10 +627,6 @@ public class MantleCarvingComponent extends IrisMantleComponent {
}
private static double computeAverageWeight(double[] weights) {
return computeAverageWeight(weights, CHUNK_AREA);
}
private static double computeAverageWeight(double[] weights, int areaSize) {
if (weights == null || weights.length == 0) {
return 0D;
}
@@ -700,7 +634,7 @@ public class MantleCarvingComponent extends IrisMantleComponent {
for (double weight : weights) {
sum += weight;
}
return sum / Math.max(1, areaSize);
return sum / CHUNK_AREA;
}
private static double clampWeight(double value) {
@@ -730,10 +664,6 @@ public class MantleCarvingComponent extends IrisMantleComponent {
this.worldYRange = worldYRange;
this.sequence = sequence;
}
private double averageWeight() {
return averageWeight;
}
}
private static final class BlendScratch {
@@ -930,7 +930,7 @@ public class IrisEngine implements Engine {
queryMaximumX,
queryMaximumZ);
for (NativeStructureVolume volume : resolved) {
if (!volume.intersectsRect(minimumX, minimumZ, maximumX, maximumZ)) {
if (!volume.intersectsInfluenceRect(minimumX, minimumZ, maximumX, maximumZ)) {
continue;
}
if (matches == null) {
@@ -115,7 +115,7 @@ public final class NativeStructureVolumeIndex {
for (int chunkX = fromChunkX; chunkX <= toChunkX; chunkX++) {
for (int chunkZ = fromChunkZ; chunkZ <= toChunkZ; chunkZ++) {
for (NativeStructureVolume volume : chunkVolumes(engine, runtimeId, chunkX, chunkZ)) {
if (!volume.intersectsRect(minX, minZ, maxX, maxZ)) {
if (!volume.intersectsInfluenceRect(minX, minZ, maxX, maxZ)) {
continue;
}
if (matches == null) {
@@ -150,7 +150,7 @@ public final class NativeStructureVolumeIndex {
for (int originX = chunkX - ORIGIN_REACH_CHUNKS; originX <= chunkX + ORIGIN_REACH_CHUNKS; originX++) {
for (int originZ = chunkZ - ORIGIN_REACH_CHUNKS; originZ <= chunkZ + ORIGIN_REACH_CHUNKS; originZ++) {
for (NativeStructureVolume volume : scopedOriginVolumes(engine, originX, originZ, pinnedRuntimeId)) {
if (!volume.intersectsRect(minX, minZ, maxX, maxZ)) {
if (!volume.intersectsInfluenceRect(minX, minZ, maxX, maxZ)) {
continue;
}
if (volumes == null) {
@@ -54,7 +54,7 @@ public final class NativeStructureVolumeMemo {
for (int chunkX = fromChunkX; chunkX <= toChunkX; chunkX++) {
for (int chunkZ = fromChunkZ; chunkZ <= toChunkZ; chunkZ++) {
for (NativeStructureVolume volume : chunkVolumes(engine, hooks, chunkX, chunkZ)) {
if (!volume.intersectsRect(minX, minZ, maxX, maxZ)) {
if (!volume.intersectsInfluenceRect(minX, minZ, maxX, maxZ)) {
continue;
}
if (matches == null) {
@@ -49,6 +49,7 @@ import art.arcane.volmlib.util.math.BlockPosition;
import art.arcane.volmlib.util.math.Position2;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.volmlib.util.matter.MatterMarker;
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
import java.util.Comparator;
import java.util.Objects;
@@ -1135,10 +1136,14 @@ final class IrisObjectPlacementRunner {
int envelopeMinY = projection != null ? Integer.MIN_VALUE : worldY + bounds.minY() - warpMargin;
int envelopeMaxY = projection != null ? Integer.MAX_VALUE : worldY + bounds.maxY() + warpMargin;
boolean envelopeMeetsPiece = false;
boolean includesSurfaceCuts = false;
for (NativeStructureVolume volume : volumes) {
if (volume.intersects(minX, envelopeMinY, minZ, maxX, envelopeMaxY, maxZ)) {
envelopeMeetsPiece = true;
break;
}
if (volume.surfaceAdjustment() != null && volume.intersectsInfluenceRect(minX, minZ, maxX, maxZ)) {
envelopeMeetsPiece = true;
includesSurfaceCuts = true;
}
}
@@ -1148,6 +1153,7 @@ final class IrisObjectPlacementRunner {
self.readLock.lock();
try {
Long2LongOpenHashMap surfaceCuts = null;
VectorMap<NativeBlockState>.Cursor cursor = self.blocks.cursor();
while (cursor.next()) {
NativeBlockState state = cursor.value();
@@ -1187,6 +1193,28 @@ final class IrisObjectPlacementRunner {
return true;
}
}
if (!includesSurfaceCuts) {
continue;
}
if (surfaceCuts == null) {
surfaceCuts = new Long2LongOpenHashMap();
surfaceCuts.defaultReturnValue(Long.MIN_VALUE);
}
long column = ((long) xx << 32) ^ (zz & 0xffffffffL);
long cut = surfaceCuts.get(column);
if (cut == Long.MIN_VALUE) {
int surfaceY = Engine.hostHeight(engine, xx, zz, true) + engine.getMinHeight();
int targetY = NativeStructureVolume.surfaceCutY(volumes, xx, zz, surfaceY);
cut = ((long) surfaceY << 32) ^ (targetY & 0xffffffffL);
surfaceCuts.put(column, cut);
}
int surfaceY = (int) (cut >> 32);
int targetY = (int) cut;
int margin = projection == null ? warpMargin : 0;
if (targetY < surfaceY && worldBlockY > (long) targetY - margin
&& worldBlockY <= (long) surfaceY + 1 + margin) {
return true;
}
}
} finally {
self.readLock.unlock();
@@ -124,6 +124,7 @@ final class IrisObjectTransforms {
interpolation = IrisObjectPlacementScaleInterpolator.NONE;
}
boolean savedOrigin = origin == ScaleOrigin.SAVED;
boolean fractional = scale != Math.rint(scale);
List<ScaledVoxel> voxels;
IrisObject output;
TreeGrounding grounding;
@@ -148,26 +149,33 @@ final class IrisObjectTransforms {
sourcePosition.getBlockZ() + sourceCenter.getZ());
IrisBlockVector minimum = scaledMinimum(position, scale);
IrisBlockVector maximum = scaledMaximum(position, scale);
IrisVector corner = fractional ? new IrisVector(position.getX() * scale,
position.getY() * scale, position.getZ() * scale) : minimum;
if (!savedOrigin) {
minimum.subtract(targetCenter);
maximum.subtract(targetCenter);
if (fractional) {
corner.subtract(targetCenter);
}
}
TileData tile = self.states.get(sourcePosition);
voxels.add(new ScaledVoxel(sourcePosition.clone(), minimum, maximum, entry.getValue(),
voxels.add(new ScaledVoxel(sourcePosition.clone(), minimum, maximum, corner, entry.getValue(),
tile == null ? null : tile.clone(), grounding != null && grounding.isCanopy(
sourcePosition.getBlockX(), sourcePosition.getBlockY(), sourcePosition.getBlockZ())));
}
} finally {
self.readLock.unlock();
}
if (scale != Math.rint(scale)) {
Set<TreeBlockCanvas.Vec> canopy = grounding == null ? null : new HashSet<>();
if (fractional) {
voxels.sort(Comparator.comparingInt((ScaledVoxel voxel) -> voxel.source().getBlockX())
.thenComparingInt(voxel -> voxel.source().getBlockY())
.thenComparingInt(voxel -> voxel.source().getBlockZ()));
}
Set<TreeBlockCanvas.Vec> canopy = grounding == null ? null : new HashSet<>();
for (ScaledVoxel voxel : voxels) {
writeScaledVoxel(output, voxel, canopy);
writeResampledVoxels(output, voxels, scale, canopy);
} else {
for (ScaledVoxel voxel : voxels) {
writeScaledVoxel(output, voxel, canopy);
}
}
VectorMap<NativeBlockState> scaledBlocks = output.blocks;
@@ -206,7 +214,7 @@ final class IrisObjectTransforms {
for (int x = minimum.getBlockX(); x <= maximum.getBlockX(); x++) {
for (int z = minimum.getBlockZ(); z <= maximum.getBlockZ(); z++) {
NativeBlockState state = output.blocks.get(new IrisBlockVector(x, y, z));
if (state != null) {
if (state != null && !canopy.contains(new TreeBlockCanvas.Vec(x, y, z))) {
roots.add(new TreeGrounding.Root(x, y, z, state));
}
}
@@ -225,23 +233,53 @@ final class IrisObjectTransforms {
position.setZ(z);
for (int y = minimum.getBlockY(); y <= maximum.getBlockY(); y++) {
position.setY(y);
output.blocks.put(position, voxel.block());
if (canopy != null) {
TreeBlockCanvas.Vec cell = new TreeBlockCanvas.Vec(x, y, z);
if (voxel.canopy()) {
canopy.add(cell);
} else {
canopy.remove(cell);
writeScaledBlock(output, position, voxel, canopy);
}
}
}
}
private static void writeResampledVoxels(IrisObject output, List<ScaledVoxel> voxels, double scale,
Set<TreeBlockCanvas.Vec> canopy) {
VectorMap<ScaledVoxel> samples = new VectorMap<>();
IrisBlockVector position = new IrisBlockVector();
for (ScaledVoxel voxel : voxels) {
for (int x = voxel.minimum().getBlockX(); x <= voxel.maximum().getBlockX(); x++) {
position.setX(x);
for (int z = voxel.minimum().getBlockZ(); z <= voxel.maximum().getBlockZ(); z++) {
position.setZ(z);
for (int y = voxel.minimum().getBlockY(); y <= voxel.maximum().getBlockY(); y++) {
position.setY(y);
ScaledVoxel previous = samples.get(position);
if (previous == null || voxel.overlap(position, scale) >= previous.overlap(position, scale)) {
samples.put(position, voxel);
}
}
if (voxel.tile() == null) {
output.states.remove(position);
} else {
output.states.put(position, voxel.tile().clone());
}
}
}
}
for (Map.Entry<IrisBlockVector, ScaledVoxel> entry : samples) {
writeScaledBlock(output, entry.getKey(), entry.getValue(), canopy);
}
}
private static void writeScaledBlock(IrisObject output, IrisBlockVector position, ScaledVoxel voxel,
Set<TreeBlockCanvas.Vec> canopy) {
output.blocks.put(position, voxel.block());
if (canopy != null) {
TreeBlockCanvas.Vec cell = new TreeBlockCanvas.Vec(position.getBlockX(),
position.getBlockY(), position.getBlockZ());
if (voxel.canopy()) {
canopy.add(cell);
} else {
canopy.remove(cell);
}
}
if (voxel.tile() == null) {
output.states.remove(position);
} else {
output.states.put(position, voxel.tile().clone());
}
}
private static IrisObject createCenteredScaledObject(IrisObject source, double scale) {
@@ -541,7 +579,16 @@ final class IrisObjectTransforms {
}
private record ScaledVoxel(IrisBlockVector source, IrisBlockVector minimum, IrisBlockVector maximum,
NativeBlockState block, TileData tile, boolean canopy) {
IrisVector corner, NativeBlockState block, TileData tile, boolean canopy) {
private double overlap(IrisBlockVector position, double scale) {
return overlap(corner.getX(), position.getX(), scale)
* overlap(corner.getY(), position.getY(), scale)
* overlap(corner.getZ(), position.getZ(), scale);
}
private static double overlap(double source, double target, double scale) {
return Math.max(0D, Math.min(source + scale, target + 1D) - Math.max(source, target));
}
}
private enum ScaleOrigin {