working reentrant locked tile generation
parent
574e58e40b
commit
9a2525566a
|
@ -8,12 +8,15 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import com.google.common.util.concurrent.Striped;
|
||||
import io.prometheus.client.Histogram;
|
||||
import io.rudin.minetest.tileserver.config.Layer;
|
||||
import io.rudin.minetest.tileserver.config.TileServerConfig;
|
||||
|
@ -67,6 +70,8 @@ public class TileRenderer {
|
|||
|
||||
private final int DEFAULT_BLOCK_ZOOM = 13;
|
||||
|
||||
private final Striped<ReadWriteLock> rwLockStripes = Striped.lazyWeakReadWriteLock(100);
|
||||
|
||||
public byte[] render(Layer layer, int tileX, int tileY, int zoom) throws IllegalArgumentException, DataFormatException, IOException, ExecutionException {
|
||||
return render(layer, tileX, tileY, zoom, true);
|
||||
}
|
||||
|
@ -82,6 +87,7 @@ public class TileRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
Range<MapBlockCoordinate> mapBlocksRange = CoordinateFactory.getMapBlocksInTile(new TileCoordinate(tileX, tileY, zoom));
|
||||
|
||||
int max = Math.max(
|
||||
|
@ -98,47 +104,6 @@ public class TileRenderer {
|
|||
//Out of range...
|
||||
return WhiteTile.getPNG();
|
||||
|
||||
|
||||
if (zoom < DEFAULT_BLOCK_ZOOM) {
|
||||
//TODO: fail-fast for regions without map-blocks -> white
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Result<BlocksRecord> firstResult = ctx
|
||||
.selectFrom(BLOCKS)
|
||||
.where(
|
||||
BLOCKS.POSX.ge(Math.min(mapBlocksRange.pos1.x, mapBlocksRange.pos2.x))
|
||||
.and(BLOCKS.POSX.le(Math.max(mapBlocksRange.pos1.x, mapBlocksRange.pos2.x)))
|
||||
.and(BLOCKS.POSZ.ge(Math.min(mapBlocksRange.pos1.z, mapBlocksRange.pos2.z)))
|
||||
.and(BLOCKS.POSZ.le(Math.max(mapBlocksRange.pos1.z, mapBlocksRange.pos2.z)))
|
||||
.and(yQueryBuilder.getCondition(layer))
|
||||
)
|
||||
.limit(1)
|
||||
.fetch();
|
||||
|
||||
long diff = System.currentTimeMillis() - start;
|
||||
|
||||
if (diff > 250 && cfg.logQueryPerformance()){
|
||||
logger.warn("white-count-query took {} ms", diff);
|
||||
}
|
||||
|
||||
if (firstResult.isEmpty()) {
|
||||
logger.debug("Fail-fast, got zero mapblock count for x=({})-({}) z=({})-({})",
|
||||
mapBlocksRange.pos1.x, mapBlocksRange.pos2.x,
|
||||
mapBlocksRange.pos1.z, mapBlocksRange.pos2.z);
|
||||
|
||||
byte[] data = WhiteTile.getPNG();
|
||||
|
||||
if (zoom < 11) {
|
||||
//Only cache white space in upper zoom levels
|
||||
cache.put(layer.id, tileX, tileY, zoom, data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
BufferedImage image = renderImage(layer, tileX, tileY, zoom, usecache);
|
||||
|
||||
|
@ -168,149 +133,219 @@ public class TileRenderer {
|
|||
|
||||
public BufferedImage renderImage(Layer layer, int tileX, int tileY, int zoom, boolean usecache) throws IllegalArgumentException, DataFormatException, IOException, ExecutionException {
|
||||
|
||||
//Check if binary cached, use cached version for rendering
|
||||
if (usecache && cache.has(layer.id, tileX, tileY, zoom)) {
|
||||
byte[] data = cache.get(layer.id, tileX, tileY, zoom);
|
||||
|
||||
if (data != null && data.length > 0)
|
||||
//In case the cache disappears
|
||||
return ImageIO.read(new ByteArrayInputStream(data));
|
||||
}
|
||||
|
||||
Histogram.Timer timer = renderTime.startTimer();
|
||||
ReadWriteLock rwLock = rwLockStripes.get(layer.id + "/" + tileX + "/" + tileY + "/" + zoom);
|
||||
|
||||
try {
|
||||
rwLock.readLock().lock();
|
||||
|
||||
final int HALF_TILE_PIXEL_SIZE = TILE_PIXEL_SIZE / 2;
|
||||
//Check if binary cached, use cached version for rendering
|
||||
if (usecache && cache.has(layer.id, tileX, tileY, zoom)) {
|
||||
byte[] data = cache.get(layer.id, tileX, tileY, zoom);
|
||||
|
||||
if (data != null && data.length > 0)
|
||||
//In case the cache disappears
|
||||
return ImageIO.read(new ByteArrayInputStream(data));
|
||||
}
|
||||
|
||||
} finally {
|
||||
rwLock.readLock().unlock();
|
||||
}
|
||||
|
||||
try {
|
||||
rwLock.writeLock().lock();
|
||||
|
||||
//Second cache check in critical section
|
||||
//Check if binary cached, use cached version for rendering
|
||||
if (usecache && cache.has(layer.id, tileX, tileY, zoom)) {
|
||||
byte[] data = cache.get(layer.id, tileX, tileY, zoom);
|
||||
|
||||
if (data != null && data.length > 0)
|
||||
//In case the cache disappears
|
||||
return ImageIO.read(new ByteArrayInputStream(data));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BufferedImage tile = createTile();
|
||||
|
||||
//16x16 mapblocks on a tile
|
||||
Graphics2D graphics = tile.createGraphics();
|
||||
|
||||
graphics.setColor(Color.WHITE);
|
||||
graphics.fillRect(0, 0, TILE_PIXEL_SIZE, TILE_PIXEL_SIZE);
|
||||
|
||||
Range<MapBlockCoordinate> mapBlocksRange = CoordinateFactory.getMapBlocksInTile(new TileCoordinate(tileX, tileY, zoom));
|
||||
|
||||
int max = Math.max(
|
||||
Math.max(mapBlocksRange.pos1.x, mapBlocksRange.pos1.z),
|
||||
Math.max(mapBlocksRange.pos2.x, mapBlocksRange.pos2.x)
|
||||
);
|
||||
|
||||
int min = Math.min(
|
||||
Math.min(mapBlocksRange.pos1.x, mapBlocksRange.pos1.z),
|
||||
Math.min(mapBlocksRange.pos2.x, mapBlocksRange.pos2.x)
|
||||
);
|
||||
|
||||
if (max > 2048 || min < -2048)
|
||||
//Out of range...
|
||||
return tile;
|
||||
|
||||
|
||||
if (zoom < DEFAULT_BLOCK_ZOOM) {
|
||||
//Zoom out
|
||||
|
||||
|
||||
BufferedImage tile = createTile();
|
||||
//Pack 4 tiles from higher zoom into 1 tile
|
||||
|
||||
TileQuadrants quadrants = CoordinateFactory.getZoomedQuadrantsFromTile(new TileCoordinate(tileX, tileY, zoom));
|
||||
|
||||
int nextZoom = zoom + 1;
|
||||
int nextZoomX = tileX * 2;
|
||||
int nextZoomY = tileY * 2;
|
||||
|
||||
BufferedImage upperLeft = renderImage(layer, quadrants.upperLeft.x, quadrants.upperLeft.y, quadrants.upperLeft.zoom);
|
||||
BufferedImage upperRightImage = renderImage(layer, quadrants.upperRight.x, quadrants.upperRight.y, quadrants.upperRight.zoom);
|
||||
BufferedImage lowerLeftImage = renderImage(layer, quadrants.lowerLeft.x, quadrants.lowerLeft.y, quadrants.lowerLeft.zoom);
|
||||
BufferedImage lowerRightImage = renderImage(layer, quadrants.lowerRight.x, quadrants.lowerRight.y, quadrants.lowerRight.zoom);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Graphics2D graphics = tile.createGraphics();
|
||||
Result<BlocksRecord> firstResult = ctx
|
||||
.selectFrom(BLOCKS)
|
||||
.where(
|
||||
BLOCKS.POSX.ge(Math.min(mapBlocksRange.pos1.x, mapBlocksRange.pos2.x))
|
||||
.and(BLOCKS.POSX.le(Math.max(mapBlocksRange.pos1.x, mapBlocksRange.pos2.x)))
|
||||
.and(BLOCKS.POSZ.ge(Math.min(mapBlocksRange.pos1.z, mapBlocksRange.pos2.z)))
|
||||
.and(BLOCKS.POSZ.le(Math.max(mapBlocksRange.pos1.z, mapBlocksRange.pos2.z)))
|
||||
.and(yQueryBuilder.getCondition(layer))
|
||||
)
|
||||
.limit(1)
|
||||
.fetch();
|
||||
|
||||
Image upperLeftScaledInstance = upperLeft.getScaledInstance(HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, Image.SCALE_FAST);
|
||||
graphics.drawImage(upperLeftScaledInstance, 0, 0, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, null);
|
||||
if (firstResult.size() == 0){
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
|
||||
Image upperRightScaledInstance = upperRightImage.getScaledInstance(HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, Image.SCALE_FAST);
|
||||
graphics.drawImage(upperRightScaledInstance, HALF_TILE_PIXEL_SIZE, 0, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, null);
|
||||
|
||||
Image lowerLeftScaledInstance = lowerLeftImage.getScaledInstance(HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, Image.SCALE_FAST);
|
||||
graphics.drawImage(lowerLeftScaledInstance, 0, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, null);
|
||||
Histogram.Timer timer = renderTime.startTimer();
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Image lowerRightScaledInstance = lowerRightImage.getScaledInstance(HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, Image.SCALE_FAST);
|
||||
graphics.drawImage(lowerRightScaledInstance, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, null);
|
||||
try {
|
||||
|
||||
final int HALF_TILE_PIXEL_SIZE = TILE_PIXEL_SIZE / 2;
|
||||
|
||||
|
||||
if (zoom < DEFAULT_BLOCK_ZOOM) {
|
||||
//Zoom out
|
||||
|
||||
logger.debug("Rendering tile: X={}, Y={} zoom={}", tileX, tileY, zoom);
|
||||
|
||||
//Pack 4 tiles from higher zoom into 1 tile
|
||||
|
||||
TileQuadrants quadrants = CoordinateFactory.getZoomedQuadrantsFromTile(new TileCoordinate(tileX, tileY, zoom));
|
||||
|
||||
int nextZoom = zoom + 1;
|
||||
int nextZoomX = tileX * 2;
|
||||
int nextZoomY = tileY * 2;
|
||||
|
||||
BufferedImage upperLeft = renderImage(layer, quadrants.upperLeft.x, quadrants.upperLeft.y, quadrants.upperLeft.zoom);
|
||||
BufferedImage upperRightImage = renderImage(layer, quadrants.upperRight.x, quadrants.upperRight.y, quadrants.upperRight.zoom);
|
||||
BufferedImage lowerLeftImage = renderImage(layer, quadrants.lowerLeft.x, quadrants.lowerLeft.y, quadrants.lowerLeft.zoom);
|
||||
BufferedImage lowerRightImage = renderImage(layer, quadrants.lowerRight.x, quadrants.lowerRight.y, quadrants.lowerRight.zoom);
|
||||
|
||||
Image upperLeftScaledInstance = upperLeft.getScaledInstance(HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, Image.SCALE_FAST);
|
||||
graphics.drawImage(upperLeftScaledInstance, 0, 0, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, null);
|
||||
|
||||
Image upperRightScaledInstance = upperRightImage.getScaledInstance(HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, Image.SCALE_FAST);
|
||||
graphics.drawImage(upperRightScaledInstance, HALF_TILE_PIXEL_SIZE, 0, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, null);
|
||||
|
||||
Image lowerLeftScaledInstance = lowerLeftImage.getScaledInstance(HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, Image.SCALE_FAST);
|
||||
graphics.drawImage(lowerLeftScaledInstance, 0, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, null);
|
||||
|
||||
Image lowerRightScaledInstance = lowerRightImage.getScaledInstance(HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, Image.SCALE_FAST);
|
||||
graphics.drawImage(lowerRightScaledInstance, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, HALF_TILE_PIXEL_SIZE, null);
|
||||
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream(12000);
|
||||
ImageIO.write(tile, "png", output);
|
||||
|
||||
byte[] data = output.toByteArray();
|
||||
|
||||
long diff = System.currentTimeMillis() - start;
|
||||
|
||||
logger.trace("Timings of cross-stitched tile X={} Y={} Zoom={}: render={} ms", tileX, tileY, zoom, diff);
|
||||
|
||||
cache.put(layer.id, tileX, tileY, zoom, data);
|
||||
|
||||
if (tile == null)
|
||||
logger.error("Got a null-tile @ {}/{}/{} (data={})", tileX, tileY, zoom, data.length);
|
||||
|
||||
return tile;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Range<MapBlockCoordinate> coordinateRange = CoordinateFactory.getMapBlocksInTile(new TileCoordinate(tileX, tileY, zoom));
|
||||
|
||||
|
||||
int mapblockX = coordinateRange.pos1.x;
|
||||
int mapblockZ = coordinateRange.pos1.z;
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
long timingImageSetup = now - start;
|
||||
start = now;
|
||||
|
||||
|
||||
Result<BlocksRecord> countList = ctx
|
||||
.selectFrom(BLOCKS)
|
||||
.where(
|
||||
BLOCKS.POSX.eq(mapblockX)
|
||||
.and(BLOCKS.POSZ.eq(mapblockZ))
|
||||
.and(yQueryBuilder.getCondition(layer))
|
||||
)
|
||||
.limit(1)
|
||||
.fetch();
|
||||
|
||||
now = System.currentTimeMillis();
|
||||
long timingZeroCountCheck = now - start;
|
||||
|
||||
if (timingZeroCountCheck > 250 && cfg.logQueryPerformance()) {
|
||||
logger.warn("count-zero-check took {} ms", timingZeroCountCheck);
|
||||
}
|
||||
|
||||
start = now;
|
||||
|
||||
long timingRender = 0;
|
||||
|
||||
if (!countList.isEmpty()) {
|
||||
logger.debug("Rendering tile for mapblock: X={}, Z={}", mapblockX, mapblockZ);
|
||||
blockRenderer.render(
|
||||
YQueryBuilder.coordinateToMapBlock(layer.from),
|
||||
YQueryBuilder.coordinateToMapBlock(layer.to),
|
||||
mapblockX,
|
||||
mapblockZ,
|
||||
graphics, 16
|
||||
);
|
||||
|
||||
now = System.currentTimeMillis();
|
||||
timingRender = now - start;
|
||||
start = now;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream(12000);
|
||||
ImageIO.write(tile, "png", output);
|
||||
|
||||
byte[] data = output.toByteArray();
|
||||
|
||||
long diff = System.currentTimeMillis() - start;
|
||||
now = System.currentTimeMillis();
|
||||
long timingBufferOutput = now - start;
|
||||
|
||||
logger.trace("Timings of cross-stitched tile X={} Y={} Zoom={}: render={} ms", tileX, tileY, zoom, diff);
|
||||
|
||||
logger.debug("Timings of tile X={} Y={} Zoom={}: setup={} ms, zeroCheck={} ms, render={} ms, output={} ms",
|
||||
tileX, tileY, zoom,
|
||||
timingImageSetup, timingZeroCountCheck, timingRender, timingBufferOutput
|
||||
);
|
||||
|
||||
cache.put(layer.id, tileX, tileY, zoom, data);
|
||||
|
||||
if (tile == null)
|
||||
logger.error("Got a null-tile @ {}/{}/{} (data={})", tileX, tileY, zoom, data.length);
|
||||
logger.error("Got a null-tile @ {}/{}/{} (layer={},data={})", tileX, tileY, zoom, layer.id, data.length);
|
||||
|
||||
return tile;
|
||||
|
||||
} finally {
|
||||
timer.observeDuration();
|
||||
|
||||
}
|
||||
|
||||
//Default zoom (13 == 1 mapblock with 16px wide blocks)
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Range<MapBlockCoordinate> coordinateRange = CoordinateFactory.getMapBlocksInTile(new TileCoordinate(tileX, tileY, zoom));
|
||||
|
||||
//16x16 mapblocks on a tile
|
||||
BufferedImage image = createTile();
|
||||
Graphics2D graphics = image.createGraphics();
|
||||
|
||||
graphics.setColor(Color.WHITE);
|
||||
graphics.fillRect(0, 0, TILE_PIXEL_SIZE, TILE_PIXEL_SIZE);
|
||||
|
||||
|
||||
int mapblockX = coordinateRange.pos1.x;
|
||||
int mapblockZ = coordinateRange.pos1.z;
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
long timingImageSetup = now - start;
|
||||
start = now;
|
||||
|
||||
|
||||
Result<BlocksRecord> countList = ctx
|
||||
.selectFrom(BLOCKS)
|
||||
.where(
|
||||
BLOCKS.POSX.eq(mapblockX)
|
||||
.and(BLOCKS.POSZ.eq(mapblockZ))
|
||||
.and(yQueryBuilder.getCondition(layer))
|
||||
)
|
||||
.limit(1)
|
||||
.fetch();
|
||||
|
||||
now = System.currentTimeMillis();
|
||||
long timingZeroCountCheck = now - start;
|
||||
|
||||
if (timingZeroCountCheck > 250 && cfg.logQueryPerformance()) {
|
||||
logger.warn("count-zero-check took {} ms", timingZeroCountCheck);
|
||||
}
|
||||
|
||||
start = now;
|
||||
|
||||
long timingRender = 0;
|
||||
|
||||
if (!countList.isEmpty()) {
|
||||
logger.debug("Rendering tile for mapblock: X={}, Z={}", mapblockX, mapblockZ);
|
||||
blockRenderer.render(layer.from, layer.to, mapblockX, mapblockZ, graphics, 16);
|
||||
|
||||
now = System.currentTimeMillis();
|
||||
timingRender = now - start;
|
||||
start = now;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream(12000);
|
||||
ImageIO.write(image, "png", output);
|
||||
|
||||
byte[] data = output.toByteArray();
|
||||
|
||||
now = System.currentTimeMillis();
|
||||
long timingBufferOutput = now - start;
|
||||
|
||||
|
||||
logger.trace("Timings of tile X={} Y={} Zoom={}: setup={} ms, zeroCheck={} ms, render={} ms, output={} ms",
|
||||
tileX, tileY, zoom,
|
||||
timingImageSetup, timingZeroCountCheck, timingRender, timingBufferOutput
|
||||
);
|
||||
|
||||
cache.put(layer.id, tileX, tileY, zoom, data);
|
||||
|
||||
if (image == null)
|
||||
logger.error("Got a null-tile @ {}/{}/{} (layer={},data={})", tileX, tileY, zoom, layer.id, data.length);
|
||||
|
||||
return image;
|
||||
|
||||
} finally {
|
||||
timer.observeDuration();
|
||||
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ public class UpdateChangedTilesJob implements Runnable {
|
|||
private final EventBus eventBus;
|
||||
|
||||
private final DSLContext ctx;
|
||||
|
||||
|
||||
private final TileCache tileCache;
|
||||
|
||||
private boolean running = false;
|
||||
|
@ -235,9 +235,28 @@ public class UpdateChangedTilesJob implements Runnable {
|
|||
|
||||
logger.debug("Got {} updated blocks", blocks.size());
|
||||
|
||||
//invalidation run
|
||||
for (BlocksRecord record : blocks) {
|
||||
blocksRecordService.update(record);
|
||||
mapBlockAccessor.invalidate(new Coordinate(record));
|
||||
|
||||
if (record.getMtime() > latestTimestamp)
|
||||
latestTimestamp = record.getMtime();
|
||||
|
||||
Integer x = record.getPosx();
|
||||
Integer z = record.getPosz();
|
||||
|
||||
TileCoordinate tileCoordinate = CoordinateFactory.getTileCoordinateFromMapBlock(new MapBlockCoordinate(x, z));
|
||||
|
||||
for (int i = CoordinateFactory.MAX_ZOOM; i > 0; i--) {
|
||||
tileCache.remove(layer.id, tileCoordinate.x, tileCoordinate.y, tileCoordinate.zoom);
|
||||
invalidatedTiles++;
|
||||
|
||||
//Zoom out
|
||||
if (i > 1) {
|
||||
tileCoordinate = CoordinateFactory.getZoomedOutTile(tileCoordinate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//assign new timestamp
|
||||
|
@ -251,7 +270,7 @@ public class UpdateChangedTilesJob implements Runnable {
|
|||
|
||||
List<String> updatedTileKeys = new ArrayList<>();
|
||||
|
||||
//run with rendering of other zoom levels, but cached
|
||||
//tile re-rendering
|
||||
for (BlocksRecord record : blocks) {
|
||||
|
||||
Integer x = record.getPosx();
|
||||
|
@ -259,7 +278,7 @@ public class UpdateChangedTilesJob implements Runnable {
|
|||
|
||||
TileCoordinate tileCoordinate = CoordinateFactory.getTileCoordinateFromMapBlock(new MapBlockCoordinate(x, z));
|
||||
|
||||
for (int i = CoordinateFactory.MAX_ZOOM; i >= 3; i--) {
|
||||
for (int i = CoordinateFactory.MAX_ZOOM; i > 0; i--) {
|
||||
|
||||
String tileKey = getTileKey(tileCoordinate);
|
||||
|
||||
|
@ -269,7 +288,7 @@ public class UpdateChangedTilesJob implements Runnable {
|
|||
logger.debug("Rendering tile x={} y={} zoom={}", tileCoordinate.x, tileCoordinate.y, tileCoordinate.zoom);
|
||||
tileRenderer.render(layer, tileCoordinate.x, tileCoordinate.y, tileCoordinate.zoom);
|
||||
|
||||
logger.debug("Dispatching tile-changed-event for tile: {}/{}", tileCoordinate.x, tileCoordinate.y);
|
||||
logger.debug("Dispatching tile-changed-event for tile: {}/{} zoom:{}", tileCoordinate.x, tileCoordinate.y, tileCoordinate.zoom);
|
||||
|
||||
EventBus.TileChangedEvent event = new EventBus.TileChangedEvent();
|
||||
event.layerId = layer.id;
|
||||
|
@ -289,7 +308,9 @@ public class UpdateChangedTilesJob implements Runnable {
|
|||
}
|
||||
|
||||
//zom out
|
||||
tileCoordinate = CoordinateFactory.getZoomedOutTile(tileCoordinate);
|
||||
if (i > 1) {
|
||||
tileCoordinate = CoordinateFactory.getZoomedOutTile(tileCoordinate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ public class CoordinateFactory {
|
|||
*/
|
||||
public static TileCoordinate getTileCoordinateFromMapBlock(MapBlockCoordinate mapBlock){
|
||||
//Inverted and offsetet z-axis
|
||||
return new TileCoordinate(mapBlock.x, (mapBlock.z * -1) + 1, MAX_ZOOM);
|
||||
return new TileCoordinate(mapBlock.x, (mapBlock.z + 1) * -1, MAX_ZOOM);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
|
||||
<logger name="org.jooq" level="WARN"/>
|
||||
<logger name="io.rudin.minetest.tileserver.job.UpdateChangedTilesJob" level="INFO"/>
|
||||
<logger name="io.rudin.minetest.tileserver.MapBlockRenderer" level="INFO"/>
|
||||
<logger name="io.rudin.minetest.tileserver.TileRenderer" level="INFO"/>
|
||||
<logger name="io.rudin.minetest.tileserver.service.impl.DefaultMapBlockRenderService" level="INFO"/>
|
||||
<logger name="io.rudin.minetest.tileserver.TileRenderer" level="DEBUG"/>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="logfile" />
|
||||
|
|
|
@ -12,19 +12,19 @@ public class CoordinateFactoryTest {
|
|||
MapBlockCoordinate mapBlock = new MapBlockCoordinate(0,0);
|
||||
TileCoordinate tileCoordinate = CoordinateFactory.getTileCoordinateFromMapBlock(mapBlock);
|
||||
Assert.assertEquals(0, tileCoordinate.x);
|
||||
Assert.assertEquals(1, tileCoordinate.y);
|
||||
Assert.assertEquals(-1, tileCoordinate.y);
|
||||
Assert.assertEquals(13, tileCoordinate.zoom);
|
||||
|
||||
mapBlock = new MapBlockCoordinate(1,1);
|
||||
tileCoordinate = CoordinateFactory.getTileCoordinateFromMapBlock(mapBlock);
|
||||
Assert.assertEquals(1, tileCoordinate.x);
|
||||
Assert.assertEquals(0, tileCoordinate.y);
|
||||
Assert.assertEquals(-2, tileCoordinate.y);
|
||||
Assert.assertEquals(13, tileCoordinate.zoom);
|
||||
|
||||
mapBlock = new MapBlockCoordinate(-1,-1);
|
||||
tileCoordinate = CoordinateFactory.getTileCoordinateFromMapBlock(mapBlock);
|
||||
Assert.assertEquals(-1, tileCoordinate.x);
|
||||
Assert.assertEquals(2, tileCoordinate.y);
|
||||
Assert.assertEquals(0, tileCoordinate.y);
|
||||
Assert.assertEquals(13, tileCoordinate.zoom);
|
||||
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class UpdateChangedTilesTest extends TileServerTest {
|
|||
byte[] tile = tileCache.get(0, tileCoordinate.x, tileCoordinate.y, tileCoordinate.zoom);
|
||||
Assert.assertNull(tile);
|
||||
|
||||
logger.debug("First result: {}", changedTilesJob.updateChangedTiles());
|
||||
logger.debug("First result (init): {}", changedTilesJob.updateChangedTiles());
|
||||
|
||||
tile = tileCache.get(0, tileCoordinate.x, tileCoordinate.y, tileCoordinate.zoom);
|
||||
Assert.assertNotNull(tile);
|
||||
|
@ -56,7 +56,12 @@ public class UpdateChangedTilesTest extends TileServerTest {
|
|||
block.setMtime(System.currentTimeMillis());
|
||||
block.update();
|
||||
|
||||
logger.debug("Second result: {}", changedTilesJob.updateChangedTiles());
|
||||
logger.debug("Second result (changed): {}", changedTilesJob.updateChangedTiles());
|
||||
|
||||
tile = tileCache.get(0, tileCoordinate.x, tileCoordinate.y, tileCoordinate.zoom);
|
||||
Assert.assertNotNull(tile);
|
||||
|
||||
logger.debug("Third result (unchanged): {}", changedTilesJob.updateChangedTiles());
|
||||
|
||||
tile = tileCache.get(0, tileCoordinate.x, tileCoordinate.y, tileCoordinate.zoom);
|
||||
Assert.assertNotNull(tile);
|
||||
|
|
Loading…
Reference in New Issue