diff --git a/BlueMapAPI b/BlueMapAPI index c7a9be42..6cad751a 160000 --- a/BlueMapAPI +++ b/BlueMapAPI @@ -1 +1 @@ -Subproject commit c7a9be42adda14482f0e52ef55cb43fdc12d9502 +Subproject commit 6cad751ac59286a516007799bcad3f2868e0a802 diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java index d867d275..f275f63a 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java @@ -553,7 +553,7 @@ public class Plugin implements ServerEventListener { stopWatchingMap(map); try { - RegionFileWatchService watcher = new RegionFileWatchService(renderManager, map, false); + RegionFileWatchService watcher = new RegionFileWatchService(renderManager, map); watcher.start(); regionFileWatchServices.put(map.getId(), watcher); } catch (IOException ex) { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java index 291574ae..5bfdbfc4 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java @@ -47,7 +47,6 @@ public class RegionFileWatchService extends Thread { private final RenderManager renderManager; private final WatchService watchService; - private final boolean verbose; private volatile boolean closed; private Timer delayTimer; @@ -55,10 +54,9 @@ public class RegionFileWatchService extends Thread { @DebugDump private final Map scheduledUpdates; - public RegionFileWatchService(RenderManager renderManager, BmMap map, boolean verbose) throws IOException { + public RegionFileWatchService(RenderManager renderManager, BmMap map) throws IOException { this.renderManager = renderManager; this.map = map; - this.verbose = verbose; this.closed = false; this.scheduledUpdates = new HashMap<>(); @@ -68,14 +66,17 @@ public class RegionFileWatchService extends Thread { FileHelper.createDirectories(folder); this.watchService = folder.getFileSystem().newWatchService(); - folder.register(this.watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY); + + Logger.global.logDebug("Created region-file watch-service for map '" + map.getId() + "' at '" + folder + "'."); } @Override public void run() { if (delayTimer == null) delayTimer = new Timer("BlueMap-RegionFileWatchService-DelayTimer", true); + Logger.global.logDebug("Started watching map '" + map.getId() + "' for updates..."); + try { while (!closed) { WatchKey key = this.watchService.take(); @@ -95,14 +96,15 @@ public class RegionFileWatchService extends Thread { if (!key.reset()) return; } - } catch ( ClosedWatchServiceException ignore) { + } catch (ClosedWatchServiceException ignore) { } catch (InterruptedException iex) { Thread.currentThread().interrupt(); - } - - if (!closed) { - Logger.global.logWarning("Region-file watch-service for map '" + map.getId() + - "' stopped unexpectedly! (This map might not update automatically from now on)"); + } finally { + Logger.global.logDebug("Stopped watching map '" + map.getId() + "' for updates."); + if (!closed) { + Logger.global.logWarning("Region-file watch-service for map '" + map.getId() + + "' stopped unexpectedly! (This map might not update automatically from now on)"); + } } } @@ -118,7 +120,7 @@ public class RegionFileWatchService extends Thread { int rZ = Integer.parseInt(filenameParts[2]); Vector2i regionPos = new Vector2i(rX, rZ); - // we only want to start the render when there were no changes on a file for 10 seconds + // we only want to start the render when there were no changes on a file for 5 seconds TimerTask task = scheduledUpdates.remove(regionPos); if (task != null) task.cancel(); @@ -130,12 +132,12 @@ public class RegionFileWatchService extends Thread { scheduledUpdates.remove(regionPos); renderManager.scheduleRenderTask(task); - if (verbose) Logger.global.logInfo("Scheduled update for region-file: " + regionPos + " (Map: " + map.getId() + ")"); + Logger.global.logDebug("Scheduled update for region-file: " + regionPos + " (Map: " + map.getId() + ")"); } } }; scheduledUpdates.put(regionPos, task); - delayTimer.schedule(task, 10000); + delayTimer.schedule(task, 5000); } catch (NumberFormatException ignore) {} } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java index c413e141..20f550ff 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java @@ -53,14 +53,16 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.map.MapRenderState; import de.bluecolored.bluemap.core.storage.Storage; -import de.bluecolored.bluemap.core.world.block.Block; +import de.bluecolored.bluemap.core.world.Chunk; import de.bluecolored.bluemap.core.world.World; +import de.bluecolored.bluemap.core.world.block.Block; import java.io.IOException; import java.nio.file.Path; import java.util.*; import java.util.function.Function; import java.util.function.Predicate; +import java.util.stream.Stream; public class Commands { @@ -501,24 +503,39 @@ public class Commands { Block block = new Block<>(world, blockPos.getX(), blockPos.getY(), blockPos.getZ()); Block blockBelow = new Block<>(world, blockPos.getX(), blockPos.getY() - 1, blockPos.getZ()); - // populate lazy-loaded values - block.getBlockState(); - block.getBiomeId(); - block.getLightData(); - - blockBelow.getBlockState(); - blockBelow.getBiomeId(); - blockBelow.getLightData(); - source.sendMessages(Arrays.asList( - Text.of(TextColor.GOLD, "Block at you: ", TextColor.WHITE, block), - Text.of(TextColor.GOLD, "Block below you: ", TextColor.WHITE, blockBelow) + Text.of(TextColor.GOLD, "Block at you: \n", formatBlock(block)), + Text.of(TextColor.GOLD, "Block below you: \n", formatBlock(blockBelow)) )); }, "BlueMap-Plugin-DebugBlockCommand").start(); return 1; } + private Text formatBlock(Block block) { + World world = block.getWorld(); + Chunk chunk = block.getChunk(); + + Map lines = new LinkedHashMap<>(); + lines.put("world-id", world.getId()); + lines.put("world-name", world.getName()); + lines.put("chunk-is-generated", chunk.isGenerated()); + lines.put("chunk-has-lightdata", chunk.hasLightData()); + lines.put("chunk-inhabited-time", chunk.getInhabitedTime()); + lines.put("block-state", block.getBlockState()); + lines.put("biome", block.getBiomeId()); + lines.put("position", block.getX() + " | " + block.getY() + " | " + block.getZ()); + lines.put("block-light", block.getBlockLightLevel()); + lines.put("sun-light", block.getSunLightLevel()); + + Object[] textElements = lines.entrySet().stream() + .flatMap(e -> Stream.of(TextColor.GRAY, e.getKey(), ": ", TextColor.WHITE, e.getValue(), "\n")) + .toArray(Object[]::new); + textElements[textElements.length - 1] = ""; + + return Text.of(textElements); + } + public int debugDumpCommand(CommandContext context) { final CommandSource source = commandSourceInterface.apply(context.getSource()); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java index d4f19739..4f19ab21 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java @@ -106,16 +106,7 @@ public class MapUpdateTask extends CombinedRenderTask { private static List getRegions(BmMap map, Vector2i center, int radius) { World world = map.getWorld(); Grid regionGrid = world.getRegionGrid(); - - Predicate regionFilter = r -> { - Vector2i cellMin = regionGrid.getCellMin(r); - if (cellMin.getX() > map.getMapSettings().getMaxPos().getX()) return false; - if (cellMin.getY() > map.getMapSettings().getMaxPos().getZ()) return false; - - Vector2i cellMax = regionGrid.getCellMax(r); - if (cellMax.getX() < map.getMapSettings().getMinPos().getX()) return false; - return cellMax.getY() >= map.getMapSettings().getMinPos().getZ(); - }; + Predicate regionFilter = map.getMapSettings().getRenderBoundariesCellFilter(regionGrid); if (center == null || radius < 0) { return world.listRegions().stream() diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java index e7e90c3d..5359ef7f 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java @@ -88,6 +88,7 @@ public class WorldRegionRenderTask implements RenderTask { Grid tileGrid = map.getHiresModelManager().getTileGrid(); Grid chunkGrid = map.getWorld().getChunkGrid(); + Predicate boundsTileFilter = map.getMapSettings().getRenderBoundariesCellFilter(tileGrid); for (Vector2i chunk : chunks) { Vector2i tileMin = chunkGrid.getCellMin(chunk, tileGrid); @@ -103,16 +104,6 @@ public class WorldRegionRenderTask implements RenderTask { map.getWorld().invalidateChunkCache(chunk.getX(), chunk.getY()); } - Predicate boundsTileFilter = t -> { - Vector2i cellMin = tileGrid.getCellMin(t); - if (cellMin.getX() > map.getMapSettings().getMaxPos().getX()) return false; - if (cellMin.getY() > map.getMapSettings().getMaxPos().getZ()) return false; - - Vector2i cellMax = tileGrid.getCellMax(t); - if (cellMax.getX() < map.getMapSettings().getMinPos().getX()) return false; - return cellMax.getY() >= map.getMapSettings().getMinPos().getZ(); - }; - this.tileCount = tileSet.size(); this.tiles = tileSet.stream() .sorted(WorldRegionRenderTask::compareVec2L) //sort with longs to avoid overflow (comparison uses distanceSquared) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/RenderSettings.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/RenderSettings.java index 7b8524ba..6d85cb17 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/RenderSettings.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/RenderSettings.java @@ -24,7 +24,11 @@ */ package de.bluecolored.bluemap.core.map.hires; +import com.flowpowered.math.vector.Vector2i; import com.flowpowered.math.vector.Vector3i; +import de.bluecolored.bluemap.core.util.Grid; + +import java.util.function.Predicate; public interface RenderSettings { @@ -101,6 +105,22 @@ public interface RenderSettings { y <= max.getY(); } + /** + * Returns a predicate which is filtering out all cells of a {@link Grid} + * that are completely outside the render boundaries. + */ + default Predicate getRenderBoundariesCellFilter(Grid grid) { + return t -> { + Vector2i cellMin = grid.getCellMin(t); + if (cellMin.getX() > getMaxPos().getX()) return false; + if (cellMin.getY() > getMaxPos().getZ()) return false; + + Vector2i cellMax = grid.getCellMax(t); + if (cellMax.getX() < getMinPos().getX()) return false; + return cellMax.getY() >= getMinPos().getZ(); + }; + } + boolean isSaveHiresLayer(); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java index 70afac78..71cedcba 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java @@ -34,7 +34,6 @@ import de.bluecolored.bluemap.core.world.mca.chunk.MCAChunk; import lombok.Getter; import lombok.ToString; -import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; @@ -121,7 +120,7 @@ public class MCARegion implements Region { // iterate over all chunks for (int x = 0; x < 32; x++) { for (int z = 0; z < 32; z++) { - int xzChunk = z * 32 + x; + int xzChunk = (z & 0b11111) << 5 | (x & 0b11111); int size = header[xzChunk * 4 + 3] * 4096; if (size == 0) continue; @@ -136,7 +135,7 @@ public class MCARegion implements Region { timestamp |= header[i] & 0xFF; // load chunk only if consumers filter returns true - if (consumer.filter(chunkX, chunkZ, timestamp)) { + if (consumer.filter(chunkX, chunkZ, timestamp * 1000L)) { i = xzChunk * 4; int offset = header[i++] << 16; offset |= (header[i++] & 0xFF) << 8; @@ -190,7 +189,10 @@ public class MCARegion implements Region { do { int read = src.read(bb); - if (read < 0) throw new EOFException(); + if (read < 0) + // zero out all the remaining data from the buffer + while (bb.remaining() > 0) + bb.put((byte) 0); } while (bb.remaining() > 0); } diff --git a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java index 0599b17f..87358159 100644 --- a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java +++ b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java @@ -96,7 +96,7 @@ public class BlueMapCLI { if (watch) { for (BmMap map : maps.values()) { try { - RegionFileWatchService watcher = new RegionFileWatchService(renderManager, map, true); + RegionFileWatchService watcher = new RegionFileWatchService(renderManager, map); watcher.start(); regionFileWatchServices.add(watcher); } catch (IOException ex) {