Fix Map-Updates not working correctly

This commit is contained in:
Lukas Rieger (Blue) 2024-02-22 12:58:57 +01:00
parent 2dd7a0a9c2
commit ff1e38a7e1
No known key found for this signature in database
GPG Key ID: AA33883B1BBA03E6
9 changed files with 75 additions and 52 deletions

@ -1 +1 @@
Subproject commit c7a9be42adda14482f0e52ef55cb43fdc12d9502
Subproject commit 6cad751ac59286a516007799bcad3f2868e0a802

View File

@ -553,7 +553,7 @@ public synchronized void startWatchingMap(BmMap map) {
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) {

View File

@ -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<Vector2i, TimerTask> 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 RegionFileWatchService(RenderManager renderManager, BmMap map, boolean ve
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();
@ -98,13 +99,14 @@ public void run() {
} catch (ClosedWatchServiceException ignore) {
} catch (InterruptedException iex) {
Thread.currentThread().interrupt();
}
} 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)");
}
}
}
private synchronized void updateRegion(String regionFileName) {
if (!regionFileName.endsWith(".mca")) return;
@ -118,7 +120,7 @@ private synchronized void updateRegion(String regionFileName) {
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 void run() {
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) {}
}

View File

@ -53,14 +53,16 @@
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<S> {
@ -501,24 +503,39 @@ public int debugBlockCommand(CommandContext<S> context) {
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<String, Object> 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<S> context) {
final CommandSource source = commandSourceInterface.apply(context.getSource());

View File

@ -106,16 +106,7 @@ private static List<Vector2i> getRegions(BmMap map) {
private static List<Vector2i> getRegions(BmMap map, Vector2i center, int radius) {
World world = map.getWorld();
Grid regionGrid = world.getRegionGrid();
Predicate<Vector2i> 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<Vector2i> regionFilter = map.getMapSettings().getRenderBoundariesCellFilter(regionGrid);
if (center == null || radius < 0) {
return world.listRegions().stream()

View File

@ -88,6 +88,7 @@ private synchronized void init() {
Grid tileGrid = map.getHiresModelManager().getTileGrid();
Grid chunkGrid = map.getWorld().getChunkGrid();
Predicate<Vector2i> boundsTileFilter = map.getMapSettings().getRenderBoundariesCellFilter(tileGrid);
for (Vector2i chunk : chunks) {
Vector2i tileMin = chunkGrid.getCellMin(chunk, tileGrid);
@ -103,16 +104,6 @@ private synchronized void init() {
map.getWorld().invalidateChunkCache(chunk.getX(), chunk.getY());
}
Predicate<Vector2i> 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)

View File

@ -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 @@ default boolean isInsideRenderBoundaries(int x, int y, int z) {
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<Vector2i> 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();
}

View File

@ -34,7 +34,6 @@
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 void iterateAllChunks(ChunkConsumer consumer) throws IOException {
// 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 void iterateAllChunks(ChunkConsumer consumer) throws IOException {
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 @@ private static void readFully(ReadableByteChannel src, ByteBuffer bb, int off, i
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);
}

View File

@ -96,7 +96,7 @@ public void renderMaps(BlueMapService blueMap, boolean watch, boolean forceRende
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) {