mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-07-25 00:00:33 +00:00
Fixes
This commit is contained in:
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Servers
|
||||
* Copyright (c) 2026 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.core.structure;
|
||||
|
||||
public final class NativeStructureLocateCapability {
|
||||
private static final String MONUMENT_KEY = "minecraft:monument";
|
||||
private static final String UNAVAILABLE_MESSAGE = "Native monument generation is enabled, but synchronous monument locating is unavailable because a cold search can stall the server thread. The locate request was not run.";
|
||||
|
||||
private NativeStructureLocateCapability() {
|
||||
}
|
||||
|
||||
public static boolean isPaperUnavailable(String structureKey) {
|
||||
return structureKey != null && MONUMENT_KEY.equalsIgnoreCase(structureKey.trim());
|
||||
}
|
||||
|
||||
public static String unavailableMessage() {
|
||||
return UNAVAILABLE_MESSAGE;
|
||||
}
|
||||
}
|
||||
+27
-24
@@ -41,6 +41,8 @@ import art.arcane.iris.engine.object.IrisStructurePlacement;
|
||||
import art.arcane.iris.engine.object.IrisStructureStiltSettings;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.common.data.B;
|
||||
import art.arcane.iris.util.common.math.IrisBlockVector;
|
||||
import art.arcane.iris.util.project.matter.TileWrapper;
|
||||
import art.arcane.iris.util.project.noise.CNG;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
@@ -67,7 +69,6 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
||||
private static final double OVERBORE_MIN_BOUNDARY_SQUARED = OVERBORE_MIN_BOUNDARY * OVERBORE_MIN_BOUNDARY;
|
||||
private static final double OVERBORE_BOUNDARY_SPAN = 0.8;
|
||||
private static final double OVERBORE_MAX_UP_REACH = 1.8;
|
||||
private static final int DYNAMIC_STRUCTURE_Y_TOLERANCE = 32;
|
||||
private static final MatterCavern CARVE_CAVERN = new MatterCavern(true, "", (byte) 3);
|
||||
|
||||
public IrisStructureComponent(EngineMantle engineMantle) {
|
||||
@@ -409,18 +410,19 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
||||
private void clearIntersectingObjectTrees(MantleWriter writer, IrisStructureLocator.ResolvedPlacement resolved) {
|
||||
int mantleOffset = getEngineMantle().getEngine().getMinHeight();
|
||||
int worldHeight = getEngineMantle().getEngine().getHeight();
|
||||
int verticalTolerance = resolved.exactY() ? 0 : DYNAMIC_STRUCTURE_Y_TOLERANCE;
|
||||
Map<String, ObjectMarkerBounds> intersectingObjects = new HashMap<>();
|
||||
for (PlacedStructurePiece piece : resolved.pieces()) {
|
||||
int minY = Math.max(0, piece.getMinY() - mantleOffset - verticalTolerance);
|
||||
int maxY = Math.min(worldHeight - 1, piece.getMaxY() - mantleOffset + verticalTolerance);
|
||||
if (minY > maxY) {
|
||||
continue;
|
||||
}
|
||||
for (int x = piece.getMinX(); x <= piece.getMaxX(); x++) {
|
||||
for (int z = piece.getMinZ(); z <= piece.getMaxZ(); z++) {
|
||||
collectIntersectingObjectTreeMarkers(
|
||||
writer, x, z, minY, maxY, intersectingObjects);
|
||||
for (IrisBlockVector local : piece.getObject().getBlocks().keys()) {
|
||||
PlatformBlockState structureState = piece.getObject().getBlocks().get(local);
|
||||
if (!isOccupiedStructureState(structureState)) {
|
||||
continue;
|
||||
}
|
||||
IrisBlockVector rotated = piece.getRotation().rotate(local.clone());
|
||||
int y = piece.getY() - mantleOffset + rotated.getBlockY();
|
||||
if (y >= 0 && y < worldHeight) {
|
||||
collectIntersectingObjectTreeMarker(
|
||||
writer, piece.getX() + rotated.getBlockX(), y,
|
||||
piece.getZ() + rotated.getBlockZ(), intersectingObjects);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -429,19 +431,20 @@ public class IrisStructureComponent extends IrisMantleComponent {
|
||||
}
|
||||
}
|
||||
|
||||
private void collectIntersectingObjectTreeMarkers(MantleWriter writer, int x, int z,
|
||||
int minY, int maxY,
|
||||
Map<String, ObjectMarkerBounds> intersectingObjects) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
PlatformBlockState state = writer.getDataIfPresent(x, y, z, PlatformBlockState.class);
|
||||
if (state == null || !state.isTreeBlock()) {
|
||||
continue;
|
||||
}
|
||||
String marker = writer.getDataIfPresent(x, y, z, String.class);
|
||||
if (isOrdinaryObjectMarker(marker)) {
|
||||
intersectingObjects.computeIfAbsent(marker, ignored -> new ObjectMarkerBounds())
|
||||
.include(x, y, z);
|
||||
}
|
||||
static boolean isOccupiedStructureState(PlatformBlockState state) {
|
||||
return !B.isAir(state);
|
||||
}
|
||||
|
||||
private void collectIntersectingObjectTreeMarker(MantleWriter writer, int x, int y, int z,
|
||||
Map<String, ObjectMarkerBounds> intersectingObjects) {
|
||||
PlatformBlockState state = writer.getDataIfPresent(x, y, z, PlatformBlockState.class);
|
||||
if (state == null || !state.isTreeBlock()) {
|
||||
return;
|
||||
}
|
||||
String marker = writer.getDataIfPresent(x, y, z, String.class);
|
||||
if (isOrdinaryObjectMarker(marker)) {
|
||||
intersectingObjects.computeIfAbsent(marker, ignored -> new ObjectMarkerBounds())
|
||||
.include(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ public class IrisBiome extends IrisRegistrant implements IRare {
|
||||
@Desc("The raw derivative of this biome. This is required or the terrain will not properly generate. Use any vanilla biome type. Look in examples/biome-list.txt")
|
||||
private String derivative = "minecraft:the_void";
|
||||
@Required
|
||||
@Desc("Override the derivative when vanilla places structures to this derivative. This is useful for example if you have an ocean biome, but you have set the derivative to desert to get a brown-ish color. To prevent desert structures from spawning on top of your ocean, you can set your vanillaDerivative to ocean, to allow for vanilla structures. Not defining this value will simply select the derivative.")
|
||||
@Desc("Override the derivative used for vanilla structure selection. Iris still enforces the generated terrain role: land-only Minecraft derivatives on sea biomes expose no native structure biome, and land-only derivatives on shore biomes resolve as beach, while exact ocean, river, beach, and shore variants remain eligible. Non-Minecraft namespaces remain authoritative. Not defining this value selects derivative.")
|
||||
private String vanillaDerivative = null;
|
||||
@ArrayType(min = 1, type = String.class)
|
||||
@Desc("You can instead specify multiple biome derivatives to randomly scatter colors in this biome")
|
||||
@@ -315,6 +315,20 @@ public class IrisBiome extends IrisRegistrant implements IRare {
|
||||
return resolved == null ? namespacedBiomeKey(derivative) : resolved;
|
||||
}
|
||||
|
||||
public String getStructureDerivativeKey() {
|
||||
String key = getVanillaDerivativeKey();
|
||||
if (key == null || !key.startsWith("minecraft:")) {
|
||||
return key;
|
||||
}
|
||||
if (isSea() && !isVanillaSeaStructureBiome(key)) {
|
||||
return "minecraft:the_void";
|
||||
}
|
||||
if (isShore() && !isVanillaShoreStructureBiome(key)) {
|
||||
return "minecraft:beach";
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getDerivativeKey() {
|
||||
return namespacedBiomeKey(derivative);
|
||||
}
|
||||
@@ -327,6 +341,14 @@ public class IrisBiome extends IrisRegistrant implements IRare {
|
||||
return trimmed.indexOf(':') >= 0 ? trimmed : "minecraft:" + trimmed;
|
||||
}
|
||||
|
||||
static boolean isVanillaSeaStructureBiome(String key) {
|
||||
return key != null && (key.contains("ocean") || key.endsWith("river"));
|
||||
}
|
||||
|
||||
static boolean isVanillaShoreStructureBiome(String key) {
|
||||
return key != null && (key.endsWith("beach") || key.endsWith("shore"));
|
||||
}
|
||||
|
||||
private KList<Biome> getBiomeScatterResolved() {
|
||||
return biomeScatterResolved.aquire(() -> resolveBiomeKeys(biomeScatter));
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class IrisImportedStructureControl {
|
||||
private boolean datapackOverrides = true;
|
||||
|
||||
@ArrayType(type = IrisVanillaStructureAdjustment.class, min = 1)
|
||||
@Desc("Per-structure adjustments applied to vanilla, mod, and datapack structures that still generate natively. Vertical shifts from every matching entry stack. Surface-intersecting structures clear logs and leaves automatically; a matching vegetation option can force clearing for unusual placements. The last matching entry with stilt settings controls foundation columns. A structure suppressed by an Iris placement is unaffected.")
|
||||
@Desc("Per-structure adjustments applied to vanilla, mod, and datapack structures that still generate natively. Vertical shifts from every matching entry stack. A matching vegetation option explicitly clears logs and leaves inside structure piece bounds. The last matching entry with stilt settings controls foundation columns. A structure suppressed by an Iris placement is unaffected.")
|
||||
private KList<IrisVanillaStructureAdjustment> adjustments = new KList<>();
|
||||
|
||||
public boolean shouldGenerate(String key) {
|
||||
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Servers
|
||||
* Copyright (c) 2026 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.core.structure;
|
||||
|
||||
import art.arcane.iris.engine.object.IrisImportedStructureControl;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class NativeStructureLocateCapabilityTest {
|
||||
@Test
|
||||
public void monumentLocateIsUnavailableWithoutChangingGenerationPolicy() {
|
||||
assertTrue(NativeStructureLocateCapability.isPaperUnavailable("minecraft:monument"));
|
||||
assertTrue(NativeStructureLocateCapability.isPaperUnavailable(" MINECRAFT:MONUMENT "));
|
||||
assertTrue(new IrisImportedStructureControl().shouldGenerate("minecraft:monument"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void otherStructuresRemainLocatable() {
|
||||
assertFalse(NativeStructureLocateCapability.isPaperUnavailable(null));
|
||||
assertFalse(NativeStructureLocateCapability.isPaperUnavailable(""));
|
||||
assertFalse(NativeStructureLocateCapability.isPaperUnavailable("minecraft:stronghold"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messageStatesThatGenerationRemainsEnabled() {
|
||||
String message = NativeStructureLocateCapability.unavailableMessage().toLowerCase();
|
||||
assertTrue(message.contains("generation is enabled"));
|
||||
assertTrue(message.contains("locat"));
|
||||
}
|
||||
}
|
||||
+12
@@ -41,6 +41,18 @@ public class IrisStructureComponentMarkerTest {
|
||||
assertNotEquals(first, moved);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void treeCollisionUsesOnlyNonAirStructureBlocks() {
|
||||
PlatformBlockState solid = mock(PlatformBlockState.class);
|
||||
PlatformBlockState air = mock(PlatformBlockState.class);
|
||||
when(solid.isAir()).thenReturn(false);
|
||||
when(air.isAir()).thenReturn(true);
|
||||
|
||||
assertTrue(IrisStructureComponent.isOccupiedStructureState(solid));
|
||||
assertFalse(IrisStructureComponent.isOccupiedStructureState(air));
|
||||
assertFalse(IrisStructureComponent.isOccupiedStructureState(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyResolvedPiecesRemainSkippableForNonReplacement() {
|
||||
IrisStructureLocator.ResolvedPlacement resolved = resolvedPlacement(
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package art.arcane.iris.engine.object;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class IrisBiomeStructureDerivativeTest {
|
||||
@Test
|
||||
public void seaBiomeRejectsLandOnlyVanillaDerivativeForStructures() {
|
||||
IrisBiome biome = new IrisBiome()
|
||||
.setDerivative("minecraft:warm_ocean")
|
||||
.setVanillaDerivative("minecraft:desert")
|
||||
.setInferredType(InferredType.SEA);
|
||||
|
||||
assertEquals("minecraft:desert", biome.getVanillaDerivativeKey());
|
||||
assertEquals("minecraft:the_void", biome.getStructureDerivativeKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shoreBiomeRejectsLandOnlyVanillaDerivativeForStructures() {
|
||||
IrisBiome biome = new IrisBiome()
|
||||
.setDerivative("minecraft:warm_ocean")
|
||||
.setVanillaDerivative("minecraft:savanna")
|
||||
.setInferredType(InferredType.SHORE);
|
||||
|
||||
assertEquals("minecraft:beach", biome.getStructureDerivativeKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void waterStructureDerivativesKeepTheirExactVariant() {
|
||||
IrisBiome deepOcean = new IrisBiome()
|
||||
.setVanillaDerivative("minecraft:deep_cold_ocean")
|
||||
.setInferredType(InferredType.SEA);
|
||||
IrisBiome snowyBeach = new IrisBiome()
|
||||
.setVanillaDerivative("minecraft:snowy_beach")
|
||||
.setInferredType(InferredType.SHORE);
|
||||
|
||||
assertEquals("minecraft:deep_cold_ocean", deepOcean.getStructureDerivativeKey());
|
||||
assertEquals("minecraft:snowy_beach", snowyBeach.getStructureDerivativeKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void seaAndShoreDoNotBorrowEachOthersStructureBiomes() {
|
||||
IrisBiome seaBeach = new IrisBiome()
|
||||
.setVanillaDerivative("minecraft:beach")
|
||||
.setInferredType(InferredType.SEA);
|
||||
IrisBiome shoreOcean = new IrisBiome()
|
||||
.setVanillaDerivative("minecraft:ocean")
|
||||
.setInferredType(InferredType.SHORE);
|
||||
|
||||
assertEquals("minecraft:the_void", seaBeach.getStructureDerivativeKey());
|
||||
assertEquals("minecraft:beach", shoreOcean.getStructureDerivativeKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void landAndModdedDerivativesRemainAuthoritative() {
|
||||
IrisBiome land = new IrisBiome()
|
||||
.setVanillaDerivative("minecraft:desert")
|
||||
.setInferredType(InferredType.LAND);
|
||||
IrisBiome moddedSea = new IrisBiome()
|
||||
.setVanillaDerivative("example:abyss")
|
||||
.setInferredType(InferredType.SEA);
|
||||
|
||||
assertEquals("minecraft:desert", land.getStructureDerivativeKey());
|
||||
assertEquals("example:abyss", moddedSea.getStructureDerivativeKey());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user