mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-27 22:40:13 +00:00
Merged object stability fixes
- Keep scaling geometry and volume in one locked snapshot - Skip unsupported block orientations and their tile data - Replace smart bore executor scaffolding with ordered loops
This commit is contained in:
commit
4c989fe1c0
6 files changed
+344
-117
No files matched your search
@@ -533,6 +533,9 @@ final class IrisObjectPlacementRunner {
|
||||
}
|
||||
|
||||
data = config.getRotation().rotate(data, spinx, spiny, spinz);
|
||||
if (data == null) {
|
||||
continue;
|
||||
}
|
||||
xx = x + (int) Math.round(i.getX());
|
||||
|
||||
int yy = y + (int) Math.round(i.getY());
|
||||
|
||||
@@ -23,13 +23,9 @@ import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.common.data.VectorMap;
|
||||
import art.arcane.iris.util.common.math.IrisBlockVector;
|
||||
import art.arcane.iris.util.common.math.Vector3i;
|
||||
import art.arcane.iris.util.common.parallel.BurstExecutor;
|
||||
import art.arcane.iris.util.common.parallel.MultiBurst;
|
||||
import art.arcane.volmlib.util.format.Form;
|
||||
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Volume shaping for {@link IrisObject}: smart boring, shrinkwrapping, compaction and the shared block
|
||||
* classification helpers used by placement.
|
||||
@@ -59,30 +55,23 @@ final class IrisObjectShaping {
|
||||
private static void ensureSmartBoredLocked(IrisObject self) {
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
PlatformBlockState vair = IrisObject.States.VAIR;
|
||||
AtomicInteger applied = new AtomicInteger();
|
||||
IrisBlockVector max = new IrisBlockVector(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE);
|
||||
IrisBlockVector min = new IrisBlockVector(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
|
||||
VectorMap<PlatformBlockState> source;
|
||||
self.readLock.lock();
|
||||
try {
|
||||
if (self.blocks.isEmpty()) {
|
||||
IrisLogging.warn("Cannot Smart Bore " + self.getLoadKey() + " because it has 0 blocks in it.");
|
||||
self.smartBored = true;
|
||||
return;
|
||||
}
|
||||
int applied = 0;
|
||||
IrisBlockVector max = new IrisBlockVector(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
|
||||
IrisBlockVector min = new IrisBlockVector(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
VectorMap<PlatformBlockState> source = self.blocks;
|
||||
if (source.isEmpty()) {
|
||||
IrisLogging.warn("Cannot Smart Bore " + self.getLoadKey() + " because it has 0 blocks in it.");
|
||||
self.smartBored = true;
|
||||
return;
|
||||
}
|
||||
|
||||
source = self.blocks;
|
||||
|
||||
for (IrisBlockVector i : self.blocks.keys()) {
|
||||
max.setX(Math.max(i.getX(), max.getX()));
|
||||
min.setX(Math.min(i.getX(), min.getX()));
|
||||
max.setY(Math.max(i.getY(), max.getY()));
|
||||
min.setY(Math.min(i.getY(), min.getY()));
|
||||
max.setZ(Math.max(i.getZ(), max.getZ()));
|
||||
min.setZ(Math.min(i.getZ(), min.getZ()));
|
||||
}
|
||||
} finally {
|
||||
self.readLock.unlock();
|
||||
for (IrisBlockVector i : source.keys()) {
|
||||
max.setX(Math.max(i.getX(), max.getX()));
|
||||
min.setX(Math.min(i.getX(), min.getX()));
|
||||
max.setY(Math.max(i.getY(), max.getY()));
|
||||
min.setY(Math.min(i.getY(), min.getY()));
|
||||
max.setZ(Math.max(i.getZ(), max.getZ()));
|
||||
min.setZ(Math.min(i.getZ(), min.getZ()));
|
||||
}
|
||||
|
||||
VectorMap<PlatformBlockState> bore = new VectorMap<>();
|
||||
@@ -90,114 +79,94 @@ final class IrisObjectShaping {
|
||||
// bored volume must come from a fixed X->Y->Z order on the calling (lock-owning)
|
||||
// thread, not from pool scheduling. This matches what burst-worker callers (studio,
|
||||
// generation threads) already produced, so output is unchanged where it was stable.
|
||||
BurstExecutor burst = MultiBurst.burst.burst();
|
||||
burst.setMulticore(false);
|
||||
|
||||
// Smash X
|
||||
for (int rayY = min.getBlockY(); rayY <= max.getBlockY(); rayY++) {
|
||||
int finalRayY = rayY;
|
||||
burst.queue(() -> {
|
||||
for (int rayZ = min.getBlockZ(); rayZ <= max.getBlockZ(); rayZ++) {
|
||||
int start = Integer.MAX_VALUE;
|
||||
int end = Integer.MIN_VALUE;
|
||||
for (int rayZ = min.getBlockZ(); rayZ <= max.getBlockZ(); rayZ++) {
|
||||
int start = Integer.MAX_VALUE;
|
||||
int end = Integer.MIN_VALUE;
|
||||
|
||||
for (int ray = min.getBlockX(); ray <= max.getBlockX(); ray++) {
|
||||
if (boreContains(source, bore, new IrisBlockVector(ray, finalRayY, rayZ))) {
|
||||
start = Math.min(ray, start);
|
||||
end = Math.max(ray, end);
|
||||
}
|
||||
}
|
||||
|
||||
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
|
||||
for (int i = start; i <= end; i++) {
|
||||
boreCell(source, bore, new IrisBlockVector(i, finalRayY, rayZ), vair, applied);
|
||||
}
|
||||
for (int ray = min.getBlockX(); ray <= max.getBlockX(); ray++) {
|
||||
if (boreContains(source, bore, new IrisBlockVector(ray, rayY, rayZ))) {
|
||||
start = Math.min(ray, start);
|
||||
end = Math.max(ray, end);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
|
||||
for (int i = start; i <= end; i++) {
|
||||
applied += boreCell(source, bore, new IrisBlockVector(i, rayY, rayZ), vair);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Smash Y
|
||||
for (int rayX = min.getBlockX(); rayX <= max.getBlockX(); rayX++) {
|
||||
int finalRayX = rayX;
|
||||
burst.queue(() -> {
|
||||
for (int rayZ = min.getBlockZ(); rayZ <= max.getBlockZ(); rayZ++) {
|
||||
int start = Integer.MAX_VALUE;
|
||||
int end = Integer.MIN_VALUE;
|
||||
for (int rayZ = min.getBlockZ(); rayZ <= max.getBlockZ(); rayZ++) {
|
||||
int start = Integer.MAX_VALUE;
|
||||
int end = Integer.MIN_VALUE;
|
||||
|
||||
for (int ray = min.getBlockY(); ray <= max.getBlockY(); ray++) {
|
||||
if (boreContains(source, bore, new IrisBlockVector(finalRayX, ray, rayZ))) {
|
||||
start = Math.min(ray, start);
|
||||
end = Math.max(ray, end);
|
||||
}
|
||||
}
|
||||
|
||||
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
|
||||
for (int i = start; i <= end; i++) {
|
||||
boreCell(source, bore, new IrisBlockVector(finalRayX, i, rayZ), vair, applied);
|
||||
}
|
||||
for (int ray = min.getBlockY(); ray <= max.getBlockY(); ray++) {
|
||||
if (boreContains(source, bore, new IrisBlockVector(rayX, ray, rayZ))) {
|
||||
start = Math.min(ray, start);
|
||||
end = Math.max(ray, end);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
|
||||
for (int i = start; i <= end; i++) {
|
||||
applied += boreCell(source, bore, new IrisBlockVector(rayX, i, rayZ), vair);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Smash Z
|
||||
for (int rayX = min.getBlockX(); rayX <= max.getBlockX(); rayX++) {
|
||||
int finalRayX = rayX;
|
||||
burst.queue(() -> {
|
||||
for (int rayY = min.getBlockY(); rayY <= max.getBlockY(); rayY++) {
|
||||
int start = Integer.MAX_VALUE;
|
||||
int end = Integer.MIN_VALUE;
|
||||
for (int rayY = min.getBlockY(); rayY <= max.getBlockY(); rayY++) {
|
||||
int start = Integer.MAX_VALUE;
|
||||
int end = Integer.MIN_VALUE;
|
||||
|
||||
for (int ray = min.getBlockZ(); ray <= max.getBlockZ(); ray++) {
|
||||
if (boreContains(source, bore, new IrisBlockVector(finalRayX, rayY, ray))) {
|
||||
start = Math.min(ray, start);
|
||||
end = Math.max(ray, end);
|
||||
}
|
||||
}
|
||||
|
||||
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
|
||||
for (int i = start; i <= end; i++) {
|
||||
boreCell(source, bore, new IrisBlockVector(finalRayX, rayY, i), vair, applied);
|
||||
}
|
||||
for (int ray = min.getBlockZ(); ray <= max.getBlockZ(); ray++) {
|
||||
if (boreContains(source, bore, new IrisBlockVector(rayX, rayY, ray))) {
|
||||
start = Math.min(ray, start);
|
||||
end = Math.max(ray, end);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
burst.complete();
|
||||
|
||||
self.writeLock.lock();
|
||||
try {
|
||||
if (!self.smartBored) {
|
||||
bore.forEach((v, s) -> self.blocks.computeIfAbsent(v, (vv) -> s));
|
||||
self.smartBored = true;
|
||||
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
|
||||
for (int i = start; i <= end; i++) {
|
||||
applied += boreCell(source, bore, new IrisBlockVector(rayX, rayY, i), vair);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
self.writeLock.unlock();
|
||||
}
|
||||
|
||||
IrisLogging.debug("Smart Bore: " + self.getLoadKey() + " in " + Form.duration(p.getMilliseconds(), 2) + " (" + Form.f(applied.get()) + ")");
|
||||
source.putAll(bore);
|
||||
self.smartBored = true;
|
||||
|
||||
IrisLogging.debug("Smart Bore: " + self.getLoadKey() + " in " + Form.duration(p.getMilliseconds(), 2) + " (" + Form.f(applied) + ")");
|
||||
}
|
||||
|
||||
private static boolean boreContains(VectorMap<PlatformBlockState> source, VectorMap<PlatformBlockState> bore, IrisBlockVector v) {
|
||||
return source.containsKey(v) || bore.containsKey(v);
|
||||
}
|
||||
|
||||
private static void boreCell(VectorMap<PlatformBlockState> source, VectorMap<PlatformBlockState> bore, IrisBlockVector v, PlatformBlockState vair, AtomicInteger applied) {
|
||||
private static int boreCell(VectorMap<PlatformBlockState> source, VectorMap<PlatformBlockState> bore, IrisBlockVector v, PlatformBlockState vair) {
|
||||
PlatformBlockState existing = source.get(v);
|
||||
|
||||
if (existing == null) {
|
||||
if (vair.equals(bore.get(v))) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bore.computeIfAbsent(v, (vv) -> vair);
|
||||
bore.put(v, vair);
|
||||
} else if (vair.equals(existing)) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
applied.getAndIncrement();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void shrinkwrap(IrisObject self) {
|
||||
|
||||
@@ -30,10 +30,12 @@ import art.arcane.iris.util.project.interpolation.Interpolation3D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Geometric transforms for {@link IrisObject}: rotation, scaling and the interpolated upscalers.
|
||||
@@ -52,15 +54,23 @@ final class IrisObjectTransforms {
|
||||
self.writeLock.lock();
|
||||
try {
|
||||
VectorMap<PlatformBlockState> d = new VectorMap<>();
|
||||
Set<IrisBlockVector> omitted = new HashSet<>();
|
||||
|
||||
for (var entry : self.blocks) {
|
||||
d.put(r.rotate(entry.getKey(), spinx, spiny, spinz), r.rotate(entry.getValue(), spinx, spiny, spinz));
|
||||
for (Map.Entry<IrisBlockVector, PlatformBlockState> entry : self.blocks) {
|
||||
PlatformBlockState rotated = r.rotate(entry.getValue(), spinx, spiny, spinz);
|
||||
if (rotated == null) {
|
||||
omitted.add(entry.getKey());
|
||||
continue;
|
||||
}
|
||||
d.put(r.rotate(entry.getKey(), spinx, spiny, spinz), rotated);
|
||||
}
|
||||
|
||||
VectorMap<TileData> dx = new VectorMap<>();
|
||||
|
||||
for (var entry : self.states) {
|
||||
dx.put(r.rotate(entry.getKey(), spinx, spiny, spinz), entry.getValue());
|
||||
for (Map.Entry<IrisBlockVector, TileData> entry : self.states) {
|
||||
if (!omitted.contains(entry.getKey())) {
|
||||
dx.put(r.rotate(entry.getKey(), spinx, spiny, spinz), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
self.blocks = d;
|
||||
@@ -100,26 +110,27 @@ final class IrisObjectTransforms {
|
||||
VectorMap<TileData> placeTile = new VectorMap<>();
|
||||
VectorMap<IrisBlockVector> placeMax = savedOrigin && scale > 1 ? new VectorMap<>() : null;
|
||||
|
||||
IrisVector center = new IrisVector(self.getCenter().getX(), self.getCenter().getY(), self.getCenter().getZ());
|
||||
if (self.getH() == 2) {
|
||||
center = center.setY(center.getBlockY() + 0.5);
|
||||
}
|
||||
if (self.getW() == 2) {
|
||||
center = center.setX(center.getBlockX() + 0.5);
|
||||
}
|
||||
if (self.getD() == 2) {
|
||||
center = center.setZ(center.getBlockZ() + 0.5);
|
||||
}
|
||||
|
||||
IrisObject oo = savedOrigin ? createOriginScaledObject(self, scale)
|
||||
: new IrisObject((int) Math.ceil((self.w * scale) + (scale * 2)), (int) Math.ceil((self.h * scale) + (scale * 2)), (int) Math.ceil((self.d * scale) + (scale * 2)));
|
||||
oo.setLoadKey(self.getLoadKey());
|
||||
oo.setLoader(self.getLoader());
|
||||
oo.setLoadFile(self.getLoadFile());
|
||||
|
||||
IrisVector center;
|
||||
IrisObject oo;
|
||||
boolean hasTiles;
|
||||
self.readLock.lock();
|
||||
try {
|
||||
center = new IrisVector(self.getCenter().getX(), self.getCenter().getY(), self.getCenter().getZ());
|
||||
if (self.getH() == 2) {
|
||||
center = center.setY(center.getBlockY() + 0.5);
|
||||
}
|
||||
if (self.getW() == 2) {
|
||||
center = center.setX(center.getBlockX() + 0.5);
|
||||
}
|
||||
if (self.getD() == 2) {
|
||||
center = center.setZ(center.getBlockZ() + 0.5);
|
||||
}
|
||||
|
||||
oo = savedOrigin ? createOriginScaledObject(self, scale)
|
||||
: new IrisObject((int) Math.ceil((self.w * scale) + (scale * 2)), (int) Math.ceil((self.h * scale) + (scale * 2)), (int) Math.ceil((self.d * scale) + (scale * 2)));
|
||||
oo.setLoadKey(self.getLoadKey());
|
||||
oo.setLoader(self.getLoader());
|
||||
oo.setLoadFile(self.getLoadFile());
|
||||
hasTiles = !self.states.isEmpty();
|
||||
for (Map.Entry<IrisBlockVector, PlatformBlockState> entry : self.blocks) {
|
||||
PlatformBlockState bd = entry.getValue();
|
||||
|
||||
Reference in new issue
Block a user