mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-25 13:30:08 +00:00
iggy
This commit is contained in:
1 parent
699247b1de
commit
e8dd4e1127
10 files changed
+229
-36
No files matched your search
@@ -42,3 +42,5 @@ service-account*.json
|
|||||||
docs/
|
docs/
|
||||||
|
|
||||||
CROSSPLATFORM_PLAN.md
|
CROSSPLATFORM_PLAN.md
|
||||||
|
|
||||||
|
.qa/
|
||||||
+2
-1
@@ -465,7 +465,8 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
BoundingBox area, ChunkPos chunkPos, String structureId, StructureStart start,
|
BoundingBox area, ChunkPos chunkPos, String structureId, StructureStart start,
|
||||||
IrisNativeStructureDecision decision) {
|
IrisNativeStructureDecision decision) {
|
||||||
NativeStructurePostProcessor.place(world, structureManager, this, random, area, chunkPos,
|
NativeStructurePostProcessor.place(world, structureManager, this, random, area, chunkPos,
|
||||||
structureId, start, decision, this::resolveStiltBlock);
|
structureId, start, decision, this::resolveStiltBlock,
|
||||||
|
(x, z) -> engine.getHeight(x, z, true) + engine.getMinHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<List<Structure>> structuresByStep(Registry<Structure> registry) {
|
private List<List<Structure>> structuresByStep(Registry<Structure> registry) {
|
||||||
|
|||||||
+2
@@ -85,10 +85,12 @@ public class IrisChunkGeneratorMonumentLocateContractTest {
|
|||||||
int placement = source.indexOf("start.placeInChunk(world, structureManager, generator");
|
int placement = source.indexOf("start.placeInChunk(world, structureManager, generator");
|
||||||
int stiltPlacement = source.indexOf("placeStilts(world, area, structureId, start", placement);
|
int stiltPlacement = source.indexOf("placeStilts(world, area, structureId, start", placement);
|
||||||
int occupancyCheck = source.indexOf("if (state.isSolid())", stiltPlacement);
|
int occupancyCheck = source.indexOf("if (state.isSolid())", stiltPlacement);
|
||||||
|
int terrainFloor = source.indexOf("y > terrainY", stiltPlacement);
|
||||||
|
|
||||||
assertTrue(placement >= 0);
|
assertTrue(placement >= 0);
|
||||||
assertTrue(stiltPlacement > placement);
|
assertTrue(stiltPlacement > placement);
|
||||||
assertTrue(occupancyCheck > stiltPlacement);
|
assertTrue(occupancyCheck > stiltPlacement);
|
||||||
|
assertTrue(terrainFloor > stiltPlacement);
|
||||||
assertFalse(source.contains("state.equals("));
|
assertFalse(source.contains("state.equals("));
|
||||||
assertFalse(source.contains("snapshot.states"));
|
assertFalse(source.contains("snapshot.states"));
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-6
@@ -60,13 +60,15 @@ public final class NativeStructurePostProcessor {
|
|||||||
public static void place(WorldGenLevel world, StructureManager structureManager, ChunkGenerator generator,
|
public static void place(WorldGenLevel world, StructureManager structureManager, ChunkGenerator generator,
|
||||||
WorldgenRandom random, BoundingBox area, ChunkPos chunkPos, String structureId,
|
WorldgenRandom random, BoundingBox area, ChunkPos chunkPos, String structureId,
|
||||||
StructureStart start, IrisNativeStructureDecision decision,
|
StructureStart start, IrisNativeStructureDecision decision,
|
||||||
StiltBlockResolver stiltBlockResolver) {
|
StiltBlockResolver stiltBlockResolver,
|
||||||
|
IntBinaryOperator surfaceHeight) {
|
||||||
IrisStructureStiltSettings stilt = decision.stilt();
|
IrisStructureStiltSettings stilt = decision.stilt();
|
||||||
ensureMonumentSeaLevelAlignment(start, structureId, decision.yShift(), generator.getSeaLevel(),
|
ensureMonumentSeaLevelAlignment(start, structureId, decision.yShift(), generator.getSeaLevel(),
|
||||||
area.minY(), area.maxY() + 1);
|
area.minY(), area.maxY() + 1);
|
||||||
start.placeInChunk(world, structureManager, generator, random, area, chunkPos);
|
start.placeInChunk(world, structureManager, generator, random, area, chunkPos);
|
||||||
if (stilt != null) {
|
if (stilt != null) {
|
||||||
placeStilts(world, area, structureId, start, stilt, stiltBlockResolver);
|
placeStilts(world, area, structureId, start, stilt, stiltBlockResolver, surfaceHeight,
|
||||||
|
!isUndergroundStep(start.getStructure().step()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -798,7 +800,10 @@ public final class NativeStructurePostProcessor {
|
|||||||
|
|
||||||
private static void placeStilts(WorldGenLevel world, BoundingBox area, String structureId,
|
private static void placeStilts(WorldGenLevel world, BoundingBox area, String structureId,
|
||||||
StructureStart start, IrisStructureStiltSettings settings,
|
StructureStart start, IrisStructureStiltSettings settings,
|
||||||
StiltBlockResolver stiltBlockResolver) {
|
StiltBlockResolver stiltBlockResolver,
|
||||||
|
IntBinaryOperator surfaceHeight,
|
||||||
|
boolean surfaceStructure) {
|
||||||
|
Objects.requireNonNull(surfaceHeight, "Structure stilts require an Iris terrain height resolver");
|
||||||
BlockPos.MutableBlockPos position = new BlockPos.MutableBlockPos();
|
BlockPos.MutableBlockPos position = new BlockPos.MutableBlockPos();
|
||||||
int structureHash = structureId == null ? 0 : structureId.hashCode();
|
int structureHash = structureId == null ? 0 : structureId.hashCode();
|
||||||
RNG rng = new RNG(world.getSeed() ^ structureHash);
|
RNG rng = new RNG(world.getSeed() ^ structureHash);
|
||||||
@@ -807,8 +812,12 @@ public final class NativeStructurePostProcessor {
|
|||||||
if (foundationY == Integer.MIN_VALUE) {
|
if (foundationY == Integer.MIN_VALUE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
int terrainY = surfaceStructure
|
||||||
|
? Math.max(area.minY(), Math.min(
|
||||||
|
area.maxY(), surfaceHeight.applyAsInt(column.x(), column.z())))
|
||||||
|
: area.minY() - 1;
|
||||||
for (int depth = 0, y = foundationY - 1;
|
for (int depth = 0, y = foundationY - 1;
|
||||||
depth < settings.getMaxDepth() && y >= area.minY(); depth++, y--) {
|
depth < settings.getMaxDepth() && y > terrainY; depth++, y--) {
|
||||||
position.set(column.x(), y, column.z());
|
position.set(column.x(), y, column.z());
|
||||||
BlockState existingState = world.getBlockState(position);
|
BlockState existingState = world.getBlockState(position);
|
||||||
boolean vegetation = existingState.is(BlockTags.LOGS) || existingState.is(BlockTags.LEAVES);
|
boolean vegetation = existingState.is(BlockTags.LOGS) || existingState.is(BlockTags.LEAVES);
|
||||||
@@ -825,8 +834,10 @@ public final class NativeStructurePostProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static StiltSupportAudit auditStiltSupport(WorldGenLevel world, BoundingBox area,
|
public static StiltSupportAudit auditStiltSupport(WorldGenLevel world, BoundingBox area,
|
||||||
StructureStart start, BlockState expectedStilt) {
|
StructureStart start, BlockState expectedStilt,
|
||||||
|
IntBinaryOperator surfaceHeight) {
|
||||||
Objects.requireNonNull(expectedStilt, "Expected stilt state must not be null");
|
Objects.requireNonNull(expectedStilt, "Expected stilt state must not be null");
|
||||||
|
Objects.requireNonNull(surfaceHeight, "Structure stilt audit requires an Iris terrain height resolver");
|
||||||
BlockPos.MutableBlockPos position = new BlockPos.MutableBlockPos();
|
BlockPos.MutableBlockPos position = new BlockPos.MutableBlockPos();
|
||||||
int baseColumns = 0;
|
int baseColumns = 0;
|
||||||
int stiltBlocks = 0;
|
int stiltBlocks = 0;
|
||||||
@@ -838,9 +849,15 @@ public final class NativeStructurePostProcessor {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
baseColumns++;
|
baseColumns++;
|
||||||
boolean grounded = foundationY == area.minY();
|
int terrainY = Math.max(area.minY(), Math.min(
|
||||||
|
area.maxY(), surfaceHeight.applyAsInt(column.x(), column.z())));
|
||||||
|
boolean grounded = foundationY <= terrainY + 1;
|
||||||
boolean stiltColumn = false;
|
boolean stiltColumn = false;
|
||||||
for (int y = foundationY - 1; y >= area.minY(); y--) {
|
for (int y = foundationY - 1; y >= area.minY(); y--) {
|
||||||
|
if (y <= terrainY) {
|
||||||
|
grounded = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
BlockState state = world.getBlockState(position.set(column.x(), y, column.z()));
|
BlockState state = world.getBlockState(position.set(column.x(), y, column.z()));
|
||||||
if (state.is(expectedStilt.getBlock())) {
|
if (state.is(expectedStilt.getBlock())) {
|
||||||
stiltBlocks++;
|
stiltBlocks++;
|
||||||
|
|||||||
+2
-1
@@ -1041,7 +1041,8 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
|||||||
String structureId, StructureStart start,
|
String structureId, StructureStart start,
|
||||||
IrisNativeStructureDecision decision) {
|
IrisNativeStructureDecision decision) {
|
||||||
NativeStructurePostProcessor.place(world, structureManager, this, random, area, chunkPos,
|
NativeStructurePostProcessor.place(world, structureManager, this, random, area, chunkPos,
|
||||||
structureId, start, decision, this::resolveStiltBlock);
|
structureId, start, decision, this::resolveStiltBlock,
|
||||||
|
(x, z) -> engine().getHeight(x, z, true) + engine().getMinHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<List<Structure>> structuresByStep(Registry<Structure> registry) {
|
private List<List<Structure>> structuresByStep(Registry<Structure> registry) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
package art.arcane.iris.modded;
|
package art.arcane.iris.modded;
|
||||||
|
|
||||||
import art.arcane.iris.core.nms.datapack.DataVersion;
|
import art.arcane.iris.core.nms.datapack.DataVersion;
|
||||||
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.engine.framework.NativeStructureGenerationPolicy;
|
import art.arcane.iris.engine.framework.NativeStructureGenerationPolicy;
|
||||||
import art.arcane.iris.engine.framework.StructureVerticalBounds;
|
import art.arcane.iris.engine.framework.StructureVerticalBounds;
|
||||||
import art.arcane.iris.engine.object.IrisDimension;
|
import art.arcane.iris.engine.object.IrisDimension;
|
||||||
@@ -44,6 +45,7 @@ import net.minecraft.world.level.block.Blocks;
|
|||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
@@ -71,6 +73,7 @@ import java.util.Optional;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
|
import java.util.function.IntBinaryOperator;
|
||||||
|
|
||||||
public final class ModdedWorldCheck {
|
public final class ModdedWorldCheck {
|
||||||
private static final int EXIT_PASS = 0;
|
private static final int EXIT_PASS = 0;
|
||||||
@@ -872,9 +875,16 @@ public final class ModdedWorldCheck {
|
|||||||
BoundingBox area = new BoundingBox(
|
BoundingBox area = new BoundingBox(
|
||||||
minimumChunkX, minimumWorldY, minimumChunkZ,
|
minimumChunkX, minimumWorldY, minimumChunkZ,
|
||||||
maximumChunkX, maximumWorldY, maximumChunkZ);
|
maximumChunkX, maximumWorldY, maximumChunkZ);
|
||||||
|
ChunkGenerator chunkGenerator = level.getChunkSource().getGenerator();
|
||||||
|
if (!(chunkGenerator instanceof IrisModdedChunkGenerator irisGenerator)) {
|
||||||
|
throw new IllegalStateException("Iris structure audit requires the Iris chunk generator");
|
||||||
|
}
|
||||||
|
Engine engine = irisGenerator.commandEngine();
|
||||||
|
IntBinaryOperator surfaceHeight = (x, z) ->
|
||||||
|
engine.getHeight(x, z, true) + engine.getMinHeight();
|
||||||
NativeStructurePostProcessor.StiltSupportAudit foundation =
|
NativeStructurePostProcessor.StiltSupportAudit foundation =
|
||||||
NativeStructurePostProcessor.auditStiltSupport(
|
NativeStructurePostProcessor.auditStiltSupport(
|
||||||
level, area, start, Blocks.COBBLESTONE.defaultBlockState());
|
level, area, start, Blocks.COBBLESTONE.defaultBlockState(), surfaceHeight);
|
||||||
foundationBaseColumns = foundation.baseColumns();
|
foundationBaseColumns = foundation.baseColumns();
|
||||||
foundationBlocks = foundation.stiltBlocks();
|
foundationBlocks = foundation.stiltBlocks();
|
||||||
foundationColumns = foundation.stiltColumns();
|
foundationColumns = foundation.stiltColumns();
|
||||||
|
|||||||
+147
-27
@@ -41,19 +41,23 @@ import art.arcane.iris.engine.object.IrisStructurePlacement;
|
|||||||
import art.arcane.iris.engine.object.IrisStructureStiltSettings;
|
import art.arcane.iris.engine.object.IrisStructureStiltSettings;
|
||||||
import art.arcane.iris.spi.IrisLogging;
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
import art.arcane.iris.spi.PlatformBlockState;
|
import art.arcane.iris.spi.PlatformBlockState;
|
||||||
|
import art.arcane.iris.util.project.matter.TileWrapper;
|
||||||
import art.arcane.iris.util.project.noise.CNG;
|
import art.arcane.iris.util.project.noise.CNG;
|
||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
import art.arcane.iris.util.project.context.ChunkContext;
|
import art.arcane.iris.util.project.context.ChunkContext;
|
||||||
import art.arcane.volmlib.util.documentation.ChunkCoordinates;
|
import art.arcane.volmlib.util.documentation.ChunkCoordinates;
|
||||||
|
import art.arcane.volmlib.util.mantle.runtime.MantleChunk;
|
||||||
|
import art.arcane.volmlib.util.matter.Matter;
|
||||||
import art.arcane.volmlib.util.matter.MatterCavern;
|
import art.arcane.volmlib.util.matter.MatterCavern;
|
||||||
|
import art.arcane.volmlib.util.matter.MatterStructurePOI;
|
||||||
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 it.unimi.dsi.fastutil.longs.Long2IntMap;
|
import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@ComponentFlag(ReservedFlag.JIGSAW)
|
@ComponentFlag(ReservedFlag.JIGSAW)
|
||||||
public class IrisStructureComponent extends IrisMantleComponent {
|
public class IrisStructureComponent extends IrisMantleComponent {
|
||||||
@@ -159,12 +163,13 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
|||||||
}
|
}
|
||||||
requireAppliedPieces(resolved, cx, cz, failedPieces);
|
requireAppliedPieces(resolved, cx, cz, failedPieces);
|
||||||
if (failedPieces == 0 && placement.getStilt() != null) {
|
if (failedPieces == 0 && placement.getStilt() != null) {
|
||||||
placeFoundation(writer, foundationColumns, placement.getStilt(), rng);
|
placeFoundation(writer, foundationColumns, placement.getStilt(), rng, !placement.isUnderground());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void placeFoundation(MantleWriter writer, Long2IntOpenHashMap columns,
|
private void placeFoundation(MantleWriter writer, Long2IntOpenHashMap columns,
|
||||||
IrisStructureStiltSettings settings, RNG rng) {
|
IrisStructureStiltSettings settings, RNG rng,
|
||||||
|
boolean surfaceStructure) {
|
||||||
IrisMaterialPalette palette = Objects.requireNonNull(
|
IrisMaterialPalette palette = Objects.requireNonNull(
|
||||||
settings.getPalette(), "Structure stilt palette must not be null");
|
settings.getPalette(), "Structure stilt palette must not be null");
|
||||||
int mantleOffset = getEngineMantle().getEngine().getMinHeight();
|
int mantleOffset = getEngineMantle().getEngine().getMinHeight();
|
||||||
@@ -181,10 +186,17 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
|||||||
int terrainHeight = getEngineMantle().trueHeight(worldX, worldZ);
|
int terrainHeight = getEngineMantle().trueHeight(worldX, worldZ);
|
||||||
int groundY = StructureFoundationPlanner.findGroundY(
|
int groundY = StructureFoundationPlanner.findGroundY(
|
||||||
foundationY, maxDepth, 0,
|
foundationY, maxDepth, 0,
|
||||||
y -> StructureFoundationPlanner.isGroundSolid(
|
y -> {
|
||||||
writer.getDataIfPresent(worldX, y, worldZ, PlatformBlockState.class),
|
PlatformBlockState overlay = writer.getDataIfPresent(
|
||||||
writer.getDataIfPresent(worldX, y, worldZ, MatterCavern.class) != null,
|
worldX, y, worldZ, PlatformBlockState.class);
|
||||||
y, terrainHeight));
|
boolean carved = writer.getDataIfPresent(
|
||||||
|
worldX, y, worldZ, MatterCavern.class) != null;
|
||||||
|
return surfaceStructure
|
||||||
|
? StructureFoundationPlanner.isSurfaceSupportBoundary(
|
||||||
|
overlay, carved, y, terrainHeight)
|
||||||
|
: StructureFoundationPlanner.isGroundSolid(
|
||||||
|
overlay, carved, y, terrainHeight);
|
||||||
|
});
|
||||||
if (groundY == StructureFoundationPlanner.NO_GROUND) {
|
if (groundY == StructureFoundationPlanner.NO_GROUND) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -398,6 +410,7 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
|||||||
int mantleOffset = getEngineMantle().getEngine().getMinHeight();
|
int mantleOffset = getEngineMantle().getEngine().getMinHeight();
|
||||||
int worldHeight = getEngineMantle().getEngine().getHeight();
|
int worldHeight = getEngineMantle().getEngine().getHeight();
|
||||||
int verticalTolerance = resolved.exactY() ? 0 : DYNAMIC_STRUCTURE_Y_TOLERANCE;
|
int verticalTolerance = resolved.exactY() ? 0 : DYNAMIC_STRUCTURE_Y_TOLERANCE;
|
||||||
|
Map<String, ObjectMarkerBounds> intersectingObjects = new HashMap<>();
|
||||||
for (PlacedStructurePiece piece : resolved.pieces()) {
|
for (PlacedStructurePiece piece : resolved.pieces()) {
|
||||||
int minY = Math.max(0, piece.getMinY() - mantleOffset - verticalTolerance);
|
int minY = Math.max(0, piece.getMinY() - mantleOffset - verticalTolerance);
|
||||||
int maxY = Math.min(worldHeight - 1, piece.getMaxY() - mantleOffset + verticalTolerance);
|
int maxY = Math.min(worldHeight - 1, piece.getMaxY() - mantleOffset + verticalTolerance);
|
||||||
@@ -406,15 +419,19 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
|||||||
}
|
}
|
||||||
for (int x = piece.getMinX(); x <= piece.getMaxX(); x++) {
|
for (int x = piece.getMinX(); x <= piece.getMaxX(); x++) {
|
||||||
for (int z = piece.getMinZ(); z <= piece.getMaxZ(); z++) {
|
for (int z = piece.getMinZ(); z <= piece.getMaxZ(); z++) {
|
||||||
clearIntersectingObjectTreeColumn(writer, x, z, minY, maxY, worldHeight);
|
collectIntersectingObjectTreeMarkers(
|
||||||
|
writer, x, z, minY, maxY, intersectingObjects);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (Map.Entry<String, ObjectMarkerBounds> entry : intersectingObjects.entrySet()) {
|
||||||
|
clearMarkerOwnedObject(writer, entry.getKey(), entry.getValue(), worldHeight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearIntersectingObjectTreeColumn(MantleWriter writer, int x, int z,
|
private void collectIntersectingObjectTreeMarkers(MantleWriter writer, int x, int z,
|
||||||
int minY, int maxY, int worldHeight) {
|
int minY, int maxY,
|
||||||
Set<String> intersectingMarkers = null;
|
Map<String, ObjectMarkerBounds> intersectingObjects) {
|
||||||
for (int y = minY; y <= maxY; y++) {
|
for (int y = minY; y <= maxY; y++) {
|
||||||
PlatformBlockState state = writer.getDataIfPresent(x, y, z, PlatformBlockState.class);
|
PlatformBlockState state = writer.getDataIfPresent(x, y, z, PlatformBlockState.class);
|
||||||
if (state == null || !state.isTreeBlock()) {
|
if (state == null || !state.isTreeBlock()) {
|
||||||
@@ -422,26 +439,52 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
|||||||
}
|
}
|
||||||
String marker = writer.getDataIfPresent(x, y, z, String.class);
|
String marker = writer.getDataIfPresent(x, y, z, String.class);
|
||||||
if (isOrdinaryObjectMarker(marker)) {
|
if (isOrdinaryObjectMarker(marker)) {
|
||||||
if (intersectingMarkers == null) {
|
intersectingObjects.computeIfAbsent(marker, ignored -> new ObjectMarkerBounds())
|
||||||
intersectingMarkers = new HashSet<>();
|
.include(x, y, z);
|
||||||
}
|
|
||||||
intersectingMarkers.add(marker);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (intersectingMarkers == null) {
|
}
|
||||||
|
|
||||||
|
private void clearMarkerOwnedObject(MantleWriter writer, String marker,
|
||||||
|
ObjectMarkerBounds intersections, int worldHeight) {
|
||||||
|
StructurePlacementMarker.Decoded decoded = StructurePlacementMarker.decode(marker);
|
||||||
|
if (decoded == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int y = 0; y < worldHeight; y++) {
|
IrisObject object = getData().load(IrisObject.class, decoded.objectKey(), false);
|
||||||
String marker = writer.getDataIfPresent(x, y, z, String.class);
|
if (object == null) {
|
||||||
if (!intersectingMarkers.contains(marker)) {
|
return;
|
||||||
continue;
|
}
|
||||||
|
int horizontalSpan = Math.max(1, Math.max(object.getW(), object.getD()));
|
||||||
|
int verticalSpan = Math.max(1, object.getH());
|
||||||
|
ObjectMarkerBounds search = intersections.expand(horizontalSpan - 1, verticalSpan - 1, worldHeight);
|
||||||
|
KList<ObjectBlockPosition> positions = new KList<>();
|
||||||
|
int minChunkX = Math.floorDiv(search.minX, 16);
|
||||||
|
int maxChunkX = Math.floorDiv(search.maxX, 16);
|
||||||
|
int minChunkZ = Math.floorDiv(search.minZ, 16);
|
||||||
|
int maxChunkZ = Math.floorDiv(search.maxZ, 16);
|
||||||
|
for (int chunkX = minChunkX; chunkX <= maxChunkX; chunkX++) {
|
||||||
|
for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; chunkZ++) {
|
||||||
|
MantleChunk<Matter> chunk = writer.acquireChunk(chunkX, chunkZ);
|
||||||
|
if (chunk == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int blockX = chunkX << 4;
|
||||||
|
int blockZ = chunkZ << 4;
|
||||||
|
chunk.iterate(String.class, (localX, y, localZ, value) -> {
|
||||||
|
int x = blockX + localX;
|
||||||
|
int z = blockZ + localZ;
|
||||||
|
if (marker.equals(value) && search.contains(x, y, z)) {
|
||||||
|
positions.add(new ObjectBlockPosition(x, y, z));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
PlatformBlockState state = writer.getDataIfPresent(x, y, z, PlatformBlockState.class);
|
}
|
||||||
if (state == null || !state.isTreeBlock()) {
|
for (ObjectBlockPosition position : positions) {
|
||||||
continue;
|
writer.clearBlock(position.x(), position.y(), position.z());
|
||||||
}
|
writer.clearData(position.x(), position.y(), position.z(), String.class);
|
||||||
writer.clearBlock(x, y, z);
|
writer.clearData(position.x(), position.y(), position.z(), TileWrapper.class);
|
||||||
writer.clearData(x, y, z, String.class);
|
writer.clearData(position.x(), position.y(), position.z(), MatterStructurePOI.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,6 +493,21 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
|||||||
return decoded != null && !decoded.structureAware();
|
return decoded != null && !decoded.structureAware();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ObjectMarkerBounds markerSearchBounds(int minX, int minY, int minZ,
|
||||||
|
int maxX, int maxY, int maxZ,
|
||||||
|
int horizontalSpan, int verticalSpan,
|
||||||
|
int worldHeight) {
|
||||||
|
ObjectMarkerBounds bounds = new ObjectMarkerBounds();
|
||||||
|
bounds.minX = minX;
|
||||||
|
bounds.minY = minY;
|
||||||
|
bounds.minZ = minZ;
|
||||||
|
bounds.maxX = maxX;
|
||||||
|
bounds.maxY = maxY;
|
||||||
|
bounds.maxZ = maxZ;
|
||||||
|
return bounds.expand(
|
||||||
|
Math.max(0, horizontalSpan - 1), Math.max(0, verticalSpan - 1), worldHeight);
|
||||||
|
}
|
||||||
|
|
||||||
private int[] computePieceBounds(KList<PlacedStructurePiece> pieces) {
|
private int[] computePieceBounds(KList<PlacedStructurePiece> pieces) {
|
||||||
if (pieces == null || pieces.isEmpty()) {
|
if (pieces == null || pieces.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -548,4 +606,66 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
|||||||
}
|
}
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final class ObjectMarkerBounds {
|
||||||
|
private int minX = Integer.MAX_VALUE;
|
||||||
|
private int minY = Integer.MAX_VALUE;
|
||||||
|
private int minZ = Integer.MAX_VALUE;
|
||||||
|
private int maxX = Integer.MIN_VALUE;
|
||||||
|
private int maxY = Integer.MIN_VALUE;
|
||||||
|
private int maxZ = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
void include(int x, int y, int z) {
|
||||||
|
minX = Math.min(minX, x);
|
||||||
|
minY = Math.min(minY, y);
|
||||||
|
minZ = Math.min(minZ, z);
|
||||||
|
maxX = Math.max(maxX, x);
|
||||||
|
maxY = Math.max(maxY, y);
|
||||||
|
maxZ = Math.max(maxZ, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectMarkerBounds expand(int horizontal, int vertical, int worldHeight) {
|
||||||
|
ObjectMarkerBounds expanded = new ObjectMarkerBounds();
|
||||||
|
expanded.minX = minX - horizontal;
|
||||||
|
expanded.minY = Math.max(0, minY - vertical);
|
||||||
|
expanded.minZ = minZ - horizontal;
|
||||||
|
expanded.maxX = maxX + horizontal;
|
||||||
|
expanded.maxY = Math.min(worldHeight - 1, maxY + vertical);
|
||||||
|
expanded.maxZ = maxZ + horizontal;
|
||||||
|
return expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean contains(int x, int y, int z) {
|
||||||
|
return x >= minX && x <= maxX
|
||||||
|
&& y >= minY && y <= maxY
|
||||||
|
&& z >= minZ && z <= maxZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minX() {
|
||||||
|
return minX;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minY() {
|
||||||
|
return minY;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minZ() {
|
||||||
|
return minZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxX() {
|
||||||
|
return maxX;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxY() {
|
||||||
|
return maxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxZ() {
|
||||||
|
return maxZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record ObjectBlockPosition(int x, int y, int z) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+5
@@ -47,6 +47,11 @@ final class StructureFoundationPlanner {
|
|||||||
return !carved && mantleY <= terrainHeight;
|
return !carved && mantleY <= terrainHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isSurfaceSupportBoundary(PlatformBlockState overlay, boolean carved,
|
||||||
|
int mantleY, int terrainHeight) {
|
||||||
|
return carved || isGroundSolid(overlay, false, mantleY, terrainHeight);
|
||||||
|
}
|
||||||
|
|
||||||
static int fillSupportColumn(int foundationY, int groundY, IntConsumer supportAtY) {
|
static int fillSupportColumn(int foundationY, int groundY, IntConsumer supportAtY) {
|
||||||
if (groundY == NO_GROUND || groundY >= foundationY - 1) {
|
if (groundY == NO_GROUND || groundY >= foundationY - 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+22
@@ -58,4 +58,26 @@ public class IrisStructureComponentOverboreTest {
|
|||||||
"@iris-structure:v1:dHJlZXMvb2Fr:42:bWluZWNyYWZ0Om1hbnNpb24"));
|
"@iris-structure:v1:dHJlZXMvb2Fr:42:bWluZWNyYWZ0Om1hbnNpb24"));
|
||||||
assertFalse(IrisStructureComponent.isOrdinaryObjectMarker("not-a-marker"));
|
assertFalse(IrisStructureComponent.isOrdinaryObjectMarker("not-a-marker"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void collidingObjectSearchCoversTheWholeMarkerOwnedObject() {
|
||||||
|
IrisStructureComponent.ObjectMarkerBounds bounds = IrisStructureComponent.markerSearchBounds(
|
||||||
|
20, 64, -8, 21, 66, -7, 7, 12, 384);
|
||||||
|
|
||||||
|
assertEquals(14, bounds.minX());
|
||||||
|
assertEquals(53, bounds.minY());
|
||||||
|
assertEquals(-14, bounds.minZ());
|
||||||
|
assertEquals(27, bounds.maxX());
|
||||||
|
assertEquals(77, bounds.maxY());
|
||||||
|
assertEquals(-1, bounds.maxZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void collidingObjectSearchClampsToTheWorldHeight() {
|
||||||
|
IrisStructureComponent.ObjectMarkerBounds bounds = IrisStructureComponent.markerSearchBounds(
|
||||||
|
0, 2, 0, 0, 379, 0, 1, 12, 384);
|
||||||
|
|
||||||
|
assertEquals(0, bounds.minY());
|
||||||
|
assertEquals(383, bounds.maxY());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+13
@@ -59,6 +59,19 @@ public class StructureFoundationPlannerTest {
|
|||||||
assertTrue(StructureFoundationPlanner.isGroundSolid(null, true, 0, -20));
|
assertTrue(StructureFoundationPlanner.isGroundSolid(null, true, 0, -20));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void surfaceSupportStopsAtCarvedCaveBoundary() {
|
||||||
|
PlatformBlockState solid = mock(PlatformBlockState.class);
|
||||||
|
when(solid.isSolid()).thenReturn(true);
|
||||||
|
PlatformBlockState air = mock(PlatformBlockState.class);
|
||||||
|
when(air.isSolid()).thenReturn(false);
|
||||||
|
|
||||||
|
assertTrue(StructureFoundationPlanner.isSurfaceSupportBoundary(null, true, 18, 24));
|
||||||
|
assertTrue(StructureFoundationPlanner.isSurfaceSupportBoundary(solid, false, 30, 24));
|
||||||
|
assertFalse(StructureFoundationPlanner.isSurfaceSupportBoundary(air, false, 30, 24));
|
||||||
|
assertTrue(StructureFoundationPlanner.isSurfaceSupportBoundary(null, false, 24, 24));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void fillsOnlyTheGapBetweenTheFoundationAndGround() {
|
public void fillsOnlyTheGapBetweenTheFoundationAndGround() {
|
||||||
List<Integer> written = new ArrayList<>();
|
List<Integer> written = new ArrayList<>();
|
||||||
|
|||||||
Reference in new issue
Block a user