Added styling in consoles

This commit is contained in:
SwingTheVine 2025-07-29 11:46:09 -04:00
parent aa68b22478
commit 8230b08e94
16 changed files with 241 additions and 103 deletions

4
.gitignore vendored
View file

@ -3,6 +3,10 @@
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User specified files
## Generated files
mapCSS.json
# User-specific files
*.rsuser
*.suo

View file

@ -12,6 +12,7 @@
import esbuild from 'esbuild';
import fs from 'fs';
import { execSync } from 'child_process';
import { consoleStyle } from './utils.js';
import mangleSelectors from './cssMangler.js';
import { createRequire } from 'module';
@ -19,14 +20,16 @@ const require = createRequire(import.meta.url);
// CommonJS imports (require)
const terser = require('terser');
const isGitHub = !!process.env?.GITHUB_ACTIONS; // Is this running in a GitHub Action Workflow?
const isGitHub = !!process.env?.GITHUB_ACTIONS; // Is this running in a GitHub Action Workflow?'
console.log(`${consoleStyle.BLUE}Starting build...${consoleStyle.RESET}`);
// Tries to bump the version
try {
const update = execSync('node build/update-version.js', { stdio: 'inherit' });
console.log('Version updated in meta file successfully');
console.log(`Version updated in meta file ${consoleStyle.GREEN}successfully${consoleStyle.RESET}`);
} catch (error) {
console.error('Failed to update version number:', error);
console.error(`${consoleStyle.RED + consoleStyle.BOLD}Failed to update version number${consoleStyle.RESET}:`, error);
process.exit(1);
}
@ -90,7 +93,11 @@ let resultTerser = await terser.minify(resultEsbuildJS.text, {
fs.writeFileSync('dist/BlueMarble.user.js', resultTerser.code, 'utf8');
// Mangles the CSS selectors
mangleSelectors('bm-', 'bm-', 'dist/BlueMarble.user.js', 'dist/BlueMarble.user.css');
// If we are NOT in production (GitHub Workflow), then generate the CSS mapping
const mapCSS = mangleSelectors('bm-', 'bm-', 'dist/BlueMarble.user.js', 'dist/BlueMarble.user.css', !isGitHub);
if (mapCSS) {
fs.writeFileSync('dist/mapCSS.json', JSON.stringify(mapCSS, null, 2));
}
// Adds the banner
fs.writeFileSync(
@ -98,3 +105,5 @@ fs.writeFileSync(
metaContent + fs.readFileSync('dist/BlueMarble.user.js', 'utf8'),
'utf8'
);
console.log(`${consoleStyle.GREEN + consoleStyle.BOLD + consoleStyle.UNDERLINE}Building complete!${consoleStyle.RESET}`);

View file

@ -4,12 +4,15 @@
import fs from 'fs';
import { execSync } from 'child_process';
import { consoleStyle } from './utils.js';
console.log(`${consoleStyle.BLUE}Starting patch...${consoleStyle.RESET}`);
try {
const update = execSync('npm version patch --no-git-tag-version', { stdio: 'inherit' });
console.log('Version patch updated successfully');
console.log(`Version patch updated ${consoleStyle.GREEN}successfully${consoleStyle.RESET}`);
} catch (error) {
console.error('Failed to update version number:', error);
console.error(`${consoleStyle.RED + consoleStyle.BOLD}Failed to update version number${consoleStyle.RESET}:`, error);
process.exit(1);
}

View file

@ -4,6 +4,9 @@
*/
import fs from 'fs';
import { consoleStyle } from './utils.js';
console.log(`${consoleStyle.BLUE}Starting update-version...${consoleStyle.RESET}`);
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
const version = pkg.version;
@ -12,4 +15,4 @@ let meta = fs.readFileSync('src/BlueMarble.meta.js', 'utf-8');
meta = meta.replace(/@version\s+[\d.]+/, `@version ${version}`);
fs.writeFileSync('src/BlueMarble.meta.js', meta);
console.log(`Updated userscript version to ${version}`);
console.log(`${consoleStyle.GREEN}Updated${consoleStyle.RESET} userscript version to ${consoleStyle.MAGENTA}${version}${consoleStyle.RESET}`);

32
build/utils.js Normal file
View file

@ -0,0 +1,32 @@
/** Styling for the console log.
* This only affects the console in the dev's IDE and GitHub Workflow.
* @since 0.58.24
*/
export const consoleStyle = {
/** Resets all styling */
RESET: '\x1b[0m',
/** Makes the text **bold** */
BOLD: '\x1b[1m',
/** Makes the text underlined */
UNDERLINE: '\x1b[4m',
/** Inverses the color of the text and the background */
INVERSE: '\x1b[7m',
/** Turns the text white */
WHITE: '\x1b[37m',
/** Turns the text black */
BLACK: '\x1b[30m',
/** Turns the text red */
RED: '\x1b[31m',
/** Turns the text green */
GREEN: '\x1b[32m',
/** Turns the text yellow */
YELLOW: '\x1b[33m',
/** Turns the text blue */
BLUE: '\x1b[34m',
/** Turns the text magenta */
MAGENTA: '\x1b[35m',
/** Turns the text cyan */
CYAN: '\x1b[36m'
}

View file

@ -1 +1 @@
#bm-p{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000}div#bm-p{font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-k{margin-bottom:.5em;background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="5" height="5"><circle cx="3" cy="3" r="1.5" fill="CornflowerBlue" /></svg>') repeat;cursor:grab;width:100%;height:1em}#bm-k.dragging{cursor:grabbing}#bm-b{margin-bottom:.5em}#bm-p img{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle}#bm-p h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}#bm-3 input[type=checkbox]{vertical-align:middle;margin-right:.5ch}#bm-3 label{margin-right:.5ch}.bm-q{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}#bm-h{vertical-align:middle}#bm-h svg{width:50%;margin:0 auto;fill:#111}div#bm-7{display:flex;gap:.5ch}#bm-8 svg,#bm-button-template svg{height:1em;margin:2px auto 0;text-align:center;line-height:1em;vertical-align:bottom}#bm-c input[type=number]{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}#bm-c input[type=number]::-webkit-outer-spin-button,#bm-c input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}#bm-0{display:flex;flex-direction:row;flex-wrap:wrap;align-content:center;justify-content:center;align-items:center;gap:1ch}div:has(>#bm-2)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#bm-e{font-size:small;background-color:#0003;padding:0 .5ch;height:3.75em;width:100%}#bm-1{display:flex;justify-content:space-between}#bm-p small{font-size:x-small;color:#d3d3d3}#bm-4,#bm-3,#bm-c,#bm-0,div:has(>#bm-2),#bm-e{margin-top:.5em}#bm-p button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}#bm-p button:hover,#bm-p button:focus-visible{background-color:#1061e5}#bm-p button:active,#bm-p button:disabled{background-color:#2e97ff}#bm-p button:disabled{text-decoration:line-through}
#bm-p{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000}div#bm-p{font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-k{margin-bottom:.5em;background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="5" height="5"><circle cx="3" cy="3" r="1.5" fill="CornflowerBlue" /></svg>') repeat;cursor:grab;width:100%;height:1em}#bm-k.dragging{cursor:grabbing}#bm-b{margin-bottom:.5em}#bm-p img{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle}#bm-p h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}#bm-3 input[type=checkbox]{vertical-align:middle;margin-right:.5ch}#bm-3 label{margin-right:.5ch}.bm-s{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}#bm-h{vertical-align:middle}#bm-h svg{width:50%;margin:0 auto;fill:#111}div>#bm-7{display:flex;gap:.5ch}#bm-8 svg,#bm-button-template svg{height:1em;margin:2px auto 0;text-align:center;line-height:1em;vertical-align:bottom}#bm-c input[type=number]{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}#bm-c input[type=number]::-webkit-outer-spin-button,#bm-c input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}#bm-0{display:flex;flex-direction:row;flex-wrap:wrap;align-content:center;justify-content:center;align-items:center;gap:1ch}div:has(>#bm-2)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#bm-e{font-size:small;background-color:#0003;padding:0 .5ch;height:3.75em;width:100%}#bm-1{display:flex;justify-content:space-between}#bm-p small{font-size:x-small;color:#d3d3d3}#bm-4,#bm-3,#bm-c,#bm-0,div:has(>#bm-2),#bm-e{margin-top:.5em}#bm-p button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}#bm-p button:hover,#bm-p button:focus-visible{background-color:#1061e5}#bm-p button:active,#bm-p button:disabled{background-color:#2e97ff}#bm-p button:disabled{text-decoration:line-through}

File diff suppressed because one or more lines are too long

View file

@ -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-35hrs_30mins-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-229-black?style=flat"></a>
<a href="" target="_blank"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-252-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-70.56%25-blue"></a>

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "wplace-bluemarble",
"version": "0.58.2",
"version": "0.58.25",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "wplace-bluemarble",
"version": "0.58.2",
"version": "0.58.25",
"devDependencies": {
"esbuild": "^0.25.0",
"terser": "^5.43.1"

View file

@ -1,6 +1,6 @@
{
"name": "wplace-bluemarble",
"version": "0.58.2",
"version": "0.58.25",
"type": "module",
"scripts": {
"build": "node build/build.js",

View file

@ -1,7 +1,7 @@
// ==UserScript==
// @name Blue Marble
// @namespace https://github.com/SwingTheVine/
// @version 0.58.2
// @version 0.58.25
// @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

View file

@ -609,6 +609,18 @@ export default class Overlay {
});
}
/** Handles status display.
* This will output plain text into the output Status box.
* Additionally, this will output an info message to the console.
* @param {string} text - The status text to display.
* @since 0.58.4
*/
handleDisplayStatus(text) {
const consoleInfo = console.info; // Creates a copy of the console.info function
consoleInfo(`${this.name}: ${text}`); // Outputs something like "ScriptName: text" as an info message to the console
this.updateInnerHTML(this.outputStatusId, 'Status: ' + text, true); // Update output Status box
}
/** Handles error display.
* This will output plain text into the output Status box.
* Additionally, this will output an error to the console.
@ -616,8 +628,8 @@ export default class Overlay {
* @since 0.41.6
*/
handleDisplayError(text) {
const consoleError = console.error; // Idk anymore...
consoleError(`${this.name}: ${text}`); // Outputs something like "ScriptName: text" as an error to the console
this.updateInnerHTML(this.outputStatusId, 'Error: ' + text, true);
const consoleError = console.error; // Creates a copy of the console.error function
consoleError(`${this.name}: ${text}`); // Outputs something like "ScriptName: text" as an error message to the console
this.updateInnerHTML(this.outputStatusId, 'Error: ' + text, true); // Update output Status box
}
}

View file

@ -37,7 +37,7 @@ export default class ApiManager {
// E.g. "wplace.live/api/pixel/0/0?payload" -> "pixel"
const endpointText = data['endpoint'].split('?')[0].split('/').filter(s => s && isNaN(Number(s))).pop();
console.log(`Recieved message about "${endpointText}"`);
console.log(`%cBlue Marble%c: Recieved message about "${endpointText}"`, 'color: cornflowerblue;', '');
// Each case is something that Blue Marble can use from the fetch.
// For instance, if the fetch was for "me", we can update the overlay stats

View file

@ -1,28 +1,40 @@
/** The main file. Everything in the userscript is executed from here.
* @since 0.0.0
*/
import Overlay from './Overlay.js';
import Observers from './observers.js';
import ApiManager from './apiManager.js';
import TemplateManager from './templateManager.js';
import { consoleLog } from './utils.js';
const name = GM_info.script.name.toString();
const version = GM_info.script.version.toString();
const name = GM_info.script.name.toString(); // Name of userscript
const version = GM_info.script.version.toString(); // Version of userscript
const consoleStyle = 'color: cornflowerblue;'; // The styling for the console logs
/** Injects code into the client
* This code will execute outside of TamperMonkey's sandbox
* @param {*} fn - The code to execute
* @param {*} callback - The code to execute
* @since 0.11.15
*/
function inject(fn) {
function inject(callback) {
const script = document.createElement('script');
script.textContent = `(${fn})();`;
script.setAttribute('bm-name', name); // Passes in the name value
script.setAttribute('bm-cStyle', consoleStyle); // Passes in the console style value
script.textContent = `(${callback})();`;
document.documentElement.appendChild(script);
script.remove();
}
/** What code to execute instantly in the client.
* This code will execute outside of TamperMonkey's sandbox
/** What code to execute instantly in the client (webpage).
* This code will execute outside of TamperMonkey's sandbox.
* @since 0.11.15
*/
inject(() => {
const script = document.currentScript; // Gets the current script HTML Script Element
const name = script?.getAttribute('bm-name') || 'Blue Marble'; // Gets the name value that was passed in. Defaults to "Blue Marble" if nothing was found
const consoleStyle = script?.getAttribute('bm-cStyle') || ''; // Gets the console style value that was passed in. Defaults to no styling if nothing was found
// Spys on "spontaneous" fetch requests made by the client
const originalFetch = window.fetch; // Saves a copy of the original fetch
@ -39,9 +51,9 @@ inject(() => {
// Retrieves the endpoint name. Unknown endpoint = "ignore"
let endpointName = ((args[0] instanceof Request) ? args[0]?.url : args[0]) || 'ignore';
//endpointName = endpointName.split('/').filter(Boolean).pop() || 'ignore';
console.log(`Sending JSON message about endpoint "${endpointName}"`);
// Since this code does not run in the userscript, we can't use consoleLog().
console.log(`%c${name}%c: Sending JSON message about endpoint "${endpointName}"`, consoleStyle, '');
// Sends a message about the endpoint it spied on
cloned.json()
@ -53,7 +65,7 @@ inject(() => {
}, '*');
})
.catch(err => {
console.error('BM - Failed to parse JSON:', err);
console.error(`%c${name}%c: Failed to parse JSON: `, consoleStyle, '', err);
});
}
@ -76,6 +88,7 @@ stylesheetLink.onload = function () {
};
document.head.appendChild(stylesheetLink);
// CONSTRUCTORS
const observers = new Observers(); // Constructs a new Observers object
const overlay = new Overlay(name, version); // Constructs a new Overlay object
const templateManager = new TemplateManager(); // Constructs a new TemplateManager object
@ -83,81 +96,90 @@ const apiManager = new ApiManager(); // Constructs a new ApiManager object
overlay.setApiManager(apiManager); // Sets the API manager
// Deploys the overlay to the page
// Parent/child relationships in the DOM structure below are indicated by indentation
overlay.addDiv({'id': 'bm-overlay', 'style': 'top: 10px; right: 75px;'})
.addDiv({'id': 'bm-contain-header'})
.addDiv({'id': 'bm-bar-drag'}).buildElement()
.addImg({'alt': 'Blue Marble Icon', 'src': 'https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png'}).buildElement()
.addHeader(1, {'textContent': name}).buildElement()
.buildElement()
.addHr().buildElement()
.addDiv({'id': 'bm-contain-userinfo'})
.addP({'id': 'bm-user-name', 'textContent': 'Username:'}).buildElement()
.addP({'id': 'bm-user-droplets', 'textContent': 'Droplets:'}).buildElement()
.addP({'id': 'bm-user-nextlevel', 'textContent': 'Next level in...'}).buildElement()
.buildElement()
.addHr().buildElement()
.addDiv({'id': 'bm-contain-automation'})
.addCheckbox({'id': 'bm-input-stealth', 'textContent': 'Stealth', 'checked': true}).buildElement()
.addButtonHelp({'title': 'Waits for the website to make requests, instead of sending requests.'}).buildElement()
.addBr().buildElement()
.addCheckbox({'id': 'bm-input-possessed', 'textContent': 'Possessed', 'checked': true}).buildElement()
.addButtonHelp({'title': 'Controls the website as if it were possessed.'}).buildElement()
.addBr().buildElement()
.addDiv({'id': 'bm-contain-coords'})
.addButton({'id': 'bm-button-coords', 'className': 'bm-help', 'style': 'margin-top: 0;', 'innerHTML': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4 6"><circle cx="2" cy="2" r="2"></circle><path d="M2 6 L3.7 3 L0.3 3 Z"></path><circle cx="2" cy="2" r="0.7" fill="white"></circle></svg></svg>'},
(instance, button) => {
button.onclick = () => {
const coords = instance.apiManager?.coordsTilePixel; // Retrieves the coords from the API manager
if (!coords?.[0]) {
instance.handleDisplayError('Coordinates are malformed! Did you try clicking on the canvas first?');
return;
}
instance.updateInnerHTML('bm-input-tx', coords?.[0] || '');
instance.updateInnerHTML('bm-input-ty', coords?.[1] || '');
instance.updateInnerHTML('bm-input-px', coords?.[2] || '');
instance.updateInnerHTML('bm-input-py', coords?.[3] || '');
}
}
).buildElement()
.addInput({'type': 'number', 'id': 'bm-input-tx', 'placeholder': 'Tl X', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
.addInput({'type': 'number', 'id': 'bm-input-ty', 'placeholder': 'Tl Y', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
.addInput({'type': 'number', 'id': 'bm-input-px', 'placeholder': 'Px X', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
.addInput({'type': 'number', 'id': 'bm-input-py', 'placeholder': 'Px Y', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
.buildElement()
.addInputFile({'id': 'bm-input-file-template', 'textContent': 'Upload Template', 'accept': 'image/png, image/jpeg, image/webp, image/bmp, image/gif'}).buildElement()
.addDiv({'id': 'bm-contain-buttons-template'})
.addButton({'id': 'bm-button-enable', 'textContent': 'Enable'}, (instance, button) => {
button.onclick = () => {
const input = document.querySelector('#bm-input-file-template');
// Kills itself if there is no file
if (!input?.files[0]) {instance.handleDisplayError(`No file selected!`); return;}
templateManager.setTemplateImage(input.files[0]);
}
}).buildElement()
.addButton({'id': 'bm-button-disable', 'textContent': 'Disable'}).buildElement()
.buildElement()
.addTextarea({'id': overlay.outputStatusId, 'placeholder': `Status: Sleeping...\nVersion: ${version}`, 'readOnly': true}).buildElement()
.addDiv({'id': 'bm-contain-buttons-action'})
.addDiv()
.addButton({'id': 'bm-button-teleport', 'className': 'bm-help', 'textContent': '✈'}).buildElement()
.addButton({'id': 'bm-button-favorite', 'className': 'bm-help', 'innerHTML': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><polygon points="10,2 12,7.5 18,7.5 13.5,11.5 15.5,18 10,14 4.5,18 6.5,11.5 2,7.5 8,7.5" fill="white"></polygon></svg>'}).buildElement()
.addButton({'id': 'bm-button-templates', 'className': 'bm-help', 'innerHTML': '🖌'}).buildElement()
.buildElement()
.addSmall({'textContent': 'Made by SwingTheVine', 'style': 'margin-top: auto;'}).buildElement()
.buildElement()
.buildElement()
.buildOverlay(document.body);
buildOverlayMain(); // Builds the main overlay
overlay.handleDrag('#bm-overlay', '#bm-bar-drag'); // Creates dragging capability on the drag bar for dragging the overlay
apiManager.spontaneousResponseListener(overlay); // Reads spontaneous fetch responces
console.log(`${name} (${version}) userscript has loaded!`);
consoleLog(`%c${name}%c (${version}) userscript has loaded!`, 'color: cornflowerblue;', '');
/** Deploys the overlay to the page.
* Parent/child relationships in the DOM structure below are indicated by indentation.
* @since 0.58.3
*/
function buildOverlayMain() {
overlay.addDiv({'id': 'bm-overlay', 'style': 'top: 10px; right: 75px;'})
.addDiv({'id': 'bm-contain-header'})
.addDiv({'id': 'bm-bar-drag'}).buildElement()
.addImg({'alt': 'Blue Marble Icon', 'src': 'https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png'}).buildElement()
.addHeader(1, {'textContent': name}).buildElement()
.buildElement()
.addHr().buildElement()
.addDiv({'id': 'bm-contain-userinfo'})
.addP({'id': 'bm-user-name', 'textContent': 'Username:'}).buildElement()
.addP({'id': 'bm-user-droplets', 'textContent': 'Droplets:'}).buildElement()
.addP({'id': 'bm-user-nextlevel', 'textContent': 'Next level in...'}).buildElement()
.buildElement()
.addHr().buildElement()
.addDiv({'id': 'bm-contain-automation'})
.addCheckbox({'id': 'bm-input-stealth', 'textContent': 'Stealth', 'checked': true}).buildElement()
.addButtonHelp({'title': 'Waits for the website to make requests, instead of sending requests.'}).buildElement()
.addBr().buildElement()
.addCheckbox({'id': 'bm-input-possessed', 'textContent': 'Possessed', 'checked': true}).buildElement()
.addButtonHelp({'title': 'Controls the website as if it were possessed.'}).buildElement()
.addBr().buildElement()
.addDiv({'id': 'bm-contain-coords'})
.addButton({'id': 'bm-button-coords', 'className': 'bm-help', 'style': 'margin-top: 0;', 'innerHTML': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4 6"><circle cx="2" cy="2" r="2"></circle><path d="M2 6 L3.7 3 L0.3 3 Z"></path><circle cx="2" cy="2" r="0.7" fill="white"></circle></svg></svg>'},
(instance, button) => {
button.onclick = () => {
const coords = instance.apiManager?.coordsTilePixel; // Retrieves the coords from the API manager
if (!coords?.[0]) {
instance.handleDisplayError('Coordinates are malformed! Did you try clicking on the canvas first?');
return;
}
instance.updateInnerHTML('bm-input-tx', coords?.[0] || '');
instance.updateInnerHTML('bm-input-ty', coords?.[1] || '');
instance.updateInnerHTML('bm-input-px', coords?.[2] || '');
instance.updateInnerHTML('bm-input-py', coords?.[3] || '');
}
}
).buildElement()
.addInput({'type': 'number', 'id': 'bm-input-tx', 'placeholder': 'Tl X', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
.addInput({'type': 'number', 'id': 'bm-input-ty', 'placeholder': 'Tl Y', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
.addInput({'type': 'number', 'id': 'bm-input-px', 'placeholder': 'Px X', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
.addInput({'type': 'number', 'id': 'bm-input-py', 'placeholder': 'Px Y', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
.buildElement()
.addInputFile({'id': 'bm-input-file-template', 'textContent': 'Upload Template', 'accept': 'image/png, image/jpeg, image/webp, image/bmp, image/gif'}).buildElement()
.addDiv({'id': 'bm-contain-buttons-template'})
.addButton({'id': 'bm-button-enable', 'textContent': 'Enable'}, (instance, button) => {
button.onclick = () => {
const input = document.querySelector('#bm-input-file-template');
// Kills itself if there is no file
if (!input?.files[0]) {instance.handleDisplayError(`No file selected!`); return;}
templateManager.setTemplateImage(input.files[0]);
templateManager.tempDraw();
instance.handleDisplayStatus(`Drew to canvas!`);
}
}).buildElement()
.addButton({'id': 'bm-button-disable', 'textContent': 'Disable'}).buildElement()
.buildElement()
.addTextarea({'id': overlay.outputStatusId, 'placeholder': `Status: Sleeping...\nVersion: ${version}`, 'readOnly': true}).buildElement()
.addDiv({'id': 'bm-contain-buttons-action'})
.addDiv()
.addButton({'id': 'bm-button-teleport', 'className': 'bm-help', 'textContent': '✈'}).buildElement()
.addButton({'id': 'bm-button-favorite', 'className': 'bm-help', 'innerHTML': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><polygon points="10,2 12,7.5 18,7.5 13.5,11.5 15.5,18 10,14 4.5,18 6.5,11.5 2,7.5 8,7.5" fill="white"></polygon></svg>'}).buildElement()
.addButton({'id': 'bm-button-templates', 'className': 'bm-help', 'innerHTML': '🖌'}).buildElement()
.buildElement()
.addSmall({'textContent': 'Made by SwingTheVine', 'style': 'margin-top: auto;'}).buildElement()
.buildElement()
.buildElement()
.buildOverlay(document.body);
}

View file

@ -7,10 +7,28 @@ export default class TemplateManager {
* @since 0.55.8
*/
constructor() {
this.canvas = null; // The canvas
this.canvasID = 'div#map canvas'; // The selector for the main canvas
this.template = null; // The template image.
this.state = ''; // The state of the template ('blob', 'proccessing', 'template', etc.)
}
/** Retrieves the pixel art canvas.
* If the canvas has been updated/replaced, it retrieves the new one.
* @param {string} selector - The CSS selector to use to find the canvas.
* @returns {HTMLCanvasElement|null} The canvas as an HTML Canvas Element, or null if the canvas does not exist
* @since 0.58.3
*/
getCanvas(selector) {
// If the stored canvas is "fresh," return the stored canvas
if (document.body.contains(this.canvas)) {return this.canvas;}
// Else, the stored canvas is "stale," get the canvas again
this.canvas = document.querySelector(selector); // Get the new canvas
return this.canvas; // Return the new canvas or null
}
/** Sets the template to the image passed in.
* @param {File} file - The file of the template image.
* @since 0.55.8
@ -24,4 +42,12 @@ export default class TemplateManager {
window.open(url, '_blank'); // Opens a new tab with blob
setTimeout(() => URL.revokeObjectURL(url), 10000); // Destroys the blob 10 seconds later
}
tempDraw() {
const ctx = this.getCanvas(this.canvasID)?.getContext('2d');
if (ctx) {
ctx.fillStyle = 'red';
ctx.fillRect(21511, 1305644, 500, 500);
}
}
}

View file

@ -43,4 +43,31 @@ export function serverTPtoDisplayTP(tile, pixel) {
*/
export function negativeSafeModulo(a, b) {
return (a % b + b) % b;
}
}
/** Bypasses terser's stripping of console function calls.
* This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't.
* However, the distributed version needs to call the console somehow, so this wrapper function is how.
* This is the same as `console.log()`.
* @param {...any} args - Arguments to be passed into the `log()` function of the Console
* @since 0.58.9
*/
export function consoleLog(...args) {((consoleLog) => consoleLog(...args))(console.log);}
/** Bypasses terser's stripping of console function calls.
* This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't.
* However, the distributed version needs to call the console somehow, so this wrapper function is how.
* This is the same as `console.error()`.
* @param {...any} args - Arguments to be passed into the `error()` function of the Console
* @since 0.58.13
*/
export function consoleError(...args) {((consoleError) => consoleError(...args))(console.error);}
/** Bypasses terser's stripping of console function calls.
* This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't.
* However, the distributed version needs to call the console somehow, so this wrapper function is how.
* This is the same as `console.warn()`.
* @param {...any} args - Arguments to be passed into the `warn()` function of the Console
* @since 0.58.13
*/
export function consoleWarn(...args) {((consoleWarn) => consoleWarn(...args))(console.warn);}