diff --git a/ppfun-bridge/src/pixelplanet/loadChunk.js b/ppfun-bridge/src/pixelplanet/loadChunk.js index a597df9..6c260a3 100644 --- a/ppfun-bridge/src/pixelplanet/loadChunk.js +++ b/ppfun-bridge/src/pixelplanet/loadChunk.js @@ -1,4 +1,5 @@ import fetch from 'node-fetch'; +import sharp from 'sharp'; import { TILE_SIZE, @@ -9,7 +10,6 @@ async function fetchBaseChunk( palette, zoom, cx, cy, - tile, ) { const url = `https://pixelplanet.fun/chunks/${canvasId}/${cx}/${cy}.bmp`; console.log(`Fetching ${url}`); @@ -24,10 +24,17 @@ async function fetchBaseChunk( throw new Error(`Chunk faulty or not found`); } -function fetchTile(canvasId, zoom, cx, cy, tile) { +async function fetchTile(canvasId, zoom, cx, cy) { const url = `https://pixelplanet.fun/tiles/${canvasId}/${zoom}/${cx}/${cy}.webp`; console.log(`Fetching ${url}`); - return sharp(url).removeAlpha().raw().toBuffer(); + const response = await fetch(url); + if (response.ok) { + const arrayBuffer = await response.arrayBuffer(); + if (arrayBuffer.byteLength) { + return sharp(arrayBuffer).removeAlpha().raw().toBuffer(); + } + } + throw new Error(`Chunk faulty or not found`); } /** @@ -47,13 +54,12 @@ export default async function ( const canvasId = canvas.id; try { if (canvas.maxTiledZoom === zoom) { - return await fetchBaseChunk(canvasId, canvas.palette, zoom, cx, cy, tile); + return await fetchBaseChunk(canvasId, canvas.palette, zoom, cx, cy); } else { - return await fetchTile(canvasId, zoom, cx, cy, tile); + return await fetchTile(canvasId, zoom, cx, cy); } - } catch () { - console.log(`Chunk ${cx} / ${cy} - ${zoom} is empty of faulty`); - return Buffer.allocUnsafe(0); + } catch (err) { + console.log(`Chunk ${cx} / ${cy} - ${zoom}: ${err.message}`); + return Buffer.allocUnsafe(0); } - return tile; } diff --git a/ppfun-bridge/src/pixelplanet/renderCanvas.js b/ppfun-bridge/src/pixelplanet/renderCanvas.js index 2dc7a4c..ed7939d 100644 --- a/ppfun-bridge/src/pixelplanet/renderCanvas.js +++ b/ppfun-bridge/src/pixelplanet/renderCanvas.js @@ -32,17 +32,13 @@ async function fillRect( h += y; y = 0; } - if (w > width) { - w = width; + if (w + x > width) { + w = width - x; } - if (h > height) { - h = height; + if (h + y > height) { + h = height - y; } - if (w < 0 || h < 0) { - // out of image bounds - return; - } - const rowMax = r + h; + const rowMax = y + h; for (let row = y; row < rowMax; row += 1) { let pos = (row * width + x) * 3; const max = pos + w * 3; @@ -62,27 +58,27 @@ async function drawChunk( const chunkBuffer = await getChunk(canvas, tiledZoom, xc, yc); const [ emptyR, emptyG, emptyB ] = canvas.palette.rgb; let row = Math.max(-yOff, 0); - const rowMax = Math.min(TILE_SIZE - yOff + height, TILE_SIZE); + const rowMax = (TILE_SIZE + yOff > height) ? height - yOff : TILE_SIZE; const colMin = Math.max(-xOff, 0); - const colMax = Math.min(TILE_SIZE - xOff + width, TILE_SIZE); + const colMax = (TILE_SIZE + xOff > width) ? width - xOff : TILE_SIZE; if (colMax < 0 || rowMax < 0) { // out of image bounds return; } const cutWidth = colMax - colMin; for (; row < rowMax; row += 1) { - let pos = (row * TILE_SIZE + colMin) * 3; + let ib = (row * TILE_SIZE + colMin) * 3; + let pos = ((row + yOff) * width + colMin + xOff) * 3; const max = pos + cutWidth * 3; - let ib = ((row + yOff) * width + colMin + xOff) * 3; while (pos < max) { - if (pos < chunkBuffer.length) { - buffer[ib++] = chunkBuffer[pos++]; - buffer[ib++] = chunkBuffer[pos++]; - buffer[ib++] = chunkBuffer[pos++]; + if (ib < chunkBuffer.byteLength) { + buffer[pos++] = chunkBuffer[ib++]; + buffer[pos++] = chunkBuffer[ib++]; + buffer[pos++] = chunkBuffer[ib++]; } else { - buffer[ib++] = emptyR; - buffer[ib++] = emptyG; - buffer[ib++] = emptyB; + buffer[pos++] = emptyR; + buffer[pos++] = emptyG; + buffer[pos++] = emptyB; } } } @@ -98,6 +94,7 @@ async function drawChunk( * @param height height of image (optional) */ export default async function renderCanvas( + title, canvas, x, y, @@ -125,10 +122,10 @@ export default async function renderCanvas( const relScaleW = width / unscaledWidth; const relScaleH = height / unscaledHeight; // canvas coordinates of corners - const tlX = Math.floor(x - unscaledWidth / 2 / relScaleW); - const tlY = Math.floor(y - unscaledHeight / 2 / relScaleH); - const brX = Math.floor(x - 1 + unscaledWidth / 2 / relScaleW); - const brY = Math.floor(y - 1 + unscaledHeight / 2 / relScaleH); + const tlX = Math.floor(x - width / 2 / scale); + const tlY = Math.floor(y - height / 2 / scale); + const brX = Math.floor(x - 1 + width / 2 / scale); + const brY = Math.floor(y - 1 + height / 2 / scale); // chunk coordinates of chunks in corners const tlCX = coordToChunk(tlX, canvasSize, tiledScale); const tlCY = coordToChunk(tlY, canvasSize, tiledScale); @@ -142,10 +139,11 @@ export default async function renderCanvas( const promises = []; for (let xc = tlCX; xc <= brCX; xc += 1) { for (let yc = tlCY; yc <= brCY; yc += 1) { - const xOff = chunkToCoord(xc, canvasSize, tiledScale) - tlX; - const yOff = chunkToCoord(yc, canvasSize, tiledScale) - tlY; + const xOff = Math.round((chunkToCoord(xc, canvasSize, tiledScale) - tlX) * tiledScale); + const yOff = Math.round((chunkToCoord(yc, canvasSize, tiledScale) - tlY) * tiledScale); if (xc < 0 || xc >= chunkMax || yc < 0 || yc >= chunkMax) { // out of canvas bounds + console.log(`Chunk ${xc}, ${yc} out of canvas bounds`); promises.push( fillRect( pixelBuffer, unscaledWidth, unscaledHeight, @@ -153,14 +151,15 @@ export default async function renderCanvas( ...BACKGROUND_CLR_RGB, ), ); + } else { + promises.push( + drawChunk( + pixelBuffer, unscaledWidth, unscaledHeight, + xOff, yOff, + canvas, tiledZoom, xc, yc, + ), + ); } - promises.push( - drawChunk( - pixelBuffer, unscaledWidth, unscaledHeight, - xOff, yOff, - canvas, tiledZoom, xc, yc, - ), - ); } } await Promise.all(promises); @@ -172,13 +171,13 @@ export default async function renderCanvas( channels: 3, }, }) - .resize({ width, height }) + .resize({ width, height, kernel: 'nearest' }) .png() .toBuffer(); return { - image: imageBuffer.buffer, - name: `ppfun-snap-${canvas.title}_${x}_${y}_${z}.png`, + image: imageBuffer, + name: `ppfun-snap-${title}.png`, type: 'image/png', w: width, h: height, diff --git a/ppfun-bridge/src/ppfunMatrixBridge.js b/ppfun-bridge/src/ppfunMatrixBridge.js index c66e19f..14375b1 100644 --- a/ppfun-bridge/src/ppfunMatrixBridge.js +++ b/ppfun-bridge/src/ppfunMatrixBridge.js @@ -177,10 +177,12 @@ class PPfunMatrixBridge { const userId = event.sender; - // block none :pixelplanet.fun users + /* + * block none :pixelplanet.fun users if (!userId.endsWith(this.domain)) { return; } + */ const uid = (userId.startsWith(`@${this.prefix}_`) && userId.endsWith(this.domain)) @@ -239,7 +241,7 @@ class PPfunMatrixBridge { async run() { console.log('STARTING MATRIX CONNECTION'); - await this.matrixBridge.run(this.port, null, 'localhost'); + await this.matrixBridge.run(this.port, null, '127.0.0.1'); console.log('STARTING PPFUN CONNECTION'); await this.ppfunSocket.run(); console.log('BRIDGE CONNECTED');