diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 55b4d04e..63c569bc 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -45,4 +45,6 @@ dependencies { api(libs.htmlSanitizerJ10) { isTransitive = false // depends on guava, provided by mc at runtime } + + implementation(libs.pnj) } diff --git a/common/src/main/java/xyz/jpenilla/squaremap/common/config/Config.java b/common/src/main/java/xyz/jpenilla/squaremap/common/config/Config.java index ba97a92e..e68f902d 100644 --- a/common/src/main/java/xyz/jpenilla/squaremap/common/config/Config.java +++ b/common/src/main/java/xyz/jpenilla/squaremap/common/config/Config.java @@ -5,10 +5,13 @@ import org.spongepowered.configurate.NodePath; import org.spongepowered.configurate.transformation.ConfigurationTransformation; import xyz.jpenilla.squaremap.common.data.DirectoryProvider; +import xyz.jpenilla.squaremap.common.data.image.BufferedImageMapImageIO; +import xyz.jpenilla.squaremap.common.data.image.MapImageIO; +import xyz.jpenilla.squaremap.common.data.image.PNJMapImageIO; @SuppressWarnings("unused") public final class Config extends AbstractConfig { - private static final int LATEST_VERSION = 2; + private static final int LATEST_VERSION = 3; Config(final DirectoryProvider directoryProvider) { super(directoryProvider.dataDirectory(), Config.class, "config.yml", LATEST_VERSION); @@ -26,7 +29,26 @@ protected void addVersions(final ConfigurationTransformation.VersionedBuilder ve }) .build(); - versionedBuilder.addVersion(LATEST_VERSION, oneToTwo); + final ConfigurationTransformation twoToThree = ConfigurationTransformation.chain( + ConfigurationTransformation.builder() + .addAction(NodePath.path("settings", "image-quality"), (path, node) -> new Object[]{"settings", "image-io"}) + .build(), + ConfigurationTransformation.builder() + .addAction(NodePath.path("settings", "image-io", "compress-images"), (path, node) -> new Object[]{"settings", "image-io", "bufferedimage", "compress-images"}) + .build(), + ConfigurationTransformation.builder() + .addAction(NodePath.path("settings", "image-io"), (path, node) -> { + final boolean compress = node.node("bufferedimage", "compress-images", "enabled").getBoolean(); + if (compress) { + node.node("backend").set("bufferedimage"); + } + return null; + }) + .build() + ); + + versionedBuilder.addVersion(2, oneToTwo); + versionedBuilder.addVersion(LATEST_VERSION, twoToThree); } static Config config; @@ -59,11 +81,18 @@ private static void webDirSettings() { public static boolean COMPRESS_IMAGES = false; private static double COMPRESSION_RATIO_CONFIG = 0.0F; public static float COMPRESSION_RATIO; + public static MapImageIO MAP_IMAGE_IO; - private static void imageQualitySettings() { - COMPRESS_IMAGES = config.getBoolean("settings.image-quality.compress-images.enabled", COMPRESS_IMAGES); - COMPRESSION_RATIO_CONFIG = config.getDouble("settings.image-quality.compress-images.value", COMPRESSION_RATIO_CONFIG); + private static void imageIOSettings() { + COMPRESS_IMAGES = config.getBoolean("settings.image-io.bufferedimage.compress-images.enabled", COMPRESS_IMAGES); + COMPRESSION_RATIO_CONFIG = config.getDouble("settings.image-io.bufferedimage.compress-images.value", COMPRESSION_RATIO_CONFIG); COMPRESSION_RATIO = (float) (1.0D - COMPRESSION_RATIO_CONFIG); + final String imageIoBackend = config.getString("settings.image-io.backend", "pnj"); + MAP_IMAGE_IO = switch (imageIoBackend) { + case "bufferedimage" -> new BufferedImageMapImageIO(); + case "pnj" -> new PNJMapImageIO(); + default -> throw new IllegalArgumentException("Invaild image io backend: " + imageIoBackend + "; Supported options: [pnj, bufferedimage]"); + }; } public static boolean HTTPD_ENABLED = true; diff --git a/common/src/main/java/xyz/jpenilla/squaremap/common/data/MapWorldInternal.java b/common/src/main/java/xyz/jpenilla/squaremap/common/data/MapWorldInternal.java index 72c8d5bf..f2183230 100644 --- a/common/src/main/java/xyz/jpenilla/squaremap/common/data/MapWorldInternal.java +++ b/common/src/main/java/xyz/jpenilla/squaremap/common/data/MapWorldInternal.java @@ -26,6 +26,7 @@ import xyz.jpenilla.squaremap.common.config.ConfigManager; import xyz.jpenilla.squaremap.common.config.WorldAdvanced; import xyz.jpenilla.squaremap.common.config.WorldConfig; +import xyz.jpenilla.squaremap.common.data.image.MapImage; import xyz.jpenilla.squaremap.common.layer.SpawnIconLayer; import xyz.jpenilla.squaremap.common.layer.WorldBorderLayer; import xyz.jpenilla.squaremap.common.task.render.RenderFactory; @@ -146,7 +147,7 @@ public int getMapColor(final BlockState state) { return Colors.rgb(state.getMapColor(null, null)); } - public void saveImage(final Image image) { + public void saveImage(final MapImage image) { this.imageIOExecutor.saveImage(image); } diff --git a/common/src/main/java/xyz/jpenilla/squaremap/common/data/image/BufferedImageMapImageIO.java b/common/src/main/java/xyz/jpenilla/squaremap/common/data/image/BufferedImageMapImageIO.java new file mode 100644 index 00000000..846157fa --- /dev/null +++ b/common/src/main/java/xyz/jpenilla/squaremap/common/data/image/BufferedImageMapImageIO.java @@ -0,0 +1,59 @@ +package xyz.jpenilla.squaremap.common.data.image; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Path; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.DefaultQualifier; +import xyz.jpenilla.squaremap.common.config.Config; + +@DefaultQualifier(NonNull.class) +public final class BufferedImageMapImageIO implements MapImageIO { + @Override + public void save(final BufferedImageMapImage image, final OutputStream out) throws IOException { + final ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next(); + try (final ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(out)) { + writer.setOutput(imageOutputStream); + final ImageWriteParam param = writer.getDefaultWriteParam(); + if (Config.COMPRESS_IMAGES && param.canWriteCompressed()) { + param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + if (param.getCompressionType() == null) { + param.setCompressionType(param.getCompressionTypes()[0]); + } + param.setCompressionQuality(Config.COMPRESSION_RATIO); + } + writer.write(null, new IIOImage(image.image(), null, null), param); + } + } + + @Override + public BufferedImageMapImage load(final Path input) throws IOException { + final @Nullable BufferedImage read = ImageIO.read(input.toFile()); + if (read == null) { + throw new IOException("Failed to read image file '" + input.toAbsolutePath() + "', ImageIO.read(File) result is null. This means no " + + "supported image format was able to read it. The image file may have been malformed or corrupted, it will be overwritten."); + } + return new BufferedImageMapImage(read); + } + + @Override + public BufferedImageMapImage newImage() { + return new BufferedImageMapImage( + new BufferedImage(MapImage.SIZE, MapImage.SIZE, BufferedImage.TYPE_INT_ARGB) + ); + } + + public record BufferedImageMapImage(BufferedImage image) implements MapImageIO.IOMapImage { + @Override + public void setPixel(final int x, final int y, final int color) { + this.image.setRGB(x, y, color); + } + } +} diff --git a/common/src/main/java/xyz/jpenilla/squaremap/common/data/Image.java b/common/src/main/java/xyz/jpenilla/squaremap/common/data/image/MapImage.java similarity index 61% rename from common/src/main/java/xyz/jpenilla/squaremap/common/data/Image.java rename to common/src/main/java/xyz/jpenilla/squaremap/common/data/image/MapImage.java index 39fc0f0f..4916e3d8 100644 --- a/common/src/main/java/xyz/jpenilla/squaremap/common/data/Image.java +++ b/common/src/main/java/xyz/jpenilla/squaremap/common/data/image/MapImage.java @@ -1,40 +1,42 @@ -package xyz.jpenilla.squaremap.common.data; +package xyz.jpenilla.squaremap.common.data.image; import java.awt.Color; -import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; -import javax.imageio.IIOImage; -import javax.imageio.ImageIO; -import javax.imageio.ImageWriteParam; -import javax.imageio.ImageWriter; -import javax.imageio.stream.ImageOutputStream; import net.minecraft.util.Mth; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; import xyz.jpenilla.squaremap.common.Logging; -import xyz.jpenilla.squaremap.common.config.Config; import xyz.jpenilla.squaremap.common.config.Messages; +import xyz.jpenilla.squaremap.common.data.RegionCoordinate; import xyz.jpenilla.squaremap.common.util.FileUtil; @DefaultQualifier(NonNull.class) -public final class Image { +public final class MapImage { private static final int TRANSPARENT = new Color(0, 0, 0, 0).getRGB(); public static final int SIZE = 512; + private final MapImageIO backend; private final RegionCoordinate region; private final Path directory; private final int maxZoom; private int @Nullable [][] pixels = null; - public Image(final RegionCoordinate region, final Path directory, final int maxZoom) { + @SuppressWarnings("unchecked") + public MapImage( + final RegionCoordinate region, + final Path directory, + final int maxZoom, + final MapImageIO backend + ) { this.region = region; this.directory = directory; this.maxZoom = maxZoom; + this.backend = (MapImageIO) backend; } public synchronized void setPixel(final int x, final int z, final int color) { @@ -59,7 +61,7 @@ public synchronized void save() { int scaledX = Mth.floor((double) this.region.x() / step); int scaledZ = Mth.floor((double) this.region.z() / step); - final BufferedImage image = this.getOrCreate(this.maxZoom - zoom, scaledX, scaledZ); + final MapImageIO.IOMapImage image = this.getOrCreate(this.maxZoom - zoom, scaledX, scaledZ); int baseX = (this.region.x() * size) & (SIZE - 1); int baseZ = (this.region.z() * size) & (SIZE - 1); @@ -68,29 +70,24 @@ public synchronized void save() { final int pixel = this.pixels[x][z]; if (pixel != Integer.MIN_VALUE) { final int color = pixel == 0 ? TRANSPARENT : pixel; - image.setRGB(baseX + (x / step), baseZ + (z / step), color); + image.setPixel(baseX + (x / step), baseZ + (z / step), color); } } } - this.save(this.maxZoom - zoom, scaledX, scaledZ, image); + this.saveImage(this.maxZoom - zoom, scaledX, scaledZ, image); } } - private BufferedImage getOrCreate(final int zoom, final int scaledX, final int scaledZ) { + private MapImageIO.IOMapImage getOrCreate(final int zoom, final int scaledX, final int scaledZ) { final Path file = this.imageInDirectory(zoom, scaledX, scaledZ); if (!Files.isRegularFile(file)) { - return newBufferedImage(); + return this.backend.newImage(); } try { - final @Nullable BufferedImage read = ImageIO.read(file.toFile()); - if (read == null) { - throw new IOException("Failed to read image file '" + file.toAbsolutePath() + "', ImageIO.read(File) result is null. This means no " + - "supported image format was able to read it. The image file may have been malformed or corrupted, it will be overwritten."); - } - return read; + return this.backend.load(file); } catch (final IOException ex) { try { Files.deleteIfExists(file); @@ -98,16 +95,16 @@ private BufferedImage getOrCreate(final int zoom, final int scaledX, final int s ex.addSuppressed(ex0); } this.logCouldNotRead(ex); - return newBufferedImage(); + return this.backend.newImage(); } } - private void save(final int zoom, final int scaledX, final int scaledZ, final BufferedImage image) { + private void saveImage(final int zoom, final int scaledX, final int scaledZ, final MapImageIO.IOMapImage image) { final Path out = this.imageInDirectory(zoom, scaledX, scaledZ); try { FileUtil.atomicWrite(out, tmp -> { try (final OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(tmp))) { - save(image, outputStream); + this.backend.save(image, outputStream); } }); } catch (final IOException ex) { @@ -115,22 +112,6 @@ private void save(final int zoom, final int scaledX, final int scaledZ, final Bu } } - private static void save(final BufferedImage image, final OutputStream out) throws IOException { - final ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next(); - try (final ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(out)) { - writer.setOutput(imageOutputStream); - final ImageWriteParam param = writer.getDefaultWriteParam(); - if (Config.COMPRESS_IMAGES && param.canWriteCompressed()) { - param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); - if (param.getCompressionType() == null) { - param.setCompressionType(param.getCompressionTypes()[0]); - } - param.setCompressionQuality(Config.COMPRESSION_RATIO); - } - writer.write(null, new IIOImage(image, null, null), param); - } - } - private Path imageInDirectory(final int zoom, final int scaledX, final int scaledZ) { final Path dir = this.directory.resolve(Integer.toString(zoom)); if (!Files.exists(dir)) { @@ -144,10 +125,6 @@ private Path imageInDirectory(final int zoom, final int scaledX, final int scale return dir.resolve(fileName); } - private static BufferedImage newBufferedImage() { - return new BufferedImage(Image.SIZE, Image.SIZE, BufferedImage.TYPE_INT_ARGB); - } - private void logCouldNotRead(final IOException ex) { Logging.logger().error(xz(Messages.LOG_COULD_NOT_READ_REGION), ex); } diff --git a/common/src/main/java/xyz/jpenilla/squaremap/common/data/image/MapImageIO.java b/common/src/main/java/xyz/jpenilla/squaremap/common/data/image/MapImageIO.java new file mode 100644 index 00000000..6c355ed3 --- /dev/null +++ b/common/src/main/java/xyz/jpenilla/squaremap/common/data/image/MapImageIO.java @@ -0,0 +1,20 @@ +package xyz.jpenilla.squaremap.common.data.image; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Path; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; + +@DefaultQualifier(NonNull.class) +public interface MapImageIO { + void save(I image, OutputStream out) throws IOException; + + I load(Path input) throws IOException; + + I newImage(); + + interface IOMapImage { + void setPixel(int x, int y, int color); + } +} diff --git a/common/src/main/java/xyz/jpenilla/squaremap/common/data/image/PNJMapImageIO.java b/common/src/main/java/xyz/jpenilla/squaremap/common/data/image/PNJMapImageIO.java new file mode 100644 index 00000000..172dd5ee --- /dev/null +++ b/common/src/main/java/xyz/jpenilla/squaremap/common/data/image/PNJMapImageIO.java @@ -0,0 +1,44 @@ +package xyz.jpenilla.squaremap.common.data.image; + +import io.github.xfacthd.pnj.api.PNJ; +import io.github.xfacthd.pnj.api.data.Image; +import io.github.xfacthd.pnj.api.define.ColorFormat; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Path; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; + +@DefaultQualifier(NonNull.class) +public final class PNJMapImageIO implements MapImageIO { + + @Override + public void save(final PNJMapImage image, final OutputStream out) throws IOException { + PNJ.encode(out, image.image()); + } + + @Override + public PNJMapImage load(final Path input) throws IOException { + return new PNJMapImage(PNJ.decode(input)); + } + + @Override + public PNJMapImage newImage() { + return new PNJMapImage( + new Image( + MapImage.SIZE, + MapImage.SIZE, + ColorFormat.RGB_ALPHA, + 8, + new byte[MapImage.SIZE * MapImage.SIZE * 4] + ) + ); + } + + public record PNJMapImage(Image image) implements IOMapImage { + @Override + public void setPixel(int x, int y, int color) { + this.image.setPixel(x, y, color, true); + } + } +} diff --git a/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/AbstractRender.java b/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/AbstractRender.java index c6628bd2..c375b2db 100644 --- a/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/AbstractRender.java +++ b/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/AbstractRender.java @@ -35,10 +35,11 @@ import org.checkerframework.framework.qual.DefaultQualifier; import xyz.jpenilla.squaremap.api.Pair; import xyz.jpenilla.squaremap.common.Logging; +import xyz.jpenilla.squaremap.common.config.Config; import xyz.jpenilla.squaremap.common.config.Messages; import xyz.jpenilla.squaremap.common.data.BiomeColors; import xyz.jpenilla.squaremap.common.data.ChunkCoordinate; -import xyz.jpenilla.squaremap.common.data.Image; +import xyz.jpenilla.squaremap.common.data.image.MapImage; import xyz.jpenilla.squaremap.common.data.MapWorldInternal; import xyz.jpenilla.squaremap.common.data.RegionCoordinate; import xyz.jpenilla.squaremap.common.util.ChunkHashMapKey; @@ -202,7 +203,7 @@ public final void restartProgressLogger() { } protected final void mapRegion(final RegionCoordinate region) { - final Image image = new Image(region, this.mapWorld.tilesPath(), this.mapWorld.config().ZOOM_MAX); + final MapImage image = new MapImage(region, this.mapWorld.tilesPath(), this.mapWorld.config().ZOOM_MAX, Config.MAP_IMAGE_IO); final int startX = region.getChunkX(); final int startZ = region.getChunkZ(); final List> futures = new ArrayList<>(); @@ -223,7 +224,7 @@ protected final void mapRegion(final RegionCoordinate region) { } } - protected final CompletableFuture mapSingleChunk(final Image image, final int chunkX, final int chunkZ) { + protected final CompletableFuture mapSingleChunk(final MapImage image, final int chunkX, final int chunkZ) { final CompletableFuture<@Nullable ChunkSnapshot> chunkFuture = this.chunks.snapshot(new ChunkPos(chunkX, chunkZ)); final CompletableFuture<@Nullable ChunkSnapshot> northChunk = this.chunks.snapshotDirect(new ChunkPos(chunkX, chunkZ - 1)); @@ -272,7 +273,7 @@ protected final CompletableFuture mapSingleChunk(final Image image, final }); } - protected final CompletableFuture mapChunkColumn(final Image image, final int chunkX, final int startChunkZ) { + protected final CompletableFuture mapChunkColumn(final MapImage image, final int chunkX, final int startChunkZ) { final List> futures = new ArrayList<>(33); final CompletableFuture<@Nullable ChunkSnapshot> aboveChunkFuture = this.chunks.snapshotDirect(new ChunkPos(chunkX, startChunkZ - 1)); @@ -309,7 +310,7 @@ protected final CompletableFuture mapChunkColumn(final Image image, final }); } - private void scanChunk(final Image image, final int[] lastY, final ChunkSnapshot chunk) { + private void scanChunk(final MapImage image, final int[] lastY, final ChunkSnapshot chunk) { while (this.mapWorld.renderManager().rendersPaused() && this.running()) { sleep(500); } @@ -327,7 +328,7 @@ private void scanChunk(final Image image, final int[] lastY, final ChunkSnapshot } } - private void scanTopRow(final Image image, final int[] lastY, final ChunkSnapshot chunk) { + private void scanTopRow(final MapImage image, final int[] lastY, final ChunkSnapshot chunk) { final int blockX = chunk.pos().getMinBlockX(); final int blockZ = chunk.pos().getMinBlockZ(); for (int x = 0; x < 16; x++) { diff --git a/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/BackgroundRender.java b/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/BackgroundRender.java index 5dab097f..965065cd 100644 --- a/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/BackgroundRender.java +++ b/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/BackgroundRender.java @@ -16,8 +16,9 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; import xyz.jpenilla.squaremap.common.Logging; +import xyz.jpenilla.squaremap.common.config.Config; import xyz.jpenilla.squaremap.common.data.ChunkCoordinate; -import xyz.jpenilla.squaremap.common.data.Image; +import xyz.jpenilla.squaremap.common.data.image.MapImage; import xyz.jpenilla.squaremap.common.data.MapWorldInternal; import xyz.jpenilla.squaremap.common.data.RegionCoordinate; import xyz.jpenilla.squaremap.common.util.Util; @@ -58,7 +59,7 @@ protected void render() { final Map> regionChunksMap = chunks.stream().collect(Collectors.groupingBy(ChunkCoordinate::regionCoordinate)); regionChunksMap.forEach((region, chunksToRenderInRegion) -> { - final Image image = new Image(region, this.mapWorld.tilesPath(), this.mapWorld.config().ZOOM_MAX); + final MapImage image = new MapImage(region, this.mapWorld.tilesPath(), this.mapWorld.config().ZOOM_MAX, Config.MAP_IMAGE_IO); final CompletableFuture[] chunkFutures = chunksToRenderInRegion.stream() .map(coord -> this.mapSingleChunk(image, coord.x(), coord.z())) diff --git a/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/RadiusRender.java b/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/RadiusRender.java index a249a447..bf2b646f 100644 --- a/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/RadiusRender.java +++ b/common/src/main/java/xyz/jpenilla/squaremap/common/task/render/RadiusRender.java @@ -14,9 +14,10 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; import xyz.jpenilla.squaremap.common.Logging; +import xyz.jpenilla.squaremap.common.config.Config; import xyz.jpenilla.squaremap.common.config.Messages; import xyz.jpenilla.squaremap.common.data.ChunkCoordinate; -import xyz.jpenilla.squaremap.common.data.Image; +import xyz.jpenilla.squaremap.common.data.image.MapImage; import xyz.jpenilla.squaremap.common.data.MapWorldInternal; import xyz.jpenilla.squaremap.common.data.RegionCoordinate; import xyz.jpenilla.squaremap.common.util.Numbers; @@ -99,7 +100,7 @@ protected void render() { this.mapRegion(region); continue; } - final Image image = new Image(region, this.mapWorld.tilesPath(), this.mapWorld.config().ZOOM_MAX); + final MapImage image = new MapImage(region, this.mapWorld.tilesPath(), this.mapWorld.config().ZOOM_MAX, Config.MAP_IMAGE_IO); final List> chunkFutures = new ArrayList<>(); for (final ChunkCoordinate chunkCoord : chunkCoords) { chunkFutures.add(this.mapSingleChunk(image, chunkCoord.x(), chunkCoord.z())); diff --git a/common/src/main/java/xyz/jpenilla/squaremap/common/util/ImageIOExecutor.java b/common/src/main/java/xyz/jpenilla/squaremap/common/util/ImageIOExecutor.java index 1d69da3b..3ea963bc 100644 --- a/common/src/main/java/xyz/jpenilla/squaremap/common/util/ImageIOExecutor.java +++ b/common/src/main/java/xyz/jpenilla/squaremap/common/util/ImageIOExecutor.java @@ -8,7 +8,7 @@ import net.minecraft.server.level.ServerLevel; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; -import xyz.jpenilla.squaremap.common.data.Image; +import xyz.jpenilla.squaremap.common.data.image.MapImage; @DefaultQualifier(NonNull.class) public final class ImageIOExecutor { @@ -25,14 +25,14 @@ private ImageIOExecutor(final ServerLevel level) { } /** - * Submits a save task for the given {@link Image} instance. If the save queue currently + * Submits a save task for the given {@link MapImage} instance. If the save queue currently * has {@link #IMAGE_IO_MAX_TASKS} or more tasks queued, this method will block until the queue * has less than {@link #IMAGE_IO_MAX_TASKS} tasks. This effectively throttles renders when the * save queue falls far behind a render, avoiding a potential memory leak. * - * @param image {@link Image} instance + * @param image {@link MapImage} instance */ - public void saveImage(final Image image) { + public void saveImage(final MapImage image) { this.submittedTasks.getAndIncrement(); this.executor.execute(() -> { try { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 075da5c8..7772d654 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -93,6 +93,8 @@ cardinalComponentsEntity = { group = "org.ladysnake.cardinal-components-api", na neoforge = { group = "net.neoforged", name = "neoforge", version.ref = "neoforge" } +pnj = "io.github.xfacthd:pnj:1.2" + # buildSrc indraCommon = { group = "net.kyori", name = "indra-common", version.ref = "indra" } indraPublishingSonatype = { group = "net.kyori", name = "indra-publishing-sonatype", version.ref = "indra" }