mirror of
https://github.com/SwingTheVine/Wplace-BlueMarble.git
synced 2026-03-11 17:15:38 +00:00
Set up skeleton of Template Wizard
This commit is contained in:
parent
9885a100c7
commit
34d3447138
10 changed files with 911 additions and 657 deletions
1285
dist/BlueMarble-For-GreasyFork.user.js
vendored
1285
dist/BlueMarble-For-GreasyFork.user.js
vendored
File diff suppressed because it is too large
Load diff
4
dist/BlueMarble-Standalone.user.js
vendored
4
dist/BlueMarble-Standalone.user.js
vendored
File diff suppressed because one or more lines are too long
2
dist/BlueMarble.user.css
vendored
2
dist/BlueMarble.user.css
vendored
File diff suppressed because one or more lines are too long
4
dist/BlueMarble.user.js
vendored
4
dist/BlueMarble.user.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -51,7 +51,7 @@
|
|||
<a href="https://discord.gg/tpeBPy46hf" target="_blank" rel="noopener noreferrer"><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="https://bluemarble.lol/" target="_blank" rel="noopener noreferrer"><img alt="Blue Marble Website" src="https://img.shields.io/badge/Blue_Marble_Website-crqch-blue?style=flat&logo=globe&logoColor=white"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="WakaTime" src="https://img.shields.io/badge/Coding_Time-169hrs_20mins-blue?style=flat&logo=wakatime&logoColor=black&logoSize=auto&labelColor=white"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-931-black?style=flat"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-938-black?style=flat"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Lines of Code" src="https://img.shields.io/badge/Lines_Of_Code-498-blue?style=flat"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Comments" src="https://img.shields.io/badge/Lines_Of_Comments-498-blue?style=flat"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Compression" src="https://img.shields.io/badge/Compression-70.19%25-blue"></a>
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.88.433",
|
||||
"version": "0.88.440",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.88.433",
|
||||
"version": "0.88.440",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"jsdoc": "^4.0.5",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.88.433",
|
||||
"version": "0.88.440",
|
||||
"type": "module",
|
||||
"homepage": "https://bluemarble.lol/",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// @name Blue Marble
|
||||
// @name:en Blue Marble
|
||||
// @namespace https://github.com/SwingTheVine/
|
||||
// @version 0.88.433
|
||||
// @version 0.88.440
|
||||
// @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.
|
||||
// @description:en 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
|
||||
|
|
|
|||
122
src/WindowWizard.js
Normal file
122
src/WindowWizard.js
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
import Overlay from "./Overlay";
|
||||
import { escapeHTML } from "./utils";
|
||||
|
||||
/** Wizard that manages template updates & recovery
|
||||
* @class WindowWizard
|
||||
* @since 0.88.434
|
||||
* @see {@link Overlay} for examples
|
||||
*/
|
||||
export default class WindowWizard extends Overlay {
|
||||
|
||||
/** Constructor for the Template Wizard window
|
||||
* @param {string} name - The name of the userscript
|
||||
* @param {string} version - The version of the userscript
|
||||
* @param {string} schemaVersionBleedingEdge - The bleeding edge of schema versions for Blue Marble
|
||||
* @since 0.88.434
|
||||
* @see {@link Overlay#constructor} for examples
|
||||
*/
|
||||
constructor(name, version, schemaVersionBleedingEdge) {
|
||||
super(name, version); // Executes the code in the Overlay constructor
|
||||
this.window = null; // Contains the *window* DOM tree
|
||||
this.windowID = 'bm-window-wizard'; // The ID attribute for this window
|
||||
this.windowParent = document.body; // The parent of the window DOM tree
|
||||
|
||||
// Retrieves data from storage
|
||||
this.currentJSON = JSON.parse(GM_getValue('bmTemplates', '{}')); // The current Blue Marble storage
|
||||
this.scriptVersion = this.currentJSON?.scriptVersion; // Script version when template was created
|
||||
this.schemaVersion = this.currentJSON?.schemaVersion; // Schema version when template was created
|
||||
|
||||
this.schemaHealth = undefined; // Current schema health. This is: 'Good', 'Poor', 'Bad', or 'Dead' for full match, MINOR mismatch, MAJOR mismatch, and unknown, respectively.
|
||||
this.schemaVersionBleedingEdge = schemaVersionBleedingEdge; // Latest schema version
|
||||
}
|
||||
|
||||
/** Spawns a Template Wizard window.
|
||||
* If another template wizard window already exists, we DON'T spawn another!
|
||||
* Parent/child relationships in the DOM structure below are indicated by indentation.
|
||||
* @since 0.88.434
|
||||
*/
|
||||
buildWindow() {
|
||||
|
||||
// If a template wizard window already exists, throw an error and return early
|
||||
if (document.querySelector(`#${this.windowID}`)) {
|
||||
this.handleDisplayError('Template Wizard window already exists!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Creates a new template wizard window
|
||||
this.window = this.addDiv({'id': this.windowID, 'class': 'bm-window', 'style': 'z-index: 9001;'})
|
||||
.addDragbar()
|
||||
.addButton({'class': 'bm-button-circle', 'textContent': '▼', 'aria-label': 'Minimize window "Template Wizard"', 'data-button-status': 'expanded'}, (instance, button) => {
|
||||
button.onclick = () => instance.handleMinimization(button);
|
||||
button.ontouchend = () => {button.click()}; // Needed only to negate weird interaction with dragbar
|
||||
}).buildElement()
|
||||
.addDiv().buildElement() // Contains the minimized h1 element
|
||||
.addButton({'class': 'bm-button-circle', 'textContent': '🞪', 'aria-label': 'Close window "Template Wizard"'}, (instance, button) => {
|
||||
button.onclick = () => {document.querySelector(`#${this.windowID}`)?.remove();};
|
||||
button.ontouchend = () => {button.click();}; // Needed only to negate weird interaction with dragbar
|
||||
}).buildElement()
|
||||
.buildElement()
|
||||
.addDiv({'class': 'bm-window-content'})
|
||||
.addDiv({'class': 'bm-container bm-center-vertically'})
|
||||
.addHeader(1, {'textContent': 'Template Wizard'}).buildElement()
|
||||
.buildElement()
|
||||
.addHr().buildElement()
|
||||
.addDiv({'class': 'bm-container'})
|
||||
.addP({'id': 'bm-wizard-status', 'textContent': 'Loading template storage status...'}).buildElement()
|
||||
.buildElement()
|
||||
.addDiv({'class': 'bm-container bm-scrollable'})
|
||||
.addSpan({'textContent': 'Detected templates:'}).buildElement()
|
||||
// Detected templates will show up here
|
||||
.buildElement()
|
||||
.buildElement()
|
||||
.buildElement().buildOverlay(this.windowParent);
|
||||
|
||||
this.#displaySchemaHealth();
|
||||
}
|
||||
|
||||
/** Determines how "healthy" the template storage is.
|
||||
* @since 0.88.436
|
||||
*/
|
||||
#displaySchemaHealth() {
|
||||
|
||||
// SemVer -> string[]
|
||||
const schemaVersionArray = this.schemaVersion.split(/[-\.\+]/);
|
||||
const schemaVersionBleedingEdgeArray = this.schemaVersionBleedingEdge.split(/[-\.\+]/);
|
||||
|
||||
// Calculates the health that is displayed as a banner
|
||||
let schemaHealthBanner = '';
|
||||
if (schemaVersionArray[0] == schemaVersionBleedingEdgeArray[0]) {
|
||||
|
||||
if (schemaVersionArray[1] == schemaVersionBleedingEdgeArray[1]) {
|
||||
schemaHealthBanner = 'Template storage health: <b>Healthy!</b><br>No futher action required. (Reason: Semantic version matches)';
|
||||
this.schemaHealth = 'Good';
|
||||
} else {
|
||||
schemaHealthBanner = 'Template storage health: <b>Poor!</b><br>You can still use your template, but some features may not work. It is recommended that you update Blue Marble\'s template storage. (Reason: MINOR version mismatch)';
|
||||
this.schemaHealth = 'Poor';
|
||||
}
|
||||
} else {
|
||||
schemaHealthBanner = 'Template storage health: <b>Dead!</b><br>Blue Marble can not load the template storage. (Reason: MAJOR version mismatch)';
|
||||
this.schemaHealth = 'Dead';
|
||||
}
|
||||
|
||||
// Display schema health to user
|
||||
this.updateInnerHTML('#bm-wizard-status', `${schemaHealthBanner}<br>The current schema version (<b>${escapeHTML(this.schemaVersion)}</b>) was created during Blue Marble version <b>${escapeHTML(this.scriptVersion)}</b>.<br>The current Blue Marble version (<b>${escapeHTML(this.version)}</b>) requires schema version <b>${escapeHTML(this.schemaVersionBleedingEdge)}</b>.<br>If you don't want to upgrade the template storage (schema), then downgrade Blue Marble to version <b>${escapeHTML(this.scriptVersion)}</b>.`);
|
||||
|
||||
// If the schema health is Poor or Bad, then show update options
|
||||
if ((this.schemaHealth == 'Poor') || (this.schemaHealth == 'Bad')) {
|
||||
const buttonOptions = new Overlay(this.name, this.version);
|
||||
buttonOptions.addDiv({'class': 'bm-container bm-flex-center bm-center-vertically'})
|
||||
.addButton({'textContent': 'Recover (download) templates'}, (instance, button) => {
|
||||
button.onclick = () => {
|
||||
|
||||
}
|
||||
}).buildElement()
|
||||
.addButton({'textContent': `Update template storage to ${this.schemaVersionBleedingEdge}`}, (instance, button) => {
|
||||
button.onclick = () => {
|
||||
|
||||
}
|
||||
}).buildElement()
|
||||
.buildElement().buildOverlay(document.querySelector('#bm-wizard-status').parentNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import Template from "./Template";
|
||||
import { base64ToUint8, colorpaletteForBlueMarble, numberToEncoded } from "./utils";
|
||||
import WindowWizard from "./WindowWizard";
|
||||
|
||||
/** Manages the template system.
|
||||
* This class handles all external requests for template modification, creation, and analysis.
|
||||
|
|
@ -60,7 +61,7 @@ export default class TemplateManager {
|
|||
this.name = name; // Name of userscript
|
||||
this.version = version; // Version of userscript
|
||||
this.overlay = overlay; // The main instance of the Overlay class
|
||||
this.templatesVersion = '1.0.0'; // Version of JSON schema
|
||||
this.schemaVersion = '1.1.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
|
||||
|
|
@ -88,7 +89,7 @@ export default class TemplateManager {
|
|||
return {
|
||||
"whoami": this.name.replace(' ', ''), // Name of userscript without spaces
|
||||
"scriptVersion": this.version, // Version of userscript
|
||||
"schemaVersion": this.templatesVersion, // Version of JSON schema
|
||||
"schemaVersion": this.schemaVersion, // Version of JSON schema
|
||||
"templates": {} // The templates
|
||||
};
|
||||
}
|
||||
|
|
@ -374,68 +375,102 @@ export default class TemplateManager {
|
|||
|
||||
console.log(`BlueMarble length: ${Object.keys(templates).length}`);
|
||||
|
||||
// Run only if there are templates saved
|
||||
if (Object.keys(templates).length > 0) {
|
||||
const schemaVersion = json?.schemaVersion;
|
||||
const schemaVersionArray = schemaVersion.split(/[-\.\+]/); // SemVer -> string[]
|
||||
const schemaVersionBleedingEdge = this.schemaVersion.split(/[-\.\+]/); // SemVer -> string[]
|
||||
const scriptVersion = json?.scriptVersion;
|
||||
|
||||
// For each template...
|
||||
for (const template in templates) {
|
||||
console.log(`BlueMarble Template Schema: ${schemaVersion}; Script Version: ${scriptVersion}`);
|
||||
|
||||
const templateKey = template; // The identification key for the template. E.g., "0 $Z"
|
||||
const templateValue = templates[template]; // The actual content of the template
|
||||
console.log(`Template Key: ${templateKey}`);
|
||||
// If 1.x.x
|
||||
if (schemaVersionArray[0] == schemaVersionBleedingEdge[0]) {
|
||||
|
||||
if (templates.hasOwnProperty(template)) {
|
||||
// If 1.1.x
|
||||
if (schemaVersionArray[1] == schemaVersionBleedingEdge[1]) {
|
||||
|
||||
const templateKeyArray = templateKey.split(' '); // E.g., "0 $Z" -> ["0", "$Z"]
|
||||
const sortID = Number(templateKeyArray?.[0]); // Sort ID of the template
|
||||
const authorID = templateKeyArray?.[1] || '0'; // User ID of the person who exported the template
|
||||
const displayName = templateValue.name || `Template ${sortID || ''}`; // Display name of the template
|
||||
//const coords = templateValue?.coords?.split(',').map(Number); // "1,2,3,4" -> [1, 2, 3, 4]
|
||||
loadSchemaVersion_1_x_x(); // Load 1.1.x schema
|
||||
} else {
|
||||
|
||||
const pixelCount = {
|
||||
total: templateValue.pixels.total,
|
||||
colors: new Map(Object.entries(templateValue.pixels.colors).map(([key, value]) => [Number(key), value]))
|
||||
};
|
||||
// Spawns a new Template Wizard
|
||||
const windowWizard = new WindowWizard(this.name, this.version, this.schemaVersion);
|
||||
windowWizard.buildWindow();
|
||||
|
||||
const tilesbase64 = templateValue.tiles;
|
||||
const templateTiles = {}; // Stores the template bitmap tiles for each tile.
|
||||
const templateTiles32 = {}; // Stores the template Uint32Array tiles for each tile.
|
||||
loadSchemaVersion_1_x_x(); // Load 1.x.x schema with 1.1.x loader, expecting some things to not function
|
||||
}
|
||||
} else {
|
||||
// We don't know what the schema is. Unsupported?
|
||||
|
||||
const actualTileSize = this.tileSize * this.drawMult;
|
||||
this.overlay.handleDisplayError(`Template version ${schemaVersion} is unsupported.\nUse Blue Marble version ${scriptVersion} or load a new template.`);
|
||||
}
|
||||
|
||||
for (const tile in tilesbase64) {
|
||||
console.log(tile);
|
||||
if (tilesbase64.hasOwnProperty(tile)) {
|
||||
const encodedTemplateBase64 = tilesbase64[tile];
|
||||
const templateUint8Array = base64ToUint8(encodedTemplateBase64); // Base 64 -> Uint8Array
|
||||
/** Loads version 1.0.0 of Blue Marble template storage
|
||||
* @since 0.88.434
|
||||
*/
|
||||
async function loadSchemaVersion_1_x_x() {
|
||||
|
||||
const templateBlob = new Blob([templateUint8Array], { type: "image/png" }); // Uint8Array -> Blob
|
||||
const templateBitmap = await createImageBitmap(templateBlob) // Blob -> Bitmap
|
||||
templateTiles[tile] = templateBitmap;
|
||||
|
||||
// Converts to Uint32Array
|
||||
const canvas = new OffscreenCanvas(actualTileSize, actualTileSize);
|
||||
const context = canvas.getContext('2d');
|
||||
context.drawImage(templateBitmap, 0, 0);
|
||||
const imageData = context.getImageData(0, 0, templateBitmap.width, templateBitmap.height);
|
||||
templateTiles32[tile] = new Uint32Array(imageData.data.buffer);
|
||||
// Run only if there are templates saved
|
||||
if (Object.keys(templates).length > 0) {
|
||||
|
||||
// For each template...
|
||||
for (const template in templates) {
|
||||
|
||||
const templateKey = template; // The identification key for the template. E.g., "0 $Z"
|
||||
const templateValue = templates[template]; // The actual content of the template
|
||||
console.log(`Template Key: ${templateKey}`);
|
||||
|
||||
if (templates.hasOwnProperty(template)) {
|
||||
|
||||
const templateKeyArray = templateKey.split(' '); // E.g., "0 $Z" -> ["0", "$Z"]
|
||||
const sortID = Number(templateKeyArray?.[0]); // Sort ID of the template
|
||||
const authorID = templateKeyArray?.[1] || '0'; // User ID of the person who exported the template
|
||||
const displayName = templateValue.name || `Template ${sortID || ''}`; // Display name of the template
|
||||
//const coords = templateValue?.coords?.split(',').map(Number); // "1,2,3,4" -> [1, 2, 3, 4]
|
||||
|
||||
const pixelCount = {
|
||||
total: templateValue.pixels.total,
|
||||
colors: new Map(Object.entries(templateValue.pixels.colors).map(([key, value]) => [Number(key), value]))
|
||||
};
|
||||
|
||||
const tilesbase64 = templateValue.tiles;
|
||||
const templateTiles = {}; // Stores the template bitmap tiles for each tile.
|
||||
const templateTiles32 = {}; // Stores the template Uint32Array tiles for each tile.
|
||||
|
||||
const actualTileSize = this.tileSize * this.drawMult;
|
||||
|
||||
for (const tile in tilesbase64) {
|
||||
console.log(tile);
|
||||
if (tilesbase64.hasOwnProperty(tile)) {
|
||||
const encodedTemplateBase64 = tilesbase64[tile];
|
||||
const templateUint8Array = base64ToUint8(encodedTemplateBase64); // Base 64 -> Uint8Array
|
||||
|
||||
const templateBlob = new Blob([templateUint8Array], { type: "image/png" }); // Uint8Array -> Blob
|
||||
const templateBitmap = await createImageBitmap(templateBlob) // Blob -> Bitmap
|
||||
templateTiles[tile] = templateBitmap;
|
||||
|
||||
// Converts to Uint32Array
|
||||
const canvas = new OffscreenCanvas(actualTileSize, actualTileSize);
|
||||
const context = canvas.getContext('2d');
|
||||
context.drawImage(templateBitmap, 0, 0);
|
||||
const imageData = context.getImageData(0, 0, templateBitmap.width, templateBitmap.height);
|
||||
templateTiles32[tile] = new Uint32Array(imageData.data.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a new Template class instance
|
||||
const template = new Template({
|
||||
displayName: displayName,
|
||||
sortID: sortID || this.templatesArray?.length || 0,
|
||||
authorID: authorID || '',
|
||||
//coords: coords,
|
||||
});
|
||||
template.pixelCount = pixelCount;
|
||||
template.chunked = templateTiles;
|
||||
template.chunked32 = templateTiles32;
|
||||
|
||||
this.templatesArray.push(template);
|
||||
console.log(this.templatesArray);
|
||||
console.log(`^^^ This ^^^`);
|
||||
}
|
||||
|
||||
// Creates a new Template class instance
|
||||
const template = new Template({
|
||||
displayName: displayName,
|
||||
sortID: sortID || this.templatesArray?.length || 0,
|
||||
authorID: authorID || '',
|
||||
//coords: coords,
|
||||
});
|
||||
template.pixelCount = pixelCount;
|
||||
template.chunked = templateTiles;
|
||||
template.chunked32 = templateTiles32;
|
||||
|
||||
this.templatesArray.push(template);
|
||||
console.log(this.templatesArray);
|
||||
console.log(`^^^ This ^^^`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue