diff --git a/.gitignore b/.gitignore index cbde78a..6927425 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,6 @@ ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore # User specified files -## Generated files -mapCSS.json # User-specific files *.rsuser diff --git a/build/build.js b/build/build.js index 8d8a95e..91fe3d1 100644 --- a/build/build.js +++ b/build/build.js @@ -92,11 +92,32 @@ let resultTerser = await terser.minify(resultEsbuildJS.text, { // Writes the obfuscated/mangled JS code to a file fs.writeFileSync('dist/BlueMarble.user.js', resultTerser.code, 'utf8'); +let importedMapCSS = {}; // The imported CSS map + +// Only import a CSS map if we are NOT in production (GitHub Workflow) +// Theoretically, if the previous map is always imported, the names would not scramble. However, the names would never decrease in number... +if (isGitHub) { + try { + importedMapCSS = JSON.parse(fs.readFileSync('dist/BlueMarble.user.css.map.json', 'utf8')); + } catch { + console.log(`${consoleStyle.YELLOW}Warning! Could not find a CSS map to import. A 100% new CSS map will be generated...${consoleStyle.RESET}`); + } +} + // Mangles the CSS selectors -// 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 we are in production (GitHub Workflow), then generate the CSS mapping +const mapCSS = mangleSelectors({ + inputPrefix: 'bm-', + outputPrefix: 'bm-', + pathJS: 'dist/BlueMarble.user.js', + pathCSS: 'dist/BlueMarble.user.css', + importMap: importedMapCSS, + returnMap: isGitHub +}); + +// If a map was returned, write it to the file if (mapCSS) { - fs.writeFileSync('dist/mapCSS.json', JSON.stringify(mapCSS, null, 2)); + fs.writeFileSync('dist/BlueMarble.user.css.map.json', JSON.stringify(mapCSS, null, 2)); } // Adds the banner diff --git a/build/cssMangler.js b/build/cssMangler.js index 3d1449f..40a7377 100644 --- a/build/cssMangler.js +++ b/build/cssMangler.js @@ -47,12 +47,15 @@ import fs from 'fs'; * * The default mangling is all valid single byte characters for CSS selectors (which is, ironically, 64 characters). * You can optionally return the key-value mapping of all selector names. - * @param {string} inputPrefix - The prefix to search for. - * @param {string} outputPrefix - The prefix to replace with. - * @param {string} pathJS - The path to the JS file. - * @param {string} pathCSS - The path to the CSS file. - * @param {boolean} [returnMap=false] - Should this function return the key-value map Object? - * @param {string} [encoding=''] - The characters you want the mangled selectors to consist of. + * You can optionally pass in a map to be used. If you do, any selectors not in the map will be added. + * @param {Object} params - The parameters object. + * @param {string} params.inputPrefix - The prefix to search for. + * @param {string} params.outputPrefix - The prefix to replace with. + * @param {string} params.pathJS - The path to the JS file. + * @param {string} params.pathCSS - The path to the CSS file. + * @param {Object} [params.importMap={}] - Imported map to use. + * @param {boolean} [params.returnMap=false] - Should this function return the key-value map Object? + * @param {string} [params.encoding=''] - The characters you want the mangled selectors to consist of. * @returns {Object|undefined} A mapping of the mangled CSS selectors as an Object, or `undefined` if `returnMap` is not `true`. * @since 0.56.1 * @example @@ -75,19 +78,63 @@ import fs from 'fs'; * #b-1 {color:red;} * .b-0 {background-color:blue;} * // Optional returned map Object: - * console.log(JSON.stringify(mangleSelectors('bm-', 'b-', 'bundled.js', 'bundled.css', true), null, 2)); + * console.log( + * JSON.stringify( + * mangleSelectors({ + * inputPrefix: 'bm-', + * outputPrefix: 'b-', + * pathJS: 'bundled.js', + * pathCSS: 'bundled.css', + * returnMap: true + * }), + * null, 2 + * ) + * ); + * // Return Map: * { * "bm-paragraph-class": "b-0", * "bm-paragraph-id": "b-1", * } */ -export default function mangleSelectors(inputPrefix, outputPrefix, pathJS, pathCSS, returnMap=false, encoding='') { +export default function mangleSelectors({ + inputPrefix = '', + outputPrefix = '', + pathJS = '', + pathCSS = '', + importMap = {}, + returnMap = false, + encoding = '' +} = {}) { + + if (!inputPrefix || !outputPrefix || !pathJS || !pathCSS) { + throw new Error(`mangleSelectors() was called without the required variables: ${!inputPrefix ? 'inputPrefix ' : ''}${!outputPrefix ? 'outputPrefix ' : ''}${!pathJS ? 'pathJS ' : ''}${!pathCSS ? 'pathCSS' : ''}`); + } encoding = encoding || '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_'; // Default encoding const fileInputJS = fs.readFileSync(pathJS, 'utf8'); // The JS file const fileInputCSS = fs.readFileSync(pathCSS, 'utf8'); // The CSS file + /** How many keys-value pairs there are in the in the imported map, along with an "index shift" if a map was imported. + * @example + * // Assume the imported map has 10 keys. + * // The first key of the new map has an index of 0. + * // If we add 10 + 0, we get an index collision. + * // Therefore, we add 10 + 2 + 0. + * // However, if no map is imported, the map will start it's index at 2. We don't want that. + * // Therefore, if we abuse the fact that `true` is `1`, and `false` is `0`, we can add `2 * !!importMap.length` which will only shift the index by 2 if a map was imported. + * @example + * const importMap = {}; + * console.log(importMapLength); // 0 + * @example + * const importMap = {'foo': 'bar'}; + * console.log(importMapLength); // 3 + * @example + * const importMap = {'foo': 'bar', 'bar': 'foo'}; + * console.log(importMapLength); // 4 + */ + const importMapLength = Object.keys(importMap).length + (2 * !!Object.keys(importMap).length); + // One of each of all matching selectors // File -> RegEx -> Array (Duplicates) -> Set (Unique) -> Array (Unique) let matchedSelectors = [...new Set([...fileInputJS.matchAll(new RegExp(`\\b${escapeRegex(inputPrefix)}[a-zA-Z0-9_-]+`, 'g'))].map(match => match[0]))]; @@ -98,8 +145,16 @@ export default function mangleSelectors(inputPrefix, outputPrefix, pathJS, pathC matchedSelectors.sort((a, b) => b.length - a.length); // Converts the string[] to an Object (key-value) - matchedSelectors = Object.fromEntries(matchedSelectors.map((key, value) => [key, outputPrefix + numberToEncoded(matchedSelectors.indexOf(key), encoding)])); - + matchedSelectors = { + ...importMap, + ...Object.fromEntries( + matchedSelectors + .filter(key => !(key in importMap)) + .map(key => [key, outputPrefix + numberToEncoded(importMapLength + matchedSelectors.indexOf(key), encoding)] + ) + ) + }; + // Compile the RegEx from the selector map const regex = new RegExp(Object.keys(matchedSelectors).map(selector => escapeRegex(selector)).join('|'), 'g'); diff --git a/dist/BlueMarble.user.css b/dist/BlueMarble.user.css index 8bdf0c8..15e73b6 100644 --- a/dist/BlueMarble.user.css +++ b/dist/BlueMarble.user.css @@ -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,') 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} +#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,') 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:has(>#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} diff --git a/dist/BlueMarble.user.css.map.json b/dist/BlueMarble.user.css.map.json new file mode 100644 index 0000000..cc6db83 --- /dev/null +++ b/dist/BlueMarble.user.css.map.json @@ -0,0 +1,31 @@ +{ + "bm-contain-buttons-template": "bm-0", + "bm-contain-buttons-action": "bm-1", + "bm-input-file-template": "bm-2", + "bm-contain-automation": "bm-3", + "bm-contain-userinfo": "bm-4", + "bm-button-templates": "bm-5", + "bm-input-possessed": "bm-6", + "bm-button-teleport": "bm-7", + "bm-button-favorite": "bm-8", + "bm-display-coords": "bm-9", + "bm-user-nextlevel": "bm-a", + "bm-contain-header": "bm-b", + "bm-contain-coords": "bm-c", + "bm-button-disable": "bm-d", + "bm-output-status": "bm-e", + "bm-user-droplets": "bm-f", + "bm-input-stealth": "bm-g", + "bm-button-coords": "bm-h", + "bm-button-enable": "bm-i", + "bm-user-name": "bm-j", + "bm-bar-drag": "bm-k", + "bm-input-tx": "bm-l", + "bm-input-ty": "bm-m", + "bm-input-px": "bm-n", + "bm-input-py": "bm-o", + "bm-overlay": "bm-p", + "bm-cStyle": "bm-q", + "bm-name": "bm-r", + "bm-help": "bm-s" +} \ No newline at end of file diff --git a/dist/BlueMarble.user.js b/dist/BlueMarble.user.js index f9d1b72..eedb373 100644 --- a/dist/BlueMarble.user.js +++ b/dist/BlueMarble.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name Blue Marble // @namespace https://github.com/SwingTheVine/ -// @version 0.59.0 +// @version 0.59.8 // @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 @@ -20,4 +20,4 @@ // Wplace --> https://wplace.live // License --> https://www.mozilla.org/en-US/MPL/2.0/ -(()=>{var t,e,n=t=>{throw TypeError(t)},s=(t,e,s)=>(((t,e)=>{e.has(t)||n("Cannot access private method")})(t,e),s);t=new WeakSet,e=function(t,e={},n={}){const s=document.createElement(t);this.t?(this.i.appendChild(s),this.o.push(this.i),this.i=s):(this.t=s,this.i=s);for(const[t,n]of Object.entries(e))s[t]=n;for(const[t,e]of Object.entries(n))s[t]=e;return s};var i=GM_info.script.name.toString(),o=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-r",i),e.setAttribute("bm-q","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=(t?.getAttribute("bm-r"),t?.getAttribute("bm-q"),window.fetch);window.fetch=async function(...t){const n=await e.apply(this,t),s=n.clone();if((s.headers.get("content-type")||"").includes("application/json")){let e=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore";s.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:e,jsonData:t},"*")}).catch(t=>{})}return n}});var a=GM_getResourceText("CSS-BM-File");GM_addStyle(a);var r=document.createElement("link");r.href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",r.rel="preload",r.as="style",r.onload=function(){this.onload=null,this.rel="stylesheet"},document.head.appendChild(r),new class{constructor(){this.l=null,this.h=null,this.u="#bm-9"}m(t){return this.h=t,this.l=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.u)}),this}p(){return this.l}observe(t,e=!1,n=!1){t.observe(this.h,{childList:e,subtree:n})}};var c=new class{constructor(e,s){var i,o;i=this,(o=t).has(i)?n("Cannot add the same private member more than once"):o instanceof WeakSet?o.add(i):o.set(i,undefined),this.name=e,this.version=s,this.v=null,this.C="bm-e",this.t=null,this.i=null,this.o=[]}M(t){this.v=t}$(){return this.o.length>0&&(this.i=this.o.pop()),this}T(t){t.appendChild(this.t),this.t=null,this.i=null,this.o=[]}S(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"div",{},n)),this}k(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"p",{},n)),this}N(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"small",{},n)),this}I(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"img",{},n)),this}L(n,i={},o=()=>{}){return o(this,s(this,t,e).call(this,"h"+n,{},i)),this}D(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"hr",{},n)),this}H(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"br",{},n)),this}B(n={},i=()=>{}){const o=s(this,t,e).call(this,"label",{textContent:n.textContent??""});delete n.textContent;const a=s(this,t,e).call(this,"input",{type:"checkbox"},n);return o.insertBefore(a,o.firstChild),this.$(),i(this,o,a),this}O(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"button",{},n)),this}P(n={},i=()=>{}){const o=n.title??n.textContent??"Help: No info";delete n.textContent,n.title=`Help: ${o}`;const a={textContent:"?",className:"bm-s",onclick:()=>{this.R(this.C,o)}};return i(this,s(this,t,e).call(this,"button",a,n)),this}U(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"input",{},n)),this}j(n={},i=()=>{}){const o=n.textContent??"";delete n.textContent;const a=s(this,t,e).call(this,"div"),r=s(this,t,e).call(this,"input",{type:"file",style:"display: none;"},n);this.$();const c=s(this,t,e).call(this,"button",{textContent:o});return this.$(),this.$(),c.addEventListener("click",()=>{r.click()}),r.addEventListener("change",()=>{c.style.maxWidth=`${c.offsetWidth}px`,r.files.length>0?c.textContent=r.files[0].name:c.textContent=o}),i(this,a,r,c),this}_(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"textarea",{},n)),this}R(t,e,n=!1){const s=document.getElementById(t.replace(/^#/,""));s&&(s instanceof HTMLInputElement?s.value=e:n?s.textContent=e:s.innerHTML=e)}G(t,e){let n,s=!1,i=0;t=document.querySelector("#"==t?.[0]?t:"#"+t),e=document.querySelector("#"==e?.[0]?e:"#"+e),t&&e?(e.addEventListener("mousedown",function(o){s=!0,n=o.clientX-t.getBoundingClientRect().left,i=o.clientY-t.getBoundingClientRect().top,document.body.style.userSelect="none",e.classList.add("dragging")}),e.addEventListener("touchstart",function(o){s=!0;const a=o?.touches?.[0];a&&(n=a.clientX-t.getBoundingClientRect().left,i=a.clientY-t.getBoundingClientRect().top,document.body.style.userSelect="none",e.classList.add("dragging"))},{passive:!1}),document.addEventListener("mousemove",function(e){s&&(t.style.left=e.clientX-n+"px",t.style.top=e.clientY-i+"px",t.style.right="")}),document.addEventListener("touchmove",function(e){if(s){const s=e?.touches?.[0];if(!s)return;t.style.left=s.clientX-n+"px",t.style.top=s.clientY-i+"px",e.preventDefault()}},{passive:!1}),document.addEventListener("mouseup",function(){s=!1,document.body.style.userSelect="",e.classList.remove("dragging")}),document.addEventListener("touchend",function(){s=!1,document.body.style.userSelect="",e.classList.remove("dragging")}),document.addEventListener("touchcancel",function(){s=!1,document.body.style.userSelect="",e.classList.remove("dragging")})):this.W(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`)}X(t){(0,console.info)(`${this.name}: ${t}`),this.R(this.C,"Status: "+t,!0)}W(t){(0,console.error)(`${this.name}: ${t}`),this.R(this.C,"Error: "+t,!0)}}(i,o),l=new class{constructor(){this.canvas=null,this.Y="div#map canvas",this.q=null,this.state=""}F(t){return document.body.contains(this.canvas)||(this.canvas=document.querySelector(t)),this.canvas}V(t){this.q=t,this.state="file";const e=URL.createObjectURL(t);window.open(e,"_blank"),setTimeout(()=>URL.revokeObjectURL(e),1e4)}A(){const t=this.F(this.Y)?.getContext("2d");t&&(t.fillStyle="red",t.fillRect(21511,1305644,500,500))}},h=new class{constructor(){this.Z=!1,this.J=[]}K(t){window.addEventListener("message",e=>{const n=e.data,s=n.jsonData;var i,o;if(n&&"blue-marble"===n.source)switch(n.endpoint.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).pop()){case"me":if(s.status&&"2"!=s.status?.toString()[0])return void t.W("The game is down!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(s.level)*Math.pow(30,.65),1/.65)-s.pixelsPainted);t.R("bm-j",`Username: ${function(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}(s.name)}`),t.R("bm-f",`Droplets: ${(new Intl.NumberFormat).format(s.droplets)}`),t.R("bm-a",`Next level in ${(new Intl.NumberFormat).format(e)} pixel${1==e?"":"s"}`);break;case"pixel":const a=n.endpoint.split("?")[0].split("/").filter(t=>t&&!isNaN(Number(t))),r=new URLSearchParams(n.endpoint.split("?")[1]),c=[r.get("x"),r.get("y")];if(this.J.length&&(!a.length||!c.length))return void t.W("Coordinates are malformed!\nDid you try clicking the canvas first?");this.J=[...a,...c];const l=(i=a,o=c,[parseInt(i[0])%4*1e3+parseInt(o[0]),parseInt(i[1])%4*1e3+parseInt(o[1])]),h=document.querySelectorAll("span");for(const t of h)if(t.textContent.trim().includes(`${l[0]}, ${l[1]}`)){let e=document.querySelector("#bm-9");const n=`(Tl X: ${a[0]}, Tl Y: ${a[1]}, Px X: ${c[0]}, Px Y: ${c[1]})`;e?e.textContent=n:(e=document.createElement("span"),e.id="bm-9",e.textContent=n,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"robots":this.Z="false"==s.userscript?.toString().toLowerCase()}})}};c.M(h),c.S({id:"bm-p",style:"top: 10px; right: 75px;"}).S({id:"bm-b"}).S({id:"bm-k"}).$().I({alt:"Blue Marble Icon",src:"https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png"}).$().L(1,{textContent:i}).$().$().D().$().S({id:"bm-4"}).k({id:"bm-j",textContent:"Username:"}).$().k({id:"bm-f",textContent:"Droplets:"}).$().k({id:"bm-a",textContent:"Next level in..."}).$().$().D().$().S({id:"bm-3"}).B({id:"bm-g",textContent:"Stealth",checked:!0}).$().P({title:"Waits for the website to make requests, instead of sending requests."}).$().H().$().B({id:"bm-6",textContent:"Possessed",checked:!0}).$().P({title:"Controls the website as if it were possessed."}).$().H().$().S({id:"bm-c"}).O({id:"bm-h",className:"bm-s",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.v?.J;e?.[0]?(t.R("bm-l",e?.[0]||""),t.R("bm-m",e?.[1]||""),t.R("bm-n",e?.[2]||""),t.R("bm-o",e?.[3]||"")):t.W("Coordinates are malformed! Did you try clicking on the canvas first?")}}).$().U({type:"number",id:"bm-l",placeholder:"Tl X",min:0,max:2047,step:1}).$().U({type:"number",id:"bm-m",placeholder:"Tl Y",min:0,max:2047,step:1}).$().U({type:"number",id:"bm-n",placeholder:"Px X",min:0,max:2047,step:1}).$().U({type:"number",id:"bm-o",placeholder:"Px Y",min:0,max:2047,step:1}).$().$().j({id:"bm-2",textContent:"Upload Template",accept:"image/png, image/jpeg, image/webp, image/bmp, image/gif"}).$().S({id:"bm-0"}).O({id:"bm-i",textContent:"Enable"},(t,e)=>{e.onclick=()=>{const e=document.querySelector("#bm-2");e?.files[0]?(l.V(e.files[0]),l.A(),t.X("Drew to canvas!")):t.W("No file selected!")}}).$().O({id:"bm-d",textContent:"Disable"}).$().$()._({id:c.C,placeholder:`Status: Sleeping...\nVersion: ${o}`,readOnly:!0}).$().S({id:"bm-1"}).S().O({id:"bm-7",className:"bm-s",textContent:"✈"}).$().O({id:"bm-8",className:"bm-s",innerHTML:''}).$().O({id:"bm-5",className:"bm-s",innerHTML:"🖌"}).$().$().N({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).$().$().$().T(document.body),c.G("#bm-p","#bm-k"),h.K(c),function(...t){(0,console.log)(...t)}(`%c${i}%c (${o}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file +(()=>{var t,e,n=t=>{throw TypeError(t)},s=(t,e,s)=>(((t,e)=>{e.has(t)||n("Cannot access private method")})(t,e),s);t=new WeakSet,e=function(t,e={},n={}){const s=document.createElement(t);this.t?(this.i.appendChild(s),this.o.push(this.i),this.i=s):(this.t=s,this.i=s);for(const[t,n]of Object.entries(e))s[t]=n;for(const[t,e]of Object.entries(n))s[t]=e;return s};var i=GM_info.script.name.toString(),o=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-r",i),e.setAttribute("bm-q","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-r")||"Blue Marble",n=t?.getAttribute("bm-q")||"",s=window.fetch;window.fetch=async function(...t){const i=await s.apply(this,t),o=i.clone();if((o.headers.get("content-type")||"").includes("application/json")){let s=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore";console.log(`%c${e}%c: Sending JSON message about endpoint "${s}"`,n,""),o.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:s,jsonData:t},"*")}).catch(t=>{console.error(`%c${e}%c: Failed to parse JSON: `,n,"",t)})}return i}});var a=GM_getResourceText("CSS-BM-File");GM_addStyle(a);var r=document.createElement("link");r.href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",r.rel="preload",r.as="style",r.onload=function(){this.onload=null,this.rel="stylesheet"},document.head.appendChild(r),new class{constructor(){this.l=null,this.h=null,this.u="#bm-9"}m(t){return this.h=t,this.l=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.u)}),this}p(){return this.l}observe(t,e=!1,n=!1){t.observe(this.h,{childList:e,subtree:n})}};var c=new class{constructor(e,s){var i,o;i=this,(o=t).has(i)?n("Cannot add the same private member more than once"):o instanceof WeakSet?o.add(i):o.set(i,undefined),this.name=e,this.version=s,this.v=null,this.$="bm-e",this.t=null,this.i=null,this.o=[]}M(t){this.v=t}C(){return this.o.length>0&&(this.i=this.o.pop()),this}T(t){t.appendChild(this.t),this.t=null,this.i=null,this.o=[]}S(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"div",{},n)),this}N(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"p",{},n)),this}k(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"small",{},n)),this}I(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"img",{},n)),this}L(n,i={},o=()=>{}){return o(this,s(this,t,e).call(this,"h"+n,{},i)),this}B(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"hr",{},n)),this}D(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"br",{},n)),this}H(n={},i=()=>{}){const o=s(this,t,e).call(this,"label",{textContent:n.textContent??""});delete n.textContent;const a=s(this,t,e).call(this,"input",{type:"checkbox"},n);return o.insertBefore(a,o.firstChild),this.C(),i(this,o,a),this}O(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"button",{},n)),this}R(n={},i=()=>{}){const o=n.title??n.textContent??"Help: No info";delete n.textContent,n.title=`Help: ${o}`;const a={textContent:"?",className:"bm-s",onclick:()=>{this.P(this.$,o)}};return i(this,s(this,t,e).call(this,"button",a,n)),this}U(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"input",{},n)),this}j(n={},i=()=>{}){const o=n.textContent??"";delete n.textContent;const a=s(this,t,e).call(this,"div"),r=s(this,t,e).call(this,"input",{type:"file",style:"display: none;"},n);this.C();const c=s(this,t,e).call(this,"button",{textContent:o});return this.C(),this.C(),c.addEventListener("click",()=>{r.click()}),r.addEventListener("change",()=>{c.style.maxWidth=`${c.offsetWidth}px`,r.files.length>0?c.textContent=r.files[0].name:c.textContent=o}),i(this,a,r,c),this}_(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"textarea",{},n)),this}P(t,e,n=!1){const s=document.getElementById(t.replace(/^#/,""));s&&(s instanceof HTMLInputElement?s.value=e:n?s.textContent=e:s.innerHTML=e)}F(t,e){let n,s=!1,i=0;t=document.querySelector("#"==t?.[0]?t:"#"+t),e=document.querySelector("#"==e?.[0]?e:"#"+e),t&&e?(e.addEventListener("mousedown",function(o){s=!0,n=o.clientX-t.getBoundingClientRect().left,i=o.clientY-t.getBoundingClientRect().top,document.body.style.userSelect="none",e.classList.add("dragging")}),e.addEventListener("touchstart",function(o){s=!0;const a=o?.touches?.[0];a&&(n=a.clientX-t.getBoundingClientRect().left,i=a.clientY-t.getBoundingClientRect().top,document.body.style.userSelect="none",e.classList.add("dragging"))},{passive:!1}),document.addEventListener("mousemove",function(e){s&&(t.style.left=e.clientX-n+"px",t.style.top=e.clientY-i+"px",t.style.right="")}),document.addEventListener("touchmove",function(e){if(s){const s=e?.touches?.[0];if(!s)return;t.style.left=s.clientX-n+"px",t.style.top=s.clientY-i+"px",e.preventDefault()}},{passive:!1}),document.addEventListener("mouseup",function(){s=!1,document.body.style.userSelect="",e.classList.remove("dragging")}),document.addEventListener("touchend",function(){s=!1,document.body.style.userSelect="",e.classList.remove("dragging")}),document.addEventListener("touchcancel",function(){s=!1,document.body.style.userSelect="",e.classList.remove("dragging")})):this.G(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`)}W(t){(0,console.info)(`${this.name}: ${t}`),this.P(this.$,"Status: "+t,!0)}G(t){(0,console.error)(`${this.name}: ${t}`),this.P(this.$,"Error: "+t,!0)}}(i,o),l=new class{constructor(){this.canvas=null,this.X="div#map canvas",this.Y=null,this.state=""}q(t){return document.body.contains(this.canvas)||(this.canvas=document.querySelector(t)),this.canvas}V(t){this.Y=t,this.state="file";const e=URL.createObjectURL(t);window.open(e,"_blank"),setTimeout(()=>URL.revokeObjectURL(e),1e4)}J(){const t=this.q(this.X)?.getContext("2d");t&&(t.fillStyle="red",t.fillRect(21511,1305644,500,500))}},h=new class{constructor(){this.A=!1,this.Z=[]}K(t){window.addEventListener("message",e=>{const n=e.data,s=n.jsonData;if(!n||"blue-marble"!==n.source)return;const i=n.endpoint.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).pop();switch(console.log(`%cBlue Marble%c: Recieved message about "${i}"`,"color: cornflowerblue;",""),i){case"me":if(s.status&&"2"!=s.status?.toString()[0])return void t.G("The game is down!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(s.level)*Math.pow(30,.65),1/.65)-s.pixelsPainted);t.P("bm-j",`Username: ${function(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}(s.name)}`),t.P("bm-f",`Droplets: ${(new Intl.NumberFormat).format(s.droplets)}`),t.P("bm-a",`Next level in ${(new Intl.NumberFormat).format(e)} pixel${1==e?"":"s"}`);break;case"pixel":const i=n.endpoint.split("?")[0].split("/").filter(t=>t&&!isNaN(Number(t))),r=new URLSearchParams(n.endpoint.split("?")[1]),c=[r.get("x"),r.get("y")];if(this.Z.length&&(!i.length||!c.length))return void t.G("Coordinates are malformed!\nDid you try clicking the canvas first?");this.Z=[...i,...c];const l=(o=i,a=c,[parseInt(o[0])%4*1e3+parseInt(a[0]),parseInt(o[1])%4*1e3+parseInt(a[1])]),h=document.querySelectorAll("span");for(const t of h)if(t.textContent.trim().includes(`${l[0]}, ${l[1]}`)){let e=document.querySelector("#bm-9");const n=`(Tl X: ${i[0]}, Tl Y: ${i[1]}, Px X: ${c[0]}, Px Y: ${c[1]})`;e?e.textContent=n:(e=document.createElement("span"),e.id="bm-9",e.textContent=n,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"robots":this.A="false"==s.userscript?.toString().toLowerCase();break}var o,a})}};c.M(h),c.S({id:"bm-p",style:"top: 10px; right: 75px;"}).S({id:"bm-b"}).S({id:"bm-k"}).C().I({alt:"Blue Marble Icon",src:"https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png"}).C().L(1,{textContent:i}).C().C().B().C().S({id:"bm-4"}).N({id:"bm-j",textContent:"Username:"}).C().N({id:"bm-f",textContent:"Droplets:"}).C().N({id:"bm-a",textContent:"Next level in..."}).C().C().B().C().S({id:"bm-3"}).H({id:"bm-g",textContent:"Stealth",checked:!0}).C().R({title:"Waits for the website to make requests, instead of sending requests."}).C().D().C().H({id:"bm-6",textContent:"Possessed",checked:!0}).C().R({title:"Controls the website as if it were possessed."}).C().D().C().S({id:"bm-c"}).O({id:"bm-h",className:"bm-s",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.v?.Z;e?.[0]?(t.P("bm-l",e?.[0]||""),t.P("bm-m",e?.[1]||""),t.P("bm-n",e?.[2]||""),t.P("bm-o",e?.[3]||"")):t.G("Coordinates are malformed! Did you try clicking on the canvas first?")}}).C().U({type:"number",id:"bm-l",placeholder:"Tl X",min:0,max:2047,step:1}).C().U({type:"number",id:"bm-m",placeholder:"Tl Y",min:0,max:2047,step:1}).C().U({type:"number",id:"bm-n",placeholder:"Px X",min:0,max:2047,step:1}).C().U({type:"number",id:"bm-o",placeholder:"Px Y",min:0,max:2047,step:1}).C().C().j({id:"bm-2",textContent:"Upload Template",accept:"image/png, image/jpeg, image/webp, image/bmp, image/gif"}).C().S({id:"bm-0"}).O({id:"bm-i",textContent:"Enable"},(t,e)=>{e.onclick=()=>{const e=document.querySelector("#bm-2");e?.files[0]?(l.V(e.files[0]),l.J(),t.W("Drew to canvas!")):t.G("No file selected!")}}).C().O({id:"bm-d",textContent:"Disable"}).C().C()._({id:c.$,placeholder:`Status: Sleeping...\nVersion: ${o}`,readOnly:!0}).C().S({id:"bm-1"}).S().O({id:"bm-7",className:"bm-s",textContent:"✈"}).C().O({id:"bm-8",className:"bm-s",innerHTML:''}).C().O({id:"bm-5",className:"bm-s",innerHTML:"🖌"}).C().C().k({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).C().C().C().T(document.body),c.F("#bm-p","#bm-k"),h.K(c),function(...t){(0,console.log)(...t)}(`%c${i}%c (${o}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 73a2363..f55efaf 100644 --- a/docs/README.md +++ b/docs/README.md @@ -35,7 +35,7 @@ Software License: MPL-2.0 Contact Me WakaTime -Total Patches +Total Patches Total Lines of Code Total Comments Compression diff --git a/package-lock.json b/package-lock.json index 59e5dbe..2d04e18 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wplace-bluemarble", - "version": "0.58.25", + "version": "0.59.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wplace-bluemarble", - "version": "0.58.25", + "version": "0.59.8", "devDependencies": { "esbuild": "^0.25.0", "terser": "^5.43.1" diff --git a/package.json b/package.json index f085323..2af8384 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wplace-bluemarble", - "version": "0.59.0", + "version": "0.59.8", "type": "module", "scripts": { "build": "node build/build.js", diff --git a/src/BlueMarble.meta.js b/src/BlueMarble.meta.js index 1eeed42..15f8c50 100644 --- a/src/BlueMarble.meta.js +++ b/src/BlueMarble.meta.js @@ -1,7 +1,7 @@ // ==UserScript== // @name Blue Marble // @namespace https://github.com/SwingTheVine/ -// @version 0.59.0 +// @version 0.59.8 // @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 diff --git a/src/overlay.css b/src/overlay.css index 3f04683..db3f457 100644 --- a/src/overlay.css +++ b/src/overlay.css @@ -94,7 +94,7 @@ div#bm-overlay { } /* Container for action buttons, that is inside the action button container */ -div > #bm-button-teleport { +div:has(> #bm-button-teleport) { display: flex; gap: 0.5ch; }