Port the v3 map as iris std map

- iris std map opens the v3 map window; noise, palettes, objects, procedural and image maps are views in it
- Rivers view draws v4 hydrology, with an empty state when the pack has rivers off
- 3D views fall back to software when LWJGL isn't on the classpath; modded jars use the game's LWJGL
- FlatLaf and LWJGL join core; v4's separate studio windows are removed
This commit is contained in:
piexel committed 2026-10-25 16:00:17 +01:00
1 parent 2d211cf106
commit 29cca99947
214 files changed
+27582 -4368

No files matched your search

@@ -1,4 +1,4 @@
package art.arcane.iris.studio.view;
package art.arcane.iris.studio.map;
import art.arcane.iris.generation.runtime.Engine;
import org.junit.Test;
@@ -7,12 +7,12 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
public class ImageMapStudioGUITest {
public class ImageMapExplorerTest {
@Test
public void exportRequestsHotloadWithoutMutatingTheActiveGenerationData() {
Engine engine = mock(Engine.class);
ImageMapStudioGUI.reloadActiveEngine(engine);
ImageMapExplorer.reloadActiveEngine(engine);
verify(engine).hotloadSilently();
verifyNoMoreInteractions(engine);
@@ -1,4 +1,4 @@
package art.arcane.iris.studio.view;
package art.arcane.iris.studio.map;
import art.arcane.iris.generation.image.IrisImageMap;
import art.arcane.iris.generation.image.IrisImageMapOrigin;
@@ -1,4 +1,4 @@
package art.arcane.iris.studio.view;
package art.arcane.iris.studio.map;
import art.arcane.iris.generation.image.CompiledIrisImageMap;
import art.arcane.iris.generation.image.IrisImageMapRuntime;
@@ -0,0 +1,74 @@
package art.arcane.iris.studio.map;
import art.arcane.iris.configuration.IrisSettings;
import art.arcane.iris.generation.runtime.MeteredCache;
import art.arcane.iris.generation.runtime.PreservationRegistry;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.testsupport.PlatformLeakGuard;
import org.junit.ClassRule;
import org.junit.Test;
import javax.swing.SwingUtilities;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public final class NoiseExplorerGUITest {
@ClassRule
public static final PlatformLeakGuard PLATFORM_GUARD = PlatformLeakGuard.clean();
@Test
public void allExecutorsRegisterForPreservationAndCloseWithWindow() throws Exception {
PreservationRegistry previous = IrisServices.getOrNull(PreservationRegistry.class);
IrisSettings previousSettings = IrisSettings.settings;
RecordingPreservationRegistry preservation = new RecordingPreservationRegistry();
AtomicReference<NoiseExplorerGUI> explorerReference = new AtomicReference<>();
IrisServices.register(PreservationRegistry.class, preservation);
IrisSettings.settings = new IrisSettings();
try {
SwingUtilities.invokeAndWait(() -> explorerReference.set(NoiseExplorerGUI.createNoiseExplorer(null)));
assertFalse(preservation.executors.isEmpty());
SwingUtilities.invokeAndWait(explorerReference.get()::close);
for (ExecutorService executor : preservation.executors) {
assertTrue(executor.isShutdown());
}
} finally {
NoiseExplorerGUI explorer = explorerReference.get();
if (explorer != null) {
SwingUtilities.invokeAndWait(explorer::close);
}
if (previous == null) {
IrisServices.remove(PreservationRegistry.class);
} else {
IrisServices.register(PreservationRegistry.class, previous);
}
IrisSettings.settings = previousSettings;
}
}
private static final class RecordingPreservationRegistry implements PreservationRegistry {
private final List<ExecutorService> executors = new ArrayList<>();
@Override
public void register(Thread thread) {
}
@Override
public void register(ExecutorService service) {
executors.add(service);
}
@Override
public void registerCache(MeteredCache cache) {
}
@Override
public void dereference() {
}
}
}
@@ -1,4 +1,4 @@
package art.arcane.iris.studio.view;
package art.arcane.iris.studio.map;
import org.junit.Test;
@@ -1,4 +1,4 @@
package art.arcane.iris.studio.view;
package art.arcane.iris.studio.map;
import art.arcane.volmlib.util.function.NoiseProvider;
import org.junit.Test;
@@ -295,6 +295,7 @@ public final class NoiseRenderCoordinatorTest {
coordinator.request(stale);
assertTrue(firstSample.await(3L, TimeUnit.SECONDS));
coordinator.request(latest);
releaseFirst.countDown();
assertTrue(latestCompleted.await(3L, TimeUnit.SECONDS));
assertEquals(null, failure.get());
@@ -354,66 +355,4 @@ public final class NoiseRenderCoordinatorTest {
coordinator.close();
}
}
@Test
public void latestMultiBandViewCompletesAfterThreeInterruptIgnoringGenerations() throws Exception {
CountDownLatch latestCompleted = new CountDownLatch(1);
AtomicReference<Throwable> failure = new AtomicReference<>();
AtomicBoolean releaseStale = new AtomicBoolean();
NoiseRenderCoordinator coordinator = new NoiseRenderCoordinator(2, new NoiseRenderCoordinator.Listener() {
@Override
public void onRenderStarted(NoiseRenderCoordinator.Request request) {
}
@Override
public void onRenderCompleted(NoiseRenderCoordinator.Result result) {
if (result.request().revision() == 4L) {
latestCompleted.countDown();
}
}
@Override
public void onRenderFailed(NoiseRenderCoordinator.Request request, Throwable error) {
failure.set(error);
latestCompleted.countDown();
}
});
try {
for (long revision = 1L; revision <= 3L; revision++) {
CountDownLatch staleStarted = new CountDownLatch(2);
coordinator.request(new NoiseRenderCoordinator.Request(
revision,
(x, z) -> {
staleStarted.countDown();
while (!releaseStale.get()) {
Thread.onSpinWait();
}
return 0.25D;
},
new NoiseViewport(0D, 0D, 1D),
NoisePalette.TERRAIN,
8,
4,
1
));
assertTrue(staleStarted.await(1L, TimeUnit.SECONDS));
}
coordinator.request(new NoiseRenderCoordinator.Request(
4L,
(x, z) -> 0.75D,
new NoiseViewport(0D, 0D, 1D),
NoisePalette.TERRAIN,
8,
4,
1
));
assertTrue(latestCompleted.await(3L, TimeUnit.SECONDS));
assertEquals(null, failure.get());
} finally {
releaseStale.set(true);
coordinator.close();
}
}
}
@@ -1,4 +1,4 @@
package art.arcane.iris.studio.view;
package art.arcane.iris.studio.map;
import org.junit.Test;
@@ -1,4 +1,4 @@
package art.arcane.iris.studio.view;
package art.arcane.iris.studio.map;
import org.junit.Test;
@@ -1,6 +1,8 @@
package art.arcane.iris.studio.view;
import art.arcane.iris.configuration.IrisSettings;
import art.arcane.iris.studio.map.MapWindow;
import art.arcane.iris.studio.map.NoiseExplorerGUI;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -38,28 +40,28 @@ public class DesktopGuiLaunchTest {
@Test
public void mapLaunchDoesNotCreateAWindowWithoutDesktop() throws Exception {
VisionGUI.launch(null, null);
MapWindow.openMap(null);
assertNoDesktopFailure();
}
@Test
public void noiseLaunchDoesNotCreateAWindowWithoutDesktop() throws Exception {
NoiseExplorerGUI.launch();
MapWindow.openNoise(null);
assertNoDesktopFailure();
}
@Test
public void generatorLaunchDoesNotCreateAWindowWithoutDesktop() throws Exception {
NoiseExplorerGUI.launchGeneratorKey("test", null, 12345L);
NoiseExplorerGUI.launchGeneratorKey(null, "test", null, 12345L);
assertNoDesktopFailure();
}
@Test
public void imageMapLaunchDoesNotReadEngineWithoutDesktop() throws Exception {
ImageMapStudioGUI.launch(null);
MapWindow.openImageMaps(null);
assertNoDesktopFailure();
}
@@ -1,122 +0,0 @@
package art.arcane.iris.studio.view;
import art.arcane.iris.generation.runtime.MeteredCache;
import art.arcane.iris.generation.runtime.PreservationRegistry;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.testsupport.PlatformLeakGuard;
import art.arcane.volmlib.util.function.NoiseProvider;
import org.junit.ClassRule;
import org.junit.Test;
import javax.swing.SwingUtilities;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public final class NoiseExplorerGUITest {
@ClassRule
public static final PlatformLeakGuard PLATFORM_GUARD = PlatformLeakGuard.clean();
@Test
public void openingInitialSourceBuildsSamplerExactlyOnce() throws Exception {
AtomicInteger factoryCalls = new AtomicInteger();
CountDownLatch firstFactoryCall = new CountDownLatch(1);
CountDownLatch releaseFactory = new CountDownLatch(1);
CountDownLatch duplicateFactoryCall = new CountDownLatch(1);
AtomicReference<NoiseExplorerGUI> explorerReference = new AtomicReference<>();
try {
SwingUtilities.invokeAndWait(() -> {
NoiseExplorerGUI explorer = new NoiseExplorerGUI(sourceSeed -> {
int invocation = factoryCalls.incrementAndGet();
if (invocation == 1) {
firstFactoryCall.countDown();
try {
releaseFactory.await(3L, TimeUnit.SECONDS);
} catch (InterruptedException error) {
Thread.currentThread().interrupt();
}
} else {
duplicateFactoryCall.countDown();
}
return constantSampler();
}, "Test source", 12345L);
explorer.buildSidebar();
explorer.openViewer();
explorerReference.set(explorer);
});
assertTrue(firstFactoryCall.await(3L, TimeUnit.SECONDS));
releaseFactory.countDown();
assertFalse(duplicateFactoryCall.await(300L, TimeUnit.MILLISECONDS));
assertEquals(1, factoryCalls.get());
} finally {
releaseFactory.countDown();
NoiseExplorerGUI explorer = explorerReference.get();
if (explorer != null) {
SwingUtilities.invokeAndWait(explorer::close);
}
}
}
@Test
public void allExecutorsRegisterForPreservationAndCloseWithWindow() throws Exception {
PreservationRegistry previous = IrisServices.getOrNull(PreservationRegistry.class);
RecordingPreservationRegistry preservation = new RecordingPreservationRegistry();
AtomicReference<NoiseExplorerGUI> explorerReference = new AtomicReference<>();
IrisServices.register(PreservationRegistry.class, preservation);
try {
SwingUtilities.invokeAndWait(() -> explorerReference.set(
new NoiseExplorerGUI(sourceSeed -> constantSampler(), "Test source", 12345L)
));
assertEquals(2, preservation.executors.size());
SwingUtilities.invokeAndWait(explorerReference.get()::close);
for (ExecutorService executor : preservation.executors) {
assertTrue(executor.isShutdown());
}
} finally {
NoiseExplorerGUI explorer = explorerReference.get();
if (explorer != null) {
SwingUtilities.invokeAndWait(explorer::close);
}
if (previous == null) {
IrisServices.remove(PreservationRegistry.class);
} else {
IrisServices.register(PreservationRegistry.class, previous);
}
}
}
private static NoiseProvider constantSampler() {
return (x, z) -> 0.5D;
}
private static final class RecordingPreservationRegistry implements PreservationRegistry {
private final List<ExecutorService> executors = new ArrayList<>();
@Override
public void register(Thread thread) {
}
@Override
public void register(ExecutorService service) {
executors.add(service);
}
@Override
public void registerCache(MeteredCache cache) {
}
@Override
public void dereference() {
}
}
}
@@ -1,370 +0,0 @@
package art.arcane.iris.studio.view;
import art.arcane.iris.studio.render.IrisRenderer;
import art.arcane.iris.studio.render.RenderType;
import art.arcane.iris.testsupport.Await;
import org.junit.Test;
import java.awt.image.BufferedImage;
import java.time.Duration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BooleanSupplier;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class VisionRenderControllerTest {
@Test
public void visibleTilesAreUniqueAndOrderedCenterFirst() {
VisionRenderController.RenderSpec spec = spec(RenderType.BIOME, 7L, 0D, 0D, 4D, 1440, 792);
List<VisionRenderController.VisibleTile> tiles = VisionRenderController.visibleTiles(spec);
assertEquals(336, tiles.size());
Set<String> coordinates = new HashSet<>();
double previousDistance = -1D;
for (VisionRenderController.VisibleTile tile : tiles) {
assertTrue(coordinates.add(tile.tileX() + ":" + tile.tileZ()));
assertTrue(tile.distanceSquared() >= previousDistance);
previousDistance = tile.distanceSquared();
}
assertEquals(1_376_256L, VisionRenderController.sampleCount(tiles.size()));
}
@Test
public void negativeWorldCoordinatesUseFloorBasedTileOwnership() {
VisionRenderController.RenderSpec spec = spec(RenderType.BIOME, 1L, -32D, -32D, 1D, 1, 1);
List<VisionRenderController.VisibleTile> tiles = VisionRenderController.visibleTiles(spec);
assertEquals(1, tiles.size());
assertEquals(-1L, tiles.get(0).tileX());
assertEquals(-1L, tiles.get(0).tileZ());
}
@Test
public void cacheIdentityContainsOnlyAtlasGenerationModeZoomAndWorldPage() {
VisionRenderController.TileKey baseline = new VisionRenderController.TileKey(4L, RenderType.BIOME, 4D, 8L, 9L);
assertNotEquals(baseline, new VisionRenderController.TileKey(5L, RenderType.BIOME, 4D, 8L, 9L));
assertNotEquals(baseline, new VisionRenderController.TileKey(4L, RenderType.RIVER, 4D, 8L, 9L));
assertNotEquals(baseline, new VisionRenderController.TileKey(4L, RenderType.BIOME, 4.5D, 8L, 9L));
assertNotEquals(baseline, new VisionRenderController.TileKey(4L, RenderType.BIOME, 4D, 7L, 9L));
}
@Test
public void everyPublishedPageIsFinalResolutionAndIdenticalRequestsAreCacheHits() throws Exception {
IrisRenderer renderer = mock(IrisRenderer.class);
AtomicInteger calls = new AtomicInteger();
when(renderer.renderStudioBase(
anyDouble(),
anyDouble(),
anyDouble(),
anyInt(),
any(RenderType.class),
any(BooleanSupplier.class)
)).thenAnswer(invocation -> {
assertEquals(VisionRenderController.TILE_PIXELS, (int) invocation.getArgument(3));
calls.incrementAndGet();
return new BufferedImage(
VisionRenderController.TILE_PIXELS,
VisionRenderController.TILE_PIXELS,
BufferedImage.TYPE_INT_RGB
);
});
passThroughRefinement(renderer);
VisionRenderController controller = controller(2);
VisionRenderController.RenderSpec spec = spec(renderer, RenderType.BIOME, 1L, 0D, 0D, 4D, 128, 128);
try {
VisionRenderController.Frame first = controller.request(spec);
Await.until("the first render to report every tile ready", Duration.ofSeconds(2L),
() -> controller.progress(first).ready() == controller.progress(first).total());
int rendered = calls.get();
VisionRenderController.Frame cached = controller.request(spec);
assertEquals(rendered, calls.get());
assertEquals(controller.progress(cached).total(), controller.progress(cached).ready());
for (VisionRenderController.VisibleTile tile : cached.tiles()) {
assertEquals(VisionRenderController.TILE_PIXELS, controller.image(cached, tile).getWidth());
assertEquals(VisionRenderController.TILE_PIXELS, controller.image(cached, tile).getHeight());
}
} finally {
controller.close();
}
}
@Test
public void smallPanReusesEveryOverlappingWorldPage() throws Exception {
IrisRenderer renderer = exactRenderer();
VisionRenderController controller = controller(2);
try {
VisionRenderController.Frame first = controller.request(spec(renderer, RenderType.BIOME, 1L, 16D, 16D, 4D, 128, 128));
Await.until("the first render to report every tile ready", Duration.ofSeconds(2L),
() -> controller.progress(first).ready() == controller.progress(first).total());
Set<VisionRenderController.TileKey> firstKeys = keys(first);
VisionRenderController.Frame panned = controller.request(spec(renderer, RenderType.BIOME, 1L, 20D, 20D, 4D, 128, 128));
assertEquals(firstKeys, keys(panned));
assertEquals(panned.tiles().size(), controller.progress(panned).ready());
for (VisionRenderController.VisibleTile pannedTile : panned.tiles()) {
VisionRenderController.VisibleTile original = tile(first, panned.key(pannedTile));
assertSame(controller.image(first, original), controller.image(panned, pannedTile));
}
} finally {
controller.close();
}
}
@Test
public void newerViewPublishesWithoutWaitingForCancelledQueuedWork() throws Exception {
IrisRenderer renderer = mock(IrisRenderer.class);
CountDownLatch staleStarted = new CountDownLatch(1);
CountDownLatch latestStarted = new CountDownLatch(1);
when(renderer.renderStudio(
anyDouble(),
anyDouble(),
anyDouble(),
anyInt(),
any(RenderType.class),
any(BooleanSupplier.class)
)).thenAnswer(invocation -> {
RenderType type = invocation.getArgument(4);
BooleanSupplier cancelled = invocation.getArgument(5);
if (type == RenderType.REGION) {
staleStarted.countDown();
while (!cancelled.getAsBoolean()) {
Thread.onSpinWait();
}
throw new java.util.concurrent.CancellationException();
}
latestStarted.countDown();
return new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB);
});
when(renderer.renderStudioBase(anyDouble(), anyDouble(), anyDouble(), anyInt(),
any(RenderType.class), any(BooleanSupplier.class))).thenAnswer(invocation -> {
latestStarted.countDown();
return new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB);
});
passThroughRefinement(renderer);
VisionRenderController controller = controller(2);
try {
controller.request(spec(renderer, RenderType.REGION, 1L, 0D, 0D, 4D, 64, 64));
assertTrue(staleStarted.await(1L, TimeUnit.SECONDS));
controller.request(spec(renderer, RenderType.BIOME, 1L, 0D, 0D, 4D, 64, 64));
assertTrue(latestStarted.await(1L, TimeUnit.SECONDS));
} finally {
controller.close();
}
}
@Test
public void completeBaseIsVisibleBeforeBlockedHydrologyRefinementStarts() throws Exception {
IrisRenderer renderer = exactRenderer();
CountDownLatch overlayStarted = new CountDownLatch(1);
CountDownLatch releaseOverlay = new CountDownLatch(1);
AtomicInteger baseCalls = new AtomicInteger();
AtomicInteger overlays = new AtomicInteger();
when(renderer.renderStudioBase(anyDouble(), anyDouble(), anyDouble(), anyInt(),
any(RenderType.class), any(BooleanSupplier.class))).thenAnswer(invocation -> {
baseCalls.incrementAndGet();
return new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB);
});
when(renderer.refineStudioBiome(anyDouble(), anyDouble(), anyDouble(), any(BufferedImage.class),
any(BooleanSupplier.class))).thenAnswer(invocation -> {
overlays.incrementAndGet();
overlayStarted.countDown();
assertTrue(releaseOverlay.await(2L, TimeUnit.SECONDS));
return invocation.getArgument(3);
});
VisionRenderController controller = controller(3);
try {
VisionRenderController.RenderSpec spec = spec(renderer, RenderType.BIOME, 1L, 0D, 0D, 4D, 192, 128);
VisionRenderController.Frame frame = controller.request(spec);
assertTrue(overlayStarted.await(2L, TimeUnit.SECONDS));
assertEquals(frame.tiles().size(), baseCalls.get());
assertEquals(1, overlays.get());
assertEquals(0, controller.progress(frame).ready());
for (VisionRenderController.VisibleTile tile : frame.tiles()) {
assertEquals(64, controller.image(frame, tile).getWidth());
}
releaseOverlay.countDown();
Await.until("every biome overlay to complete", Duration.ofSeconds(2L),
() -> controller.progress(frame).ready() == frame.tiles().size());
assertEquals(frame.tiles().size(), overlays.get());
VisionRenderController.Frame cached = controller.request(spec);
assertEquals(frame.tiles().size(), controller.progress(cached).ready());
assertEquals(frame.tiles().size(), baseCalls.get());
assertEquals(frame.tiles().size(), overlays.get());
} finally {
releaseOverlay.countDown();
controller.close();
}
}
@Test
public void cancelledOverlayKeepsCachedBaseWithoutMarkingItComplete() throws Exception {
IrisRenderer renderer = exactRenderer();
CountDownLatch staleStarted = new CountDownLatch(1);
CountDownLatch latestStarted = new CountDownLatch(1);
CountDownLatch releaseLatest = new CountDownLatch(1);
AtomicInteger baseCalls = new AtomicInteger();
AtomicInteger overlayCalls = new AtomicInteger();
when(renderer.renderStudioBase(anyDouble(), anyDouble(), anyDouble(), anyInt(),
any(RenderType.class), any(BooleanSupplier.class))).thenAnswer(invocation -> {
baseCalls.incrementAndGet();
return new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB);
});
when(renderer.refineStudioBiome(anyDouble(), anyDouble(), anyDouble(), any(BufferedImage.class),
any(BooleanSupplier.class))).thenAnswer(invocation -> {
if (overlayCalls.getAndIncrement() == 0) {
staleStarted.countDown();
BooleanSupplier cancelled = invocation.getArgument(4);
while (!cancelled.getAsBoolean()) {
Thread.onSpinWait();
}
throw new CancellationException();
}
latestStarted.countDown();
assertTrue(releaseLatest.await(2L, TimeUnit.SECONDS));
return invocation.getArgument(3);
});
VisionRenderController controller = controller(2);
try {
VisionRenderController.RenderSpec spec = spec(renderer, RenderType.BIOME, 1L, 0D, 0D, 4D, 128, 128);
VisionRenderController.Frame stale = controller.request(spec);
assertTrue(staleStarted.await(2L, TimeUnit.SECONDS));
VisionRenderController.Frame latest = controller.request(spec);
assertTrue(latestStarted.await(2L, TimeUnit.SECONDS));
assertEquals(stale.tiles().size(), baseCalls.get());
assertEquals(0, controller.progress(latest).ready());
for (VisionRenderController.VisibleTile tile : latest.tiles()) {
assertEquals(64, controller.image(latest, tile).getWidth());
}
releaseLatest.countDown();
Await.until("the replacement frame to finish its overlays", Duration.ofSeconds(2L),
() -> controller.progress(latest).ready() == latest.tiles().size());
assertEquals(0, controller.progress(stale).ready());
} finally {
releaseLatest.countDown();
controller.close();
}
}
private static VisionRenderController controller(int workers) {
return new VisionRenderController(
() -> {
},
new VisionRenderController.RuntimeOptions(workers, 8, false)
);
}
private static IrisRenderer exactRenderer() {
IrisRenderer renderer = mock(IrisRenderer.class);
when(renderer.renderStudio(
anyDouble(),
anyDouble(),
anyDouble(),
anyInt(),
any(RenderType.class),
any(BooleanSupplier.class)
)).thenAnswer(invocation -> new BufferedImage(
invocation.getArgument(3),
invocation.getArgument(3),
BufferedImage.TYPE_INT_RGB
));
when(renderer.renderStudioBase(anyDouble(), anyDouble(), anyDouble(), anyInt(),
any(RenderType.class), any(BooleanSupplier.class))).thenAnswer(invocation -> new BufferedImage(
invocation.getArgument(3), invocation.getArgument(3), BufferedImage.TYPE_INT_RGB));
passThroughRefinement(renderer);
return renderer;
}
private static void passThroughRefinement(IrisRenderer renderer) {
when(renderer.refineStudioBiome(anyDouble(), anyDouble(), anyDouble(), any(BufferedImage.class),
any(BooleanSupplier.class))).thenAnswer(invocation -> invocation.getArgument(3));
}
private static Set<VisionRenderController.TileKey> keys(VisionRenderController.Frame frame) {
Set<VisionRenderController.TileKey> keys = new HashSet<>();
for (VisionRenderController.VisibleTile tile : frame.tiles()) {
keys.add(frame.key(tile));
}
return keys;
}
private static VisionRenderController.VisibleTile tile(
VisionRenderController.Frame frame,
VisionRenderController.TileKey key
) {
for (VisionRenderController.VisibleTile tile : frame.tiles()) {
if (frame.key(tile).equals(key)) {
return tile;
}
}
throw new AssertionError("Missing tile " + key);
}
private static VisionRenderController.RenderSpec spec(
RenderType type,
long revision,
double centerX,
double centerZ,
double blocksPerPixel,
int width,
int height
) {
return new VisionRenderController.RenderSpec(
mock(IrisRenderer.class),
type,
revision,
centerX,
centerZ,
blocksPerPixel,
width,
height
);
}
private static VisionRenderController.RenderSpec spec(
IrisRenderer renderer,
RenderType type,
long revision,
double centerX,
double centerZ,
double blocksPerPixel,
int width,
int height
) {
return new VisionRenderController.RenderSpec(
renderer,
type,
revision,
centerX,
centerZ,
blocksPerPixel,
width,
height
);
}
}
@@ -1,40 +0,0 @@
package art.arcane.iris.studio.view;
import art.arcane.iris.localization.DesktopUiMessages;
import art.arcane.iris.studio.render.RenderType;
import art.arcane.volmlib.util.localization.MessageKey;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
public class VisionRenderTypeTest {
@Test
public void everyRenderTypeHasALocalizedVisionLabel() {
for (RenderType type : RenderType.values()) {
MessageKey key = VisionGUI.modeKey(type);
assertNotNull(type.name(), key);
assertTrueCatalogMember(key);
}
}
@Test
public void riverRenderTypeUsesTheRiverNetworkLabel() {
assertSame(DesktopUiMessages.VISION_MODE_RIVER, VisionGUI.modeKey(RenderType.RIVER));
assertEquals("iris.desktop.vision.mode.river", DesktopUiMessages.VISION_MODE_RIVER.id());
}
@Test
public void teleportCoordinatesFloorAcrossTheNegativeOrigin() {
assertEquals(-1, VisionGUI.floorWorldCoordinate(-0.01D));
assertEquals(0, VisionGUI.floorWorldCoordinate(0.99D));
assertEquals(1, VisionGUI.floorWorldCoordinate(1D));
}
private static void assertTrueCatalogMember(MessageKey key) {
assertEquals(key.id(), 1, DesktopUiMessages.keys().stream()
.filter(candidate -> candidate.id().equals(key.id()))
.count());
}
}