mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-27 06:20:02 +00:00
Poplar
This commit is contained in:
1 parent
2fa0853e42
commit
8e3ef1b651
45 files changed
+1036
-36
No files matched your search
@@ -298,6 +298,7 @@ public class DecoratorCoreTest {
|
||||
when(decorator.pickBlockDataTop(any(RNG.class), eq(data), anyDouble(), anyDouble())).thenReturn(decorant);
|
||||
|
||||
Hunk<NativeBlockState> output = Hunk.newArrayHunk(1, 2, 1);
|
||||
output.set(0, 0, 0, sturdyState());
|
||||
int placed = DecoratorCore.placeFloatingStacked(
|
||||
decorator, 0, 0, 0, 0, 0, 3, output, new RNG(1L), data, null);
|
||||
|
||||
@@ -305,6 +306,72 @@ public class DecoratorCoreTest {
|
||||
assertSame(decorant, output.get(0, 1, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void floatingDecoratorsRejectUnsupportedSurface() {
|
||||
IrisDecorator decorator = mock(IrisDecorator.class);
|
||||
IrisData data = mock(IrisData.class);
|
||||
NativeBlockState decorant = mock(NativeBlockState.class);
|
||||
NativeBlockState air = airState();
|
||||
NativeBlockState fluid = mock(NativeBlockState.class);
|
||||
NativeBlockState plant = mock(NativeBlockState.class);
|
||||
when(plant.key()).thenReturn("minecraft:short_grass");
|
||||
when(fluid.isFluid()).thenReturn(true);
|
||||
when(decorant.key()).thenReturn("minecraft:cobblestone_slab");
|
||||
when(decorator.getHeight(any(RNG.class), anyDouble(), anyDouble(), eq(data))).thenReturn(2);
|
||||
when(decorator.getTopThreshold()).thenReturn(1.0);
|
||||
when(decorator.pickBlockData(any(RNG.class), eq(data), anyDouble(), anyDouble())).thenReturn(decorant);
|
||||
when(decorator.pickBlockDataTop(any(RNG.class), eq(data), anyDouble(), anyDouble())).thenReturn(decorant);
|
||||
|
||||
for (NativeBlockState surface : new NativeBlockState[]{null, air, fluid, plant}) {
|
||||
Hunk<NativeBlockState> output = Hunk.newArrayHunk(1, 5, 1);
|
||||
output.set(0, 0, 0, sturdyState());
|
||||
output.set(0, 2, 0, surface);
|
||||
output.set(0, 3, 0, air);
|
||||
output.set(0, 4, 0, air);
|
||||
|
||||
DecoratorCore.placeFloatingSimple(
|
||||
decorator, 0, 0, 0, 0, 2, 3, output, new RNG(1L), data, null);
|
||||
assertSame(air, output.get(0, 3, 0));
|
||||
|
||||
int placed = DecoratorCore.placeFloatingStacked(
|
||||
decorator, 0, 0, 0, 0, 2, 3, output, new RNG(1L), data, null);
|
||||
assertEquals(0, placed);
|
||||
assertSame(surface, output.get(0, 2, 0));
|
||||
assertSame(air, output.get(0, 3, 0));
|
||||
assertSame(air, output.get(0, 4, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void floatingDecoratorsPreserveSupportedPlacementWithoutMaterialGating() {
|
||||
IrisDecorator decorator = mock(IrisDecorator.class);
|
||||
IrisData data = mock(IrisData.class);
|
||||
NativeBlockState surface = mock(NativeBlockState.class);
|
||||
NativeBlockState decorant = mock(NativeBlockState.class);
|
||||
when(surface.isSolid()).thenReturn(true);
|
||||
when(decorant.key()).thenReturn("minecraft:cobblestone_slab");
|
||||
when(decorator.getHeight(any(RNG.class), anyDouble(), anyDouble(), eq(data))).thenReturn(2);
|
||||
when(decorator.getTopThreshold()).thenReturn(1.0);
|
||||
when(decorator.pickBlockData(any(RNG.class), eq(data), anyDouble(), anyDouble())).thenReturn(decorant);
|
||||
when(decorator.pickBlockDataTop(any(RNG.class), eq(data), anyDouble(), anyDouble())).thenReturn(decorant);
|
||||
Hunk<NativeBlockState> output = Hunk.newArrayHunk(1, 4, 1);
|
||||
output.set(0, 1, 0, surface);
|
||||
output.set(0, 2, 0, airState());
|
||||
output.set(0, 3, 0, airState());
|
||||
|
||||
DecoratorCore.placeFloatingSimple(
|
||||
decorator, 0, 0, 0, 0, 1, 3, output, new RNG(1L), data, null);
|
||||
assertSame(decorant, output.get(0, 2, 0));
|
||||
output.set(0, 2, 0, airState());
|
||||
|
||||
int placed = DecoratorCore.placeFloatingStacked(
|
||||
decorator, 0, 0, 0, 0, 1, 3, output, new RNG(1L), data, null);
|
||||
assertEquals(2, placed);
|
||||
assertSame(surface, output.get(0, 1, 0));
|
||||
assertSame(decorant, output.get(0, 2, 0));
|
||||
assertSame(decorant, output.get(0, 3, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tallSurfacePlantDoesNotPlaceWhenUpperTargetIsOccupied() {
|
||||
IrisDecorator decorator = mock(IrisDecorator.class);
|
||||
@@ -337,6 +404,7 @@ public class DecoratorCoreTest {
|
||||
when(decorator.pickBlockData(any(RNG.class), eq(data), anyDouble(), anyDouble())).thenReturn(plant);
|
||||
|
||||
Hunk<NativeBlockState> output = Hunk.newArrayHunk(1, 4, 1);
|
||||
output.set(0, 0, 0, sturdyState());
|
||||
output.set(0, 1, 0, air);
|
||||
output.set(0, 2, 0, occupied);
|
||||
|
||||
@@ -737,6 +805,7 @@ public class DecoratorCoreTest {
|
||||
private NativeBlockState sturdyState() {
|
||||
NativeBlockState support = mock(NativeBlockState.class);
|
||||
BlockData blockData = mock(BlockData.class);
|
||||
when(support.isSolid()).thenReturn(true);
|
||||
when(support.nativeHandle()).thenReturn(blockData);
|
||||
when(blockData.isFaceSturdy(any(), eq(BlockSupport.FULL))).thenReturn(true);
|
||||
return support;
|
||||
|
||||
+2
@@ -109,6 +109,8 @@ public class IrisSugarCanePlacementTest {
|
||||
local = size / 2;
|
||||
output = Hunk.newArrayHunk(size, 8, size);
|
||||
when(air.isAir()).thenReturn(true);
|
||||
when(stone.isSolid()).thenReturn(true);
|
||||
when(soil.isSolid()).thenReturn(true);
|
||||
when(water.isWater()).thenReturn(true);
|
||||
when(cane.canPlaceOnto(soil)).thenReturn(true);
|
||||
when(cane.canPlaceOnto(cane)).thenReturn(true);
|
||||
|
||||
+65
@@ -5,6 +5,7 @@ import org.junit.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -88,6 +89,70 @@ public class ProceduralTreeGeneratorTest {
|
||||
assertTrue("leaves should rise above the trunk top", maxLeafY >= height - 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void poplarCrownIsBroaderAndHigherThanColumnarCrown() {
|
||||
TreeBlockCanvas poplar = profileCanopy(IrisTreeProfile.POPLAR);
|
||||
TreeBlockCanvas columnar = profileCanopy(IrisTreeProfile.COLUMNAR);
|
||||
int poplarWidth = 0;
|
||||
int columnarWidth = 0;
|
||||
int poplarBottom = Integer.MAX_VALUE;
|
||||
int columnarBottom = Integer.MAX_VALUE;
|
||||
for (TreeBlockCanvas.Vec leaf : poplar.getLeaf()) {
|
||||
poplarWidth = Math.max(poplarWidth, Math.abs(leaf.x()));
|
||||
poplarBottom = Math.min(poplarBottom, leaf.y());
|
||||
}
|
||||
for (TreeBlockCanvas.Vec leaf : columnar.getLeaf()) {
|
||||
columnarWidth = Math.max(columnarWidth, Math.abs(leaf.x()));
|
||||
columnarBottom = Math.min(columnarBottom, leaf.y());
|
||||
}
|
||||
|
||||
assertTrue(poplarWidth > columnarWidth);
|
||||
assertTrue(poplarBottom > columnarBottom);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void branchingPoplarVariantsRetainSupportedLeavesAndOrientedWood() {
|
||||
IrisProceduralTree tree = new IrisProceduralTree()
|
||||
.setProfile(IrisTreeProfile.POPLAR)
|
||||
.setTrunk("minecraft:poplar_log")
|
||||
.setLeaves("minecraft:orange_poplar_leaves")
|
||||
.setLeanAngle(7);
|
||||
IrisTreeBranches branches = new IrisTreeBranches()
|
||||
.setProbabilityFunction(IrisTreeBranchProbability.TOP_HEAVY)
|
||||
.setProbabilityExponent(2)
|
||||
.setLengthFunction(IrisTreeFunction.CONSTANT)
|
||||
.setLengthConstant(3)
|
||||
.setElevation(35)
|
||||
.setClusterRadius(2);
|
||||
tree.getCanopy().setBranches(branches);
|
||||
for (int height = 7; height <= 11; height++) {
|
||||
TreeBlockCanvas canvas = new TreeBlockCanvas();
|
||||
List<int[]> endpoints = new ArrayList<>();
|
||||
double[][] offsets = TreeTrunkBuilder.build(canvas, tree, height).getFirst().offsets();
|
||||
TreeCanopyBuilder.build(canvas, tree, height, offsets, 0, height * 7919L, endpoints);
|
||||
TreeSupport.ensureLeavesSupported(canvas, 24);
|
||||
|
||||
assertFalse(endpoints.isEmpty());
|
||||
assertFalse(canvas.getLeaf().isEmpty());
|
||||
Map<TreeBlockCanvas.Vec, Integer> distances = TreePlausibility.computeDistances(canvas.getTrunk(), canvas.getLeaf());
|
||||
for (TreeBlockCanvas.Vec leaf : canvas.getLeaf()) {
|
||||
assertNotNull(distances.get(leaf));
|
||||
assertTrue(distances.get(leaf) <= 6);
|
||||
}
|
||||
for (TreeBlockCanvas.Vec wood : canvas.getTrunk()) {
|
||||
assertTrue(canvas.get(wood.x(), wood.y(), wood.z()).axis() != TreeBlockCanvas.Axis.NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static TreeBlockCanvas profileCanopy(IrisTreeProfile profile) {
|
||||
IrisProceduralTree tree = new IrisProceduralTree().setProfile(profile);
|
||||
TreeBlockCanvas canvas = new TreeBlockCanvas();
|
||||
double[][] offsets = TreeTrunkBuilder.build(canvas, tree, 14).getFirst().offsets();
|
||||
TreeCanopyBuilder.build(canvas, tree, 14, offsets, 0, 1234L, null);
|
||||
return canvas;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hollowCanopyHasFewerLeavesThanFilled() {
|
||||
TreeBlockCanvas filled = canopyOnly(IrisTreeLeafMode.FILLED);
|
||||
|
||||
+54
@@ -6,8 +6,46 @@ import org.junit.Test;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
public class TreeDecoratorApplierTest {
|
||||
@Test
|
||||
public void trunkAttachmentsFaceAwayFromTheirWoodSupport() {
|
||||
TreeBlockCanvas canvas = new TreeBlockCanvas();
|
||||
canvas.setTrunk(0, 2, 0, TreeBlockCanvas.Role.TRUNK, TreeBlockCanvas.Axis.Y);
|
||||
IrisProceduralTree tree = surfaceTree(IrisTreeDecoratorTarget.TRUNK_SURFACE, true);
|
||||
|
||||
TreeDecoratorApplier.apply(canvas, tree, 918L, List.of());
|
||||
|
||||
assertOutwardFacings(canvas);
|
||||
assertEquals(1, canvas.getTrunk().size());
|
||||
assertEquals(5, canvas.getCells().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void leafAttachmentsFaceAwayFromTheirLeafSupport() {
|
||||
TreeBlockCanvas canvas = new TreeBlockCanvas();
|
||||
canvas.setLeaf(0, 2, 0, TreeBlockCanvas.Role.LEAF);
|
||||
IrisProceduralTree tree = surfaceTree(IrisTreeDecoratorTarget.LEAF_SURFACE, true);
|
||||
|
||||
TreeDecoratorApplier.apply(canvas, tree, 918L, List.of());
|
||||
|
||||
assertOutwardFacings(canvas);
|
||||
assertEquals(1, canvas.getLeaf().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trunkAttachmentsKeepExplicitBlockFacingWhenAxisAwarenessIsDisabled() {
|
||||
TreeBlockCanvas canvas = new TreeBlockCanvas();
|
||||
canvas.setTrunk(0, 2, 0, TreeBlockCanvas.Role.TRUNK, TreeBlockCanvas.Axis.Y);
|
||||
IrisProceduralTree tree = surfaceTree(IrisTreeDecoratorTarget.TRUNK_SURFACE, false);
|
||||
|
||||
TreeDecoratorApplier.apply(canvas, tree, 918L, List.of());
|
||||
|
||||
assertEquals(TreeBlockCanvas.Role.DECORATOR, canvas.get(1, 2, 0).role());
|
||||
assertNull(canvas.get(1, 2, 0).facing());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void branchTipsExtendOutwardThroughLeavesWithoutReplacingWood() {
|
||||
TreeBlockCanvas canvas = new TreeBlockCanvas();
|
||||
@@ -39,4 +77,20 @@ public class TreeDecoratorApplierTest {
|
||||
|
||||
assertEquals(11, canvas.getCells().size());
|
||||
}
|
||||
|
||||
private static IrisProceduralTree surfaceTree(IrisTreeDecoratorTarget target, boolean axisAware) {
|
||||
IrisTreeDecorator decorator = new IrisTreeDecorator()
|
||||
.setTarget(target)
|
||||
.setBlock("minecraft:shelf_mushroom")
|
||||
.setChance(1D)
|
||||
.setAxisAware(axisAware);
|
||||
return new IrisProceduralTree().setDecorators(new KList<>(decorator));
|
||||
}
|
||||
|
||||
private static void assertOutwardFacings(TreeBlockCanvas canvas) {
|
||||
assertEquals("east", canvas.get(1, 2, 0).facing());
|
||||
assertEquals("west", canvas.get(-1, 2, 0).facing());
|
||||
assertEquals("south", canvas.get(0, 2, 1).facing());
|
||||
assertEquals("north", canvas.get(0, 2, -1).facing());
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package art.arcane.iris.generation.stage;
|
||||
|
||||
import art.arcane.iris.generation.biome.IrisBiome;
|
||||
import art.arcane.iris.generation.biome.IrisBiomePaletteLayer;
|
||||
import art.arcane.iris.generation.context.ChunkContext;
|
||||
import art.arcane.iris.generation.context.ChunkedDataCache;
|
||||
import art.arcane.iris.generation.runtime.Engine;
|
||||
import art.arcane.iris.generation.runtime.IrisComplex;
|
||||
import art.arcane.iris.generation.terrain.IrisSlopeClip;
|
||||
import art.arcane.iris.pack.loading.IrisData;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
|
||||
import art.arcane.volmlib.util.hunk.Hunk;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import art.arcane.volmlib.util.stream.ProceduralStream;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyDouble;
|
||||
import static org.mockito.Mockito.CALLS_REAL_METHODS;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class IrisPostModifierSlabSupportTest {
|
||||
private static final int SURFACE = 12;
|
||||
private static final int PLANE_WIDTH = 5;
|
||||
private static final NativeBlockState AIR = state("minecraft:air", false, true, false);
|
||||
private static final NativeBlockState WATER = state("minecraft:water", false, false, true);
|
||||
private static final NativeBlockState STONE = state("minecraft:stone", true, false, false);
|
||||
private static final NativeBlockState SLAB = state("minecraft:cobblestone_slab", true, false, false);
|
||||
|
||||
@Test
|
||||
public void supportedStepReceivesSmoothingBlock() throws ReflectiveOperationException {
|
||||
assertSame(SLAB, smoothedBlock(STONE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void carvedAwaySurfaceDoesNotReceiveFloatingSmoothingBlock() throws ReflectiveOperationException {
|
||||
assertSame(AIR, smoothedBlock(AIR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fluidSurfaceDoesNotSupportSmoothingBlock() throws ReflectiveOperationException {
|
||||
assertSame(AIR, smoothedBlock(WATER));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private NativeBlockState smoothedBlock(NativeBlockState support) throws ReflectiveOperationException {
|
||||
Hunk<NativeBlockState> output = Hunk.newHunk(3, 24, 3);
|
||||
for (int x = 0; x < 3; x++) {
|
||||
for (int z = 0; z < 3; z++) {
|
||||
for (int y = 0; y < output.getHeight(); y++) {
|
||||
output.set(x, y, z, y <= SURFACE ? STONE : AIR);
|
||||
}
|
||||
}
|
||||
}
|
||||
output.set(1, SURFACE, 1, support);
|
||||
output.set(2, SURFACE + 1, 1, STONE);
|
||||
|
||||
IrisBiomePaletteLayer slabLayer = mock(IrisBiomePaletteLayer.class);
|
||||
doReturn(new IrisSlopeClip()).when(slabLayer).getSlopeCondition();
|
||||
doReturn(SLAB).when(slabLayer).get(any(RNG.class), anyDouble(), anyDouble(), anyDouble(), any());
|
||||
IrisBiome biome = mock(IrisBiome.class);
|
||||
doReturn(slabLayer).when(biome).getSlab();
|
||||
ChunkedDataCache<IrisBiome> biomes = mock(ChunkedDataCache.class);
|
||||
doReturn(biome).when(biomes).get(1, 1);
|
||||
ChunkContext context = mock(ChunkContext.class);
|
||||
doReturn(biomes).when(context).getBiome();
|
||||
|
||||
ProceduralStream<Double> zeroStream = mock(ProceduralStream.class);
|
||||
doReturn(0D).when(zeroStream).get(anyDouble(), anyDouble());
|
||||
IrisComplex complex = mock(IrisComplex.class);
|
||||
doReturn(zeroStream).when(complex).getRiverCarveWeightStream();
|
||||
doReturn(zeroStream).when(complex).getRiverWaterSurfaceStream();
|
||||
doReturn(zeroStream).when(complex).getSlopeStream();
|
||||
Engine engine = mock(Engine.class);
|
||||
doReturn(complex).when(engine).getComplex();
|
||||
doReturn(mock(IrisData.class)).when(engine).getData();
|
||||
|
||||
IrisPostModifier modifier = mock(IrisPostModifier.class, CALLS_REAL_METHODS);
|
||||
doReturn(engine).when(modifier).getEngine();
|
||||
Field rng = IrisPostModifier.class.getDeclaredField("rng");
|
||||
rng.setAccessible(true);
|
||||
rng.set(modifier, new RNG(88L));
|
||||
int[] heights = new int[PLANE_WIDTH * PLANE_WIDTH];
|
||||
Arrays.fill(heights, SURFACE);
|
||||
heights[2 * PLANE_WIDTH + 3] = SURFACE + 1;
|
||||
|
||||
Method post = IrisPostModifier.class.getDeclaredMethod("post", int.class, int.class, Hunk.class,
|
||||
int.class, int.class, ChunkContext.class, int[].class, int.class, boolean.class, boolean.class);
|
||||
post.setAccessible(true);
|
||||
post.invoke(modifier, 1, 1, output, 1, 1, context, heights, PLANE_WIDTH, false, true);
|
||||
return output.get(1, SURFACE + 1, 1);
|
||||
}
|
||||
|
||||
private static NativeBlockState state(String key, boolean solid, boolean air, boolean fluid) {
|
||||
NativeBlockState state = mock(NativeBlockState.class);
|
||||
doReturn(key).when(state).key();
|
||||
doReturn(key).when(state).materialKey();
|
||||
doReturn(solid).when(state).isSolid();
|
||||
doReturn(air).when(state).isAir();
|
||||
doReturn(fluid).when(state).isFluid();
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,7 @@ public class SchemaBuilderIdentityTest {
|
||||
@ClassRule
|
||||
public static final PlatformLeakGuard PLATFORM_GUARD = PlatformLeakGuard.clean();
|
||||
|
||||
private static final String EXPECTED_SCHEMA_DIGEST = "91c36f3cdb0a10a0700b62fb6a6d2456576bd50f75a4d588103acdd42a7763c1";
|
||||
private static final String EXPECTED_SCHEMA_DIGEST = "7950fa5a3f3abf7fdd2cea1bd4b1fd335745b348ce64e67404cc86e898d18f16";
|
||||
|
||||
private static final List<Class<?>> SCHEMA_ROOTS = List.of(
|
||||
IrisDimension.class,
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package art.arcane.iris.studio.edit;
|
||||
|
||||
import art.arcane.iris.generation.biome.IrisBiome;
|
||||
import art.arcane.iris.generation.runtime.Engine;
|
||||
import art.arcane.iris.localization.IrisLanguage;
|
||||
import art.arcane.iris.localization.RuntimeUiMessages;
|
||||
import art.arcane.iris.platform.bukkit.nms.INMS;
|
||||
import art.arcane.iris.platform.bukkit.nms.INMSBinding;
|
||||
import art.arcane.iris.platform.bukkit.plugin.VolmitSender;
|
||||
import art.arcane.iris.platform.generation.PlatformChunkGenerator;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.world.IrisToolbelt;
|
||||
import art.arcane.iris.world.history.SavedBiomeUnavailableException;
|
||||
import art.arcane.iris.world.task.J;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class DustRevealerTest {
|
||||
@Test
|
||||
public void loadingSurfaceBiomeSendsOneNoticeAndStopsTheReveal() {
|
||||
try (Fixture fixture = new Fixture()) {
|
||||
when(fixture.engine.getSurfaceBiome(192, 816))
|
||||
.thenThrow(new SavedBiomeUnavailableException("Saved biome information is loading.", true));
|
||||
|
||||
DustRevealer.spawn(fixture.block, fixture.sender);
|
||||
|
||||
verify(fixture.sender).sendMessage(IrisLanguage.text(RuntimeUiMessages.DUST_BIOME_LOADING));
|
||||
verifyNoMoreInteractions(fixture.sender);
|
||||
verify(fixture.engine).getObjectPlacementKey(192, 96, 816);
|
||||
fixture.verifyNoLaterQueriesOrReveal();
|
||||
fixture.logging.verifyNoInteractions();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadingDuringHeightLookupSendsOneNoticeBeforeObjectLookup() {
|
||||
try (Fixture fixture = new Fixture()) {
|
||||
when(fixture.engine.getHeight(192, 816, true))
|
||||
.thenThrow(new SavedBiomeUnavailableException("Saved biome information is loading.", true));
|
||||
|
||||
DustRevealer.spawn(fixture.block, fixture.sender);
|
||||
|
||||
verify(fixture.sender).sendMessage(IrisLanguage.text(RuntimeUiMessages.DUST_BIOME_LOADING));
|
||||
verifyNoMoreInteractions(fixture.sender);
|
||||
verify(fixture.engine, never()).getObjectPlacementKey(anyInt(), anyInt(), anyInt());
|
||||
fixture.verifyNoLaterQueriesOrReveal();
|
||||
fixture.logging.verifyNoInteractions();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void anotherClickReportsTheBiomeAfterLoadingFinishes() {
|
||||
try (Fixture fixture = new Fixture()) {
|
||||
IrisBiome biome = mock(IrisBiome.class);
|
||||
when(biome.getLoadKey()).thenReturn("ready-biome");
|
||||
when(fixture.engine.getSurfaceBiome(192, 816))
|
||||
.thenThrow(new SavedBiomeUnavailableException("Saved biome information is loading.", true))
|
||||
.thenReturn(biome);
|
||||
|
||||
DustRevealer.spawn(fixture.block, fixture.sender);
|
||||
verify(fixture.sender).sendMessage(IrisLanguage.text(RuntimeUiMessages.DUST_BIOME_LOADING));
|
||||
clearInvocations(fixture.sender);
|
||||
|
||||
DustRevealer.spawn(fixture.block, fixture.sender);
|
||||
|
||||
ArgumentCaptor<String> messages = ArgumentCaptor.forClass(String.class);
|
||||
verify(fixture.sender, atLeastOnce()).sendMessage(messages.capture());
|
||||
assertTrue(messages.getAllValues().stream().anyMatch(message -> message.contains("ready-biome")));
|
||||
verify(fixture.sender, never()).sendMessage(IrisLanguage.text(RuntimeUiMessages.DUST_BIOME_LOADING));
|
||||
verify(fixture.sender, never()).sendMessage(IrisLanguage.text(RuntimeUiMessages.DUST_REVEAL_FAILED));
|
||||
fixture.logging.verifyNoInteractions();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unavailableSavedBiomeReportsTheOriginalFailureAndStopsTheReveal() {
|
||||
try (Fixture fixture = new Fixture()) {
|
||||
SavedBiomeUnavailableException failure = new SavedBiomeUnavailableException(
|
||||
"Saved biome data could not be read.", new IllegalStateException("Corrupt biome receipt"));
|
||||
when(fixture.engine.getSurfaceBiome(192, 816)).thenThrow(failure);
|
||||
|
||||
DustRevealer.spawn(fixture.block, fixture.sender);
|
||||
|
||||
fixture.logging.verify(() -> IrisLogging.reportError(failure));
|
||||
fixture.logging.verifyNoMoreInteractions();
|
||||
verify(fixture.sender).sendMessage(IrisLanguage.text(RuntimeUiMessages.DUST_REVEAL_FAILED));
|
||||
verifyNoMoreInteractions(fixture.sender);
|
||||
verify(fixture.engine).getObjectPlacementKey(192, 96, 816);
|
||||
fixture.verifyNoLaterQueriesOrReveal();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Fixture implements AutoCloseable {
|
||||
private final MockedStatic<IrisToolbelt> toolbelt = mockStatic(IrisToolbelt.class);
|
||||
private final MockedStatic<IrisLogging> logging = mockStatic(IrisLogging.class);
|
||||
private final MockedStatic<INMS> nativeAccess = mockStatic(INMS.class);
|
||||
private final MockedStatic<J> scheduling = mockStatic(J.class);
|
||||
private final Engine engine = mock(Engine.class);
|
||||
private final World world = mock(World.class);
|
||||
private final Block block = mock(Block.class);
|
||||
private final VolmitSender sender = mock(VolmitSender.class);
|
||||
|
||||
private Fixture() {
|
||||
PlatformChunkGenerator generator = mock(PlatformChunkGenerator.class);
|
||||
when(generator.getEngine()).thenReturn(engine);
|
||||
toolbelt.when(() -> IrisToolbelt.access(world)).thenReturn(generator);
|
||||
INMSBinding binding = mock(INMSBinding.class);
|
||||
when(binding.getTrueBiomeBaseKey(any())).thenReturn("minecraft:plains");
|
||||
nativeAccess.when(INMS::get).thenReturn(binding);
|
||||
when(block.getWorld()).thenReturn(world);
|
||||
when(block.getX()).thenReturn(192);
|
||||
when(block.getY()).thenReturn(96);
|
||||
when(block.getZ()).thenReturn(816);
|
||||
when(block.getType()).thenReturn(Material.STONE);
|
||||
when(engine.getHeight(192, 816, true)).thenReturn(96);
|
||||
}
|
||||
|
||||
private void verifyNoLaterQueriesOrReveal() {
|
||||
verify(engine, never()).getBiome(anyInt(), anyInt(), anyInt());
|
||||
verify(engine, never()).getCaveOrMantleBiome(anyInt(), anyInt(), anyInt());
|
||||
verify(engine, never()).getRegion(anyInt(), anyInt());
|
||||
verify(engine, never()).getObjectsAt(anyInt(), anyInt());
|
||||
scheduling.verifyNoInteractions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
scheduling.close();
|
||||
nativeAccess.close();
|
||||
logging.close();
|
||||
toolbelt.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user