mirror of
https://github.com/SwingTheVine/Wplace-BlueMarble.git
synced 2026-04-20 14:22:05 +00:00
Multi-Tile templates sorta work
This commit is contained in:
parent
f84fbea0ce
commit
031f114433
8 changed files with 102 additions and 30 deletions
4
dist/BlueMarble.user.js
vendored
4
dist/BlueMarble.user.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -35,7 +35,7 @@
|
|||
<a href="https://github.com/SwingTheVine/Wplace-BlueMarble/blob/main/LICENSE.txt" target="_blank"><img alt="Software License: MPL-2.0" src="https://img.shields.io/badge/Software_License-MPL--2.0-brightgreen?style=flat"></a>
|
||||
<a href="https://discord.gg/tpeBPy46hf" target="_blank"><img alt="Contact Me" src="https://img.shields.io/badge/Contact_Me-gray?style=flat&logo=Discord&logoColor=white&logoSize=auto&labelColor=cornflowerblue"></a>
|
||||
<a href="" target="_blank"><img alt="WakaTime" src="https://img.shields.io/badge/Coding_Time-59hrs_0mins-blue?style=flat&logo=wakatime&logoColor=black&logoSize=auto&labelColor=white"></a>
|
||||
<a href="" target="_blank"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-405-black?style=flat"></a>
|
||||
<a href="" target="_blank"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-428-black?style=flat"></a>
|
||||
<a href="" target="_blank"><img alt="Total Lines of Code" src="https://tokei.rs/b1/github/SwingTheVine/Wplace-BlueMarble?category=code"></a>
|
||||
<a href="" target="_blank"><img alt="Total Comments" src="https://tokei.rs/b1/github/SwingTheVine/Wplace-BlueMarble?category=comments"></a>
|
||||
<a href="" target="_blank"><img alt="Compression" src="https://img.shields.io/badge/Compression-73.03%25-blue"></a>
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.65.51",
|
||||
"version": "0.65.74",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.65.51",
|
||||
"version": "0.65.74",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"terser": "^5.43.1"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.65.51",
|
||||
"version": "0.65.74",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "node build/build.js",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name Blue Marble
|
||||
// @namespace https://github.com/SwingTheVine/
|
||||
// @version 0.65.51
|
||||
// @version 0.65.74
|
||||
// @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA.
|
||||
// @author SwingTheVine
|
||||
// @license MPL-2.0
|
||||
|
|
|
|||
|
|
@ -76,27 +76,31 @@ export default class Template {
|
|||
|
||||
console.log(`Draw Size X: ${drawSizeX}\nDraw Size Y: ${drawSizeY}`);
|
||||
|
||||
console.log(`Draw X: ${drawSizeX}\nDraw Y: ${drawSizeY}\nCanvas Width: ${drawSizeX * shreadSize}\nCanvas Height: ${drawSizeY * shreadSize}`);
|
||||
|
||||
// Change the canvas size and wipe the canvas
|
||||
canvas.width = drawSizeX * shreadSize;
|
||||
canvas.height = drawSizeY * shreadSize;
|
||||
const canvasWidth = (drawSizeX * shreadSize) + (this.coords[2] * shreadSize);
|
||||
const canvasHeight = (drawSizeY * shreadSize) + (this.coords[3] * shreadSize);
|
||||
canvas.width = canvasWidth;
|
||||
canvas.height = canvasHeight;
|
||||
|
||||
console.log(`Draw X: ${drawSizeX}\nDraw Y: ${drawSizeY}\nCanvas Width: ${canvasWidth}\nCanvas Height: ${canvasHeight}`);
|
||||
|
||||
context.imageSmoothingEnabled = false; // Nearest neighbor
|
||||
|
||||
console.log(`Getting X ${pixelX}-${pixelX + drawSizeX}\nGetting Y ${pixelY}-${pixelY + drawSizeY}`);
|
||||
|
||||
// Draws the template segment on this tile segment
|
||||
context.clearRect(0, 0, drawSizeX * shreadSize, drawSizeY * shreadSize); // Clear any previous drawing (only runs when canvas size does not change)
|
||||
context.drawImage(bitmap, pixelX, pixelY, drawSizeX, drawSizeY, 0, 0, drawSizeX * shreadSize, drawSizeY * shreadSize); // Coordinates and size of draw area of source image, then canvas
|
||||
context.clearRect(0, 0, canvasWidth, canvasHeight); // Clear any previous drawing (only runs when canvas size does not change)
|
||||
context.drawImage(bitmap, pixelX - this.coords[2], pixelY - this.coords[3], drawSizeX, drawSizeY, (pixelX % this.tileSize) * shreadSize, (pixelY % this.tileSize) * shreadSize, drawSizeX * shreadSize, drawSizeY * shreadSize); // Coordinates and size of draw area of source image, then canvas
|
||||
|
||||
const imageData = context.getImageData(0, 0, drawSizeX * shreadSize, drawSizeY * shreadSize); // Data of the image on the canvas
|
||||
const imageData = context.getImageData(0, 0, canvasWidth, canvasHeight); // Data of the image on the canvas
|
||||
|
||||
for (let y = 0; y < drawSizeY * shreadSize; y++) {
|
||||
for (let x = 0; x < drawSizeX * shreadSize; x++) {
|
||||
for (let y = 0; y < canvasHeight; y++) {
|
||||
for (let x = 0; x < canvasWidth; x++) {
|
||||
// For every pixel...
|
||||
|
||||
// ... Make it transparent unless it is the "center"
|
||||
if ((x % shreadSize !== 1) || (y % shreadSize !== 1)) {
|
||||
const pixelIndex = (y * drawSizeX + x) * 4; // Find the pixel index in an array where every 4 indexes are 1 pixel
|
||||
const pixelIndex = (y * canvasWidth + x) * 4; // Find the pixel index in an array where every 4 indexes are 1 pixel
|
||||
imageData.data[pixelIndex + 3] = 0; // Make the pixel transparent on the alpha channel
|
||||
}
|
||||
}
|
||||
|
|
@ -105,10 +109,16 @@ export default class Template {
|
|||
console.log(`Shreaded pixels for ${pixelX}, ${pixelY}`, imageData);
|
||||
|
||||
context.putImageData(imageData, 0, 0);
|
||||
templateTiles[`${(this.coords[0] + Math.floor(pixelX / 1000)).toString().padStart(4, '0')},${(this.coords[1] + Math.floor(pixelY / 1000)).toString().padStart(4, '0')},${(pixelX % 1000).toString().padStart(3, '0')},${(pixelY % 1000).toString().padStart(3, '0')}`] = await canvas.convertToBlob({ type: 'image/png' });
|
||||
|
||||
//templateTiles[`${(this.coords[0] + Math.floor(pixelX / 1000)).toString().padStart(4, '0')},${(this.coords[1] + Math.floor(pixelY / 1000)).toString().padStart(4, '0')},${(pixelX % 1000).toString().padStart(3, '0')},${(pixelY % 1000).toString().padStart(3, '0')}`] = await canvas.convertToBlob({ type: 'image/png' });
|
||||
templateTiles[`${(this.coords[0] + Math.floor(pixelX / 1000)).toString().padStart(4, '0')},${(this.coords[1] + Math.floor(pixelY / 1000)).toString().padStart(4, '0')},${(pixelX % 1000).toString().padStart(3, '0')},${(pixelY % 1000).toString().padStart(3, '0')}`] = await createImageBitmap(canvas);
|
||||
|
||||
console.log(templateTiles);
|
||||
|
||||
// const final = await canvas.convertToBlob({ type: 'image/png' });
|
||||
// const url = URL.createObjectURL(final); // Creates a blob URL
|
||||
// window.open(url, '_blank'); // Opens a new tab with blob
|
||||
// setTimeout(() => URL.revokeObjectURL(url), 10000); // Destroys the blob 10 seconds later
|
||||
|
||||
pixelX += drawSizeX;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,17 +123,19 @@ export default class ApiManager {
|
|||
|
||||
const blobUUID = data['blobID'];
|
||||
const blobData = data['blobData'];
|
||||
let templateBlob = blobData; // By default, apply no template
|
||||
// let templateBlob = blobData; // By default, apply no template
|
||||
|
||||
// Only run if all coordinates are there
|
||||
if (this.templateCoordsTilePixel?.length >= 4) {
|
||||
// if (this.templateCoordsTilePixel?.length >= 4) {
|
||||
|
||||
if ((tileCoordsTile[0] == this.templateCoordsTilePixel[0]) && (tileCoordsTile[1] == this.templateCoordsTilePixel[1])) {
|
||||
// if ((tileCoordsTile[0] == this.templateCoordsTilePixel[0]) && (tileCoordsTile[1] == this.templateCoordsTilePixel[1])) {
|
||||
|
||||
console.log(`templateState: ${this.templateManager.templateState || null}`);
|
||||
templateBlob = !!this.templateManager.templateState ? await this.templateManager.drawTemplate(blobData, this.templateCoordsTilePixel) : blobData;
|
||||
}
|
||||
}
|
||||
// console.log(`templateState: ${this.templateManager.templateState || null}`);
|
||||
// templateBlob = !!this.templateManager.templateState ? await this.templateManager.drawTemplate(blobData, this.templateCoordsTilePixel) : blobData;
|
||||
|
||||
// }
|
||||
// }
|
||||
const templateBlob = await this.templateManager.drawTemplateOnTile(blobData, tileCoordsTile);
|
||||
|
||||
window.postMessage({
|
||||
source: 'blue-marble',
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { numberToEncoded } from "./utils";
|
|||
* "1 $Z": {
|
||||
* "name": "My Template",
|
||||
* "URL": "https://github.com/SwingTheVine/Wplace-BlueMarble/blob/main/dist/assets/Favicon.png",
|
||||
* "URLType": "template",
|
||||
* "enabled": false,
|
||||
* "tiles": {
|
||||
* "375,1846,276,188": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA",
|
||||
|
|
@ -44,6 +45,8 @@ export default class TemplateManager {
|
|||
this.templatesVersion = '1.0.0'; // Version of JSON schema
|
||||
this.userID = null; // The ID of the current user
|
||||
this.encodingBase = '!#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~'; // Characters to use for encoding/decoding
|
||||
this.tileSize = 1000; // The number of pixels in a tile. Assumes the tile is square
|
||||
this.drawMult = 3; // The enlarged size for each pixel. E.g. when "3", a 1x1 pixel becomes a 1x1 pixel inside a 3x3 area. MUST BE ODD
|
||||
|
||||
// Template
|
||||
this.canvasTemplate = null; // Our canvas
|
||||
|
|
@ -119,8 +122,6 @@ export default class TemplateManager {
|
|||
// Creates the JSON object if it does not already exist
|
||||
if (!this.templatesJSON) {this.templatesJSON = await this.createJSON(); console.log(`Creating JSON...`);}
|
||||
|
||||
const tileSize = 1000; // The size of a tile in pixels
|
||||
|
||||
console.log(`Awaiting creation...`);
|
||||
|
||||
// Creates a new template instance
|
||||
|
|
@ -131,12 +132,13 @@ export default class TemplateManager {
|
|||
file: blob,
|
||||
coords: coords
|
||||
});
|
||||
template.chunked = await template.createTemplateTiles(tileSize); // Chunks the tiles
|
||||
template.chunked = await template.createTemplateTiles(this.tileSize); // Chunks the tiles
|
||||
|
||||
// Appends a child into the templates object
|
||||
// The child's name is the number of templates already in the list (sort order) plus the encoded player ID
|
||||
this.templatesJSON.templates[`${template.sortID} ${template.authorID}`] = {
|
||||
"name": template.displayName, // Display name of template
|
||||
"enabled": true,
|
||||
"tiles": template.chunked
|
||||
};
|
||||
|
||||
|
|
@ -161,9 +163,67 @@ export default class TemplateManager {
|
|||
}
|
||||
|
||||
/** Draws all templates on that tile
|
||||
* @param {File} tileBlob - The pixels that are placed on a tile
|
||||
* @param {[number, number]} tileCoords - The tile coordinates [x, y]
|
||||
*/
|
||||
drawTemplateOnTile() {
|
||||
async drawTemplateOnTile(tileBlob, tileCoords) {
|
||||
|
||||
const drawSize = this.tileSize * this.drawMult; // Draw multiplier
|
||||
|
||||
tileCoords = tileCoords[0].toString().padStart(4, '0') + ',' + tileCoords[1].toString().padStart(4, '0');
|
||||
|
||||
console.log(`Looking for "${tileCoords}"`);
|
||||
|
||||
const templateArray = this.templatesArray; // Stores a copy for sorting
|
||||
|
||||
// Sorts the array of Template class instances. 0 = first = lowest draw priority
|
||||
templateArray.sort((a, b) => {
|
||||
return a.sortID - b.sortID;
|
||||
});
|
||||
|
||||
console.log(templateArray);
|
||||
|
||||
// Retrieves the relavent template tile blobs
|
||||
const templateBlobs = templateArray
|
||||
.map(template => {
|
||||
const matchingTiles = Object.keys(template.chunked).filter(tile =>
|
||||
tile.startsWith(tileCoords)
|
||||
);
|
||||
|
||||
if (matchingTiles.length === 0) {return null;} // Return nothing when nothing is found
|
||||
|
||||
// Retrieves the blobs of the templates for this tile
|
||||
const matchingTileBlobs = matchingTiles.map(tile => template.chunked[tile]);
|
||||
|
||||
return matchingTileBlobs?.[0];
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
console.log(templateBlobs);
|
||||
|
||||
const tileBitmap = await createImageBitmap(tileBlob);
|
||||
|
||||
const canvas = new OffscreenCanvas(drawSize, drawSize);
|
||||
const context = canvas.getContext('2d');
|
||||
|
||||
context.imageSmoothingEnabled = false; // Nearest neighbor
|
||||
|
||||
// Tells the canvas to ignore anything outside of this area
|
||||
context.beginPath();
|
||||
context.rect(0, 0, drawSize, drawSize);
|
||||
context.clip();
|
||||
|
||||
context.clearRect(0, 0, drawSize, drawSize); // Draws transparent background
|
||||
context.drawImage(tileBitmap, 0, 0, drawSize, drawSize);
|
||||
|
||||
// For each template in this tile, draw them.
|
||||
for (const templateBitmap of templateBlobs) {
|
||||
console.log(`Template Blob is ${typeof templateBitmap}`);
|
||||
console.log(templateBitmap);
|
||||
context.drawImage(templateBitmap, tileCoords[0]*this.drawMult, tileCoords[1]*this.drawMult);
|
||||
}
|
||||
|
||||
return await canvas.convertToBlob({ type: 'image/png' });
|
||||
}
|
||||
|
||||
/** Imports the JSON object, and appends it to any JSON object already loaded
|
||||
|
|
|
|||
Loading…
Reference in a new issue