mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-22 08:07:42 +00:00
Merge terrain-first hydrology into master
Surface rivers v2: valley-first eroded channels, spring pools, standing pools, tributaries, bed padding, ring-ordered feature search, schema v2 hydrology configuration and the transect probe.
This commit is contained in:
commit
665b201e41
330 files changed
+60150
-606
No files matched your search
+145
@@ -0,0 +1,145 @@
|
||||
package art.arcane.iris.api.terrain;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class IrisColumnSampleTest {
|
||||
@Test
|
||||
public void unavailableFieldsHaveUnambiguousSentinels() {
|
||||
IrisColumnSample sample = sample(
|
||||
IrisColumnSample.UNAVAILABLE_HEIGHT,
|
||||
IrisColumnSample.UNAVAILABLE_HEIGHT,
|
||||
IrisSurfaceKind.UNKNOWN,
|
||||
null,
|
||||
IrisRiverState.NONE,
|
||||
IrisColumnSample.UNAVAILABLE_RIVER_DISTANCE,
|
||||
IrisColumnSample.UNAVAILABLE_RIVER_FLOW,
|
||||
IrisColumnSample.UNAVAILABLE_HEIGHT
|
||||
);
|
||||
|
||||
assertFalse(sample.hasSurfaceHeight());
|
||||
assertFalse(sample.hasNaturalHeight());
|
||||
assertFalse(sample.hasSurfaceKind());
|
||||
assertFalse(sample.hasBiomeKey());
|
||||
assertFalse(sample.hasRiverState());
|
||||
assertFalse(sample.hasRiverDistance());
|
||||
assertFalse(sample.hasRiverFlow());
|
||||
assertFalse(sample.hasRiverWaterSurfaceY());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void negativeWorldHeightsRemainAvailableValues() {
|
||||
IrisColumnSample sample = sample(
|
||||
-1,
|
||||
-64,
|
||||
IrisSurfaceKind.DRY_CHANNEL,
|
||||
"test:river",
|
||||
IrisRiverState.DRY,
|
||||
0D,
|
||||
0,
|
||||
-1
|
||||
);
|
||||
|
||||
assertTrue(sample.hasSurfaceHeight());
|
||||
assertTrue(sample.hasNaturalHeight());
|
||||
assertTrue(sample.hasSurfaceKind());
|
||||
assertTrue(sample.hasBiomeKey());
|
||||
assertTrue(sample.hasRiverState());
|
||||
assertTrue(sample.hasRiverDistance());
|
||||
assertTrue(sample.hasRiverFlow());
|
||||
assertTrue(sample.hasRiverWaterSurfaceY());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blankBiomeKeysNormalizeToUnavailable() {
|
||||
IrisColumnSample sample = sample(
|
||||
64,
|
||||
65,
|
||||
IrisSurfaceKind.LAND,
|
||||
" ",
|
||||
IrisRiverState.NONE,
|
||||
IrisColumnSample.UNAVAILABLE_RIVER_DISTANCE,
|
||||
IrisColumnSample.UNAVAILABLE_RIVER_FLOW,
|
||||
IrisColumnSample.UNAVAILABLE_HEIGHT
|
||||
);
|
||||
|
||||
assertNull(sample.biomeKey());
|
||||
assertFalse(sample.hasBiomeKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theSinkReceivesTheTypedSample() {
|
||||
IrisColumnSample sample = sample(
|
||||
64,
|
||||
65,
|
||||
IrisSurfaceKind.RIVER,
|
||||
"test:river",
|
||||
IrisRiverState.WET,
|
||||
0.5D,
|
||||
3,
|
||||
67
|
||||
);
|
||||
AtomicReference<IrisColumnSample> received = new AtomicReference<>();
|
||||
IrisColumnSink sink = received::set;
|
||||
|
||||
sink.accept(sample);
|
||||
|
||||
assertSame(sample, received.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidHydrologyValuesAreRejected() {
|
||||
assertInvalid(Double.POSITIVE_INFINITY, 1);
|
||||
assertInvalid(-0.1D, 1);
|
||||
assertInvalid(0D, -2);
|
||||
}
|
||||
|
||||
private static void assertInvalid(double distance, int flow) {
|
||||
try {
|
||||
sample(
|
||||
64,
|
||||
65,
|
||||
IrisSurfaceKind.RIVER,
|
||||
"test:river",
|
||||
IrisRiverState.WET,
|
||||
distance,
|
||||
flow,
|
||||
67
|
||||
);
|
||||
fail("Expected invalid hydrology values to be rejected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(expected.getMessage().startsWith("river"));
|
||||
}
|
||||
}
|
||||
|
||||
private static IrisColumnSample sample(
|
||||
int surfaceHeight,
|
||||
int naturalHeight,
|
||||
IrisSurfaceKind surfaceKind,
|
||||
String biomeKey,
|
||||
IrisRiverState riverState,
|
||||
double riverDistance,
|
||||
int riverFlow,
|
||||
int riverWaterSurfaceY
|
||||
) {
|
||||
return new IrisColumnSample(
|
||||
12,
|
||||
-7,
|
||||
surfaceHeight,
|
||||
naturalHeight,
|
||||
surfaceKind,
|
||||
biomeKey,
|
||||
riverState,
|
||||
riverDistance,
|
||||
riverFlow,
|
||||
riverWaterSurfaceY
|
||||
);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package art.arcane.iris.core.commands;
|
||||
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.util.common.director.specialhandlers.ReachableBiomeHandler;
|
||||
import art.arcane.volmlib.util.director.annotations.Param;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class CommandFindBiomeContractTest {
|
||||
@Test
|
||||
public void biomeLookupUsesReachableBiomeHandler() throws Exception {
|
||||
Method method = CommandFind.class.getMethod("biome", IrisBiome.class, boolean.class);
|
||||
Param parameter = method.getParameters()[0].getAnnotation(Param.class);
|
||||
|
||||
assertEquals(ReachableBiomeHandler.class, parameter.customHandler());
|
||||
}
|
||||
}
|
||||
+12
-1
@@ -1,8 +1,10 @@
|
||||
package art.arcane.iris.core.commands;
|
||||
|
||||
import art.arcane.iris.engine.IrisComplex;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.object.IObjectPlacer;
|
||||
import art.arcane.iris.engine.object.IrisDimension;
|
||||
import art.arcane.iris.util.project.stream.ProceduralStream;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@@ -13,22 +15,31 @@ import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class CommandObjectFluidHeightTest {
|
||||
@Test
|
||||
public void absoluteObjectPlacementShiftsFluidHeightFromNegativeMinY() {
|
||||
public void absoluteObjectPlacementShiftsTheColumnRiverHeadFromNegativeMinY() {
|
||||
World world = mock(World.class);
|
||||
Engine engine = mock(Engine.class);
|
||||
IrisDimension dimension = mock(IrisDimension.class);
|
||||
IrisComplex complex = mock(IrisComplex.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
ProceduralStream<Double> riverHead = mock(ProceduralStream.class);
|
||||
Map<Block, BlockData> future = new HashMap<>();
|
||||
|
||||
when(engine.getMinHeight()).thenReturn(-64);
|
||||
when(engine.getDimension()).thenReturn(dimension);
|
||||
when(engine.getComplex()).thenReturn(complex);
|
||||
when(dimension.getFluidHeight()).thenReturn(127);
|
||||
when(complex.getRiverWaterSurfaceStream()).thenReturn(riverHead);
|
||||
when(riverHead.get(12, -7)).thenReturn(131D);
|
||||
|
||||
IObjectPlacer placer = CommandObject.createPlacer(world, future, engine);
|
||||
|
||||
assertEquals(63, placer.getFluidHeight());
|
||||
assertEquals(67, placer.getFluidHeight(12, -7));
|
||||
verify(riverHead).get(12, -7);
|
||||
}
|
||||
}
|
||||
+19
-2
@@ -1,10 +1,12 @@
|
||||
package art.arcane.iris.core.commands;
|
||||
|
||||
import art.arcane.iris.engine.object.IrisDimension;
|
||||
import art.arcane.volmlib.util.director.compat.DirectorAnnotationCompatibility;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorNodeDescriptor;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorParameterDescriptor;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -52,8 +54,23 @@ public class CommandPackOptionalPackContractTest {
|
||||
assertFalse(CommandPack.wantsAllPacks("overworld"));
|
||||
}
|
||||
|
||||
private static java.lang.reflect.Method findMethod(String name) {
|
||||
for (java.lang.reflect.Method method : CommandPack.class.getDeclaredMethods()) {
|
||||
@Test
|
||||
public void packageCommandIsOwnedByPackNamespace() throws Exception {
|
||||
Method method = CommandPack.class.getDeclaredMethod(
|
||||
"pkg",
|
||||
IrisDimension.class,
|
||||
boolean.class,
|
||||
boolean.class
|
||||
);
|
||||
DirectorNodeDescriptor descriptor = DirectorAnnotationCompatibility.fromMethod(method).orElseThrow();
|
||||
assertTrue(descriptor.getAliases().contains("package"));
|
||||
for (Method studioMethod : CommandStudio.class.getDeclaredMethods()) {
|
||||
assertFalse("Studio must not retain the package command", studioMethod.getName().equals("pkg"));
|
||||
}
|
||||
}
|
||||
|
||||
private static Method findMethod(String name) {
|
||||
for (Method method : CommandPack.class.getDeclaredMethods()) {
|
||||
if (method.getName().equals(name)) {
|
||||
return method;
|
||||
}
|
||||
|
||||
+51
-3
@@ -2,8 +2,13 @@ package art.arcane.iris.core.service;
|
||||
|
||||
import art.arcane.iris.api.terrain.IrisColumnField;
|
||||
import art.arcane.iris.api.terrain.IrisColumnQuery;
|
||||
import art.arcane.iris.api.terrain.IrisRiverState;
|
||||
import art.arcane.iris.api.terrain.IrisSurfaceKind;
|
||||
import art.arcane.iris.api.terrain.IrisTerrainService;
|
||||
import art.arcane.iris.engine.hydrology.HydrologyColumnLayer;
|
||||
import art.arcane.iris.engine.hydrology.HydrologyColumnSample;
|
||||
import art.arcane.iris.engine.hydrology.HydrologyFeatureRef;
|
||||
import art.arcane.iris.engine.hydrology.HydrologyFeatureType;
|
||||
import art.arcane.iris.util.common.plugin.IrisService;
|
||||
import org.bukkit.World;
|
||||
import org.junit.Test;
|
||||
@@ -12,6 +17,7 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -82,9 +88,7 @@ public class IrisTerrainSVCTest {
|
||||
IrisTerrainSVC service = new IrisTerrainSVC();
|
||||
AtomicInteger sinkCalls = new AtomicInteger();
|
||||
|
||||
boolean answered = service.sampleColumns(null, SMALL,
|
||||
(int blockX, int blockZ, int surfaceHeight, IrisSurfaceKind kind, String biomeKey)
|
||||
-> sinkCalls.incrementAndGet());
|
||||
boolean answered = service.sampleColumns(null, SMALL, sample -> sinkCalls.incrementAndGet());
|
||||
|
||||
assertFalse(answered);
|
||||
assertEquals(0, sinkCalls.get());
|
||||
@@ -97,4 +101,48 @@ public class IrisTerrainSVCTest {
|
||||
assertFalse(service.sampleColumns(null, null, null));
|
||||
assertFalse(service.sampleColumns(null, SMALL, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptedHydrologyMapsToThePublicDiagnosticStates() {
|
||||
assertEquals(IrisRiverState.NONE, IrisTerrainSVC.riverState(null));
|
||||
assertEquals(IrisRiverState.WET, IrisTerrainSVC.riverState(river(true)));
|
||||
assertEquals(IrisRiverState.DRY, IrisTerrainSVC.riverState(river(false)));
|
||||
}
|
||||
|
||||
private static HydrologyColumnSample river(boolean connectedFluid) {
|
||||
HydrologyFeatureRef feature = new HydrologyFeatureRef(
|
||||
1L,
|
||||
HydrologyFeatureType.SURFACE_POOL,
|
||||
2L,
|
||||
3L,
|
||||
0,
|
||||
63,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
false
|
||||
);
|
||||
HydrologyColumnLayer layer = new HydrologyColumnLayer(
|
||||
feature,
|
||||
60,
|
||||
63,
|
||||
63,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
connectedFluid,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
connectedFluid,
|
||||
false,
|
||||
"water",
|
||||
"river",
|
||||
"mouth",
|
||||
"shore",
|
||||
"dry",
|
||||
"cave"
|
||||
);
|
||||
return new HydrologyColumnSample(0, 0, 70, 63, false, "parent", List.of(layer));
|
||||
}
|
||||
}
|
||||
+107
-2
@@ -1,9 +1,15 @@
|
||||
package art.arcane.iris.core.service.terrain;
|
||||
|
||||
import art.arcane.iris.api.terrain.IrisSurfaceKind;
|
||||
import art.arcane.iris.engine.hydrology.HydrologyColumnLayer;
|
||||
import art.arcane.iris.engine.hydrology.HydrologyColumnSample;
|
||||
import art.arcane.iris.engine.hydrology.HydrologyFeatureRef;
|
||||
import art.arcane.iris.engine.hydrology.HydrologyFeatureType;
|
||||
import art.arcane.iris.engine.object.InferredType;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -53,9 +59,108 @@ public class IrisSurfaceClassifierTest {
|
||||
|
||||
IrisSurfaceKind expected = IrisSurfaceClassifier.classify(surface, FLUID, null);
|
||||
for (InferredType inferredType : InferredType.values()) {
|
||||
assertEquals("surface=" + surface + " type=" + inferredType,
|
||||
expected, IrisSurfaceClassifier.classify(surface, FLUID, inferredType));
|
||||
assertEquals(
|
||||
"surface=" + surface + " type=" + inferredType,
|
||||
expected,
|
||||
IrisSurfaceClassifier.classify(surface, FLUID, inferredType)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptedSurfaceRolesOverrideGenericOceanAndLandKinds() {
|
||||
assertEquals(IrisSurfaceKind.RIVER, IrisSurfaceClassifier.classify(
|
||||
60,
|
||||
63,
|
||||
InferredType.SEA,
|
||||
hydrology(HydrologyFeatureType.SURFACE_POOL, true, false, true)
|
||||
));
|
||||
assertEquals(IrisSurfaceKind.RIVER, IrisSurfaceClassifier.classify(
|
||||
60,
|
||||
63,
|
||||
InferredType.SEA,
|
||||
hydrology(HydrologyFeatureType.MOUTH, true, false, true)
|
||||
));
|
||||
assertEquals(IrisSurfaceKind.RIVER_SHORE, IrisSurfaceClassifier.classify(
|
||||
64,
|
||||
63,
|
||||
InferredType.SHORE,
|
||||
hydrology(HydrologyFeatureType.SURFACE_POOL, false, true, false)
|
||||
));
|
||||
assertEquals(IrisSurfaceKind.DRY_CHANNEL, IrisSurfaceClassifier.classify(
|
||||
60,
|
||||
60,
|
||||
InferredType.LAND,
|
||||
hydrology(HydrologyFeatureType.SURFACE_POOL, true, false, false)
|
||||
));
|
||||
assertEquals(IrisSurfaceKind.LAND, IrisSurfaceClassifier.classify(
|
||||
60,
|
||||
60,
|
||||
InferredType.LAND,
|
||||
hydrology(HydrologyFeatureType.SURFACE_POOL, false, false, false)
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void voidClassificationWinsOverAcceptedRiverGeometry() {
|
||||
assertEquals(IrisSurfaceKind.VOID, IrisSurfaceClassifier.classify(
|
||||
0,
|
||||
63,
|
||||
InferredType.LAND,
|
||||
hydrology(HydrologyFeatureType.SURFACE_POOL, true, false, true)
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void absentRejectedCandidatesDoNotCreatePublicRiverKinds() {
|
||||
assertEquals(IrisSurfaceKind.LAND, IrisSurfaceClassifier.classify(
|
||||
64,
|
||||
63,
|
||||
InferredType.LAND,
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
private static HydrologyColumnSample hydrology(
|
||||
HydrologyFeatureType type,
|
||||
boolean channel,
|
||||
boolean shore,
|
||||
boolean connectedFluid
|
||||
) {
|
||||
HydrologyFeatureRef feature = new HydrologyFeatureRef(
|
||||
1L,
|
||||
type,
|
||||
2L,
|
||||
3L,
|
||||
0,
|
||||
63,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
false
|
||||
);
|
||||
HydrologyColumnLayer layer = new HydrologyColumnLayer(
|
||||
feature,
|
||||
60,
|
||||
63,
|
||||
63,
|
||||
channel,
|
||||
shore,
|
||||
!channel && !shore,
|
||||
connectedFluid,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
connectedFluid && channel,
|
||||
false,
|
||||
"water",
|
||||
"river",
|
||||
"mouth",
|
||||
"shore",
|
||||
"dry",
|
||||
"cave"
|
||||
);
|
||||
return new HydrologyColumnSample(0, 0, 70, 63, false, "parent", List.of(layer));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user