Added output status UI

This commit is contained in:
SwingTheVine 2025-07-24 18:27:31 -04:00
parent e96a1a40d4
commit 7efa7a4268
7 changed files with 31 additions and 8 deletions

View file

@ -1,7 +1,7 @@
// ==UserScript==
// @name Blue Marble
// @namespace https://github.com/SwingTheVine/
// @version 0.26.0
// @version 0.26.3
// @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 u=class{constructor(t,e){this.name=t,this.version=e}create(){let t="bm-output-status",e=document.createElement("div");e.id="bm-overlay",e.style.top="10px",e.style.right="75px";let n=document.createElement("div");n.id="bm-contain-header";let o=document.createElement("div");o.id="bm-bar-drag",n.appendChild(o);let a=document.createElement("img");a.src="https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/src/assets/Favicon.png",a.alt="Blue Marble Icon",n.appendChild(a);let s=document.createElement("h1");s.textContent=this.name,n.appendChild(s);let c=document.createElement("div");c.id="bm-contain-userinfo";let m=document.createElement("p");m.id="bm-user-name",m.textContent="Username:",c.appendChild(m);let h=document.createElement("p");h.id="bm-user-droplets",h.textContent="Droplets:",c.appendChild(h);let f=document.createElement("p");f.id="bm-user-nextlevel",f.textContent="Next level in...",c.appendChild(f);let d=document.createElement("div");d.id="bm-contain-automation";let g=document.createElement("label");g.textContent="Stealth Mode";let r=document.createElement("input");r.type="checkbox",r.id="bm-input-stealth",r.checked=!0,g.prepend(r),d.appendChild(g),d.appendChild(this.createQuestionBox("bm-help-stealth","Waits for the website to make the request, instead of sending a request.",t)),e.appendChild(n),e.appendChild(document.createElement("hr")),e.appendChild(c),e.appendChild(document.createElement("hr")),e.appendChild(d),document.body.appendChild(e),this.handleDrag(e,o)}updateInnerHTML(t,e,n=!1){let o=document.getElementById(t);o&&(n?o.textContent=e:o.innerHTML=e)}createQuestionBox(t,e,n){let o=document.createElement("button");return o.id=t,o.className="bm-help",o.textContent="?",o.title=e,o.onclick=()=>{this.updateInnerHTML(n,e)},o}handleDrag(t,e){let n=!1,o,a=0;e.addEventListener("mousedown",function(s){n=!0,o=s.clientX-t.getBoundingClientRect().left,a=s.clientY-t.getBoundingClientRect().top,document.body.style.userSelect="none",e.classList.add("dragging")}),e.addEventListener("touchstart",function(s){n=!0;let c=s?.touches?.[0];c&&(o=c.clientX-t.getBoundingClientRect().left,a=c.clientY-t.getBoundingClientRect().top,document.body.style.userSelect="none",e.classList.add("dragging"))},{passive:!1}),document.addEventListener("mousemove",function(s){n&&(t.style.left=s.clientX-o+"px",t.style.top=s.clientY-a+"px",t.style.right="")}),document.addEventListener("touchmove",function(s){if(n){let c=s?.touches?.[0];if(!c)return;t.style.left=c.clientX-o+"px",t.style.top=c.clientY-a+"px",s.preventDefault()}},{passive:!1}),document.addEventListener("mouseup",function(){n=!1,document.body.style.userSelect="",e.classList.remove("dragging")}),document.addEventListener("touchend",function(){n=!1,document.body.style.userSelect="",e.classList.remove("dragging")}),document.addEventListener("touchcancel",function(){n=!1,document.body.style.userSelect="",e.classList.remove("dragging")})}};var p=class{constructor(){this.disableAll=!1}spontaneousResponseListener(t){window.addEventListener("message",e=>{let n=e.data;if(n&&n.source==="blue-marble")switch(n.endpoint){case"me":let o=Math.ceil(Math.pow(Math.floor(n.jsonData?.level)*Math.pow(30,.65),1.5384615384615383)-n.jsonData?.pixelsPainted);t.updateInnerHTML("bm-user-name",`Username: <b>${n.jsonData?.name}</b>`),t.updateInnerHTML("bm-user-droplets",`Droplets: <b>${new Intl.NumberFormat().format(n.jsonData?.droplets)}</b>`),t.updateInnerHTML("bm-user-nextlevel",`Next level in <b>${new Intl.NumberFormat().format(o)}</b> pixel${o==1?"":"s"}`);break;case"robots":this.disableAll=n.jsonData?.userscript?.toString().toLowerCase()=="false"}})}};var b=GM_info.script.name.toString(),x=GM_info.script.version.toString();function v(i){let t=document.createElement("script");t.textContent=`(${i})();`,document.documentElement.appendChild(t),t.remove()}v(()=>{let i=window.fetch;window.fetch=async function(...t){let e=await i.apply(this,t),n=e.clone();if((n.headers.get("content-type")||"").includes("application/json")){let a=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore";a=a.split("/").filter(Boolean).pop()||"ignore",console.log(`Sending JSON message about endpoint "${a}"`),n.json().then(s=>{window.postMessage({source:"blue-marble",endpoint:a,jsonData:s},"*")}).catch(s=>{console.error("BM - Failed to parse JSON:",s)})}return e}});var y=GM_getResourceText("CSS-Overlay");GM_addStyle(y);var l=document.createElement("link");l.href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap";l.rel="preload";l.as="style";l.onload="this.onload=null;this.rel='stylesheet'";document.head.appendChild(l);var C=new u(b,x);C.create();var E=new p;E.spontaneousResponseListener(C);console.log(`${b} (${x}) userscript has loaded!`);})();
(()=>{var p=class{constructor(t,e){this.name=t,this.version=e}create(){let t="bm-output-status",e=document.createElement("div");e.id="bm-overlay",e.style.top="10px",e.style.right="75px";let n=document.createElement("div");n.id="bm-contain-header";let o=document.createElement("div");o.id="bm-bar-drag",n.appendChild(o);let a=document.createElement("img");a.src="https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/src/assets/Favicon.png",a.alt="Blue Marble Icon",n.appendChild(a);let s=document.createElement("h1");s.textContent=this.name,n.appendChild(s);let c=document.createElement("div");c.id="bm-contain-userinfo";let h=document.createElement("p");h.id="bm-user-name",h.textContent="Username:",c.appendChild(h);let f=document.createElement("p");f.id="bm-user-droplets",f.textContent="Droplets:",c.appendChild(f);let g=document.createElement("p");g.id="bm-user-nextlevel",g.textContent="Next level in...",c.appendChild(g);let i=document.createElement("div");i.id="bm-contain-automation";let b=document.createElement("label");b.textContent="Stealth Mode";let r=document.createElement("input");r.type="checkbox",r.id="bm-input-stealth",r.checked=!0,b.prepend(r),i.appendChild(b),i.appendChild(this.createQuestionBox("bm-help-stealth","Waits for the website to make requests, instead of sending requests.",t)),i.appendChild(document.createElement("br"));let u=document.createElement("textarea");u.id=t,u.readOnly=!0,u.placeholder="Status: Sleeping...",i.appendChild(u),e.appendChild(n),e.appendChild(document.createElement("hr")),e.appendChild(c),e.appendChild(document.createElement("hr")),e.appendChild(i),document.body.appendChild(e),this.handleDrag(e,o)}updateInnerHTML(t,e,n=!1){let o=document.getElementById(t);if(o){if(o instanceof HTMLInputElement){o.value=e;return}n?o.textContent=e:o.innerHTML=e}}createQuestionBox(t,e,n){let o=document.createElement("button");return o.id=t,o.className="bm-help",o.textContent="?",o.title=e,o.onclick=()=>{this.updateInnerHTML(n,e)},o}handleDrag(t,e){let n=!1,o,a=0;e.addEventListener("mousedown",function(s){n=!0,o=s.clientX-t.getBoundingClientRect().left,a=s.clientY-t.getBoundingClientRect().top,document.body.style.userSelect="none",e.classList.add("dragging")}),e.addEventListener("touchstart",function(s){n=!0;let c=s?.touches?.[0];c&&(o=c.clientX-t.getBoundingClientRect().left,a=c.clientY-t.getBoundingClientRect().top,document.body.style.userSelect="none",e.classList.add("dragging"))},{passive:!1}),document.addEventListener("mousemove",function(s){n&&(t.style.left=s.clientX-o+"px",t.style.top=s.clientY-a+"px",t.style.right="")}),document.addEventListener("touchmove",function(s){if(n){let c=s?.touches?.[0];if(!c)return;t.style.left=c.clientX-o+"px",t.style.top=c.clientY-a+"px",s.preventDefault()}},{passive:!1}),document.addEventListener("mouseup",function(){n=!1,document.body.style.userSelect="",e.classList.remove("dragging")}),document.addEventListener("touchend",function(){n=!1,document.body.style.userSelect="",e.classList.remove("dragging")}),document.addEventListener("touchcancel",function(){n=!1,document.body.style.userSelect="",e.classList.remove("dragging")})}};var m=class{constructor(){this.disableAll=!1}spontaneousResponseListener(t){window.addEventListener("message",e=>{let n=e.data;if(n&&n.source==="blue-marble")switch(n.endpoint){case"me":let o=Math.ceil(Math.pow(Math.floor(n.jsonData?.level)*Math.pow(30,.65),1.5384615384615383)-n.jsonData?.pixelsPainted);t.updateInnerHTML("bm-user-name",`Username: <b>${n.jsonData?.name}</b>`),t.updateInnerHTML("bm-user-droplets",`Droplets: <b>${new Intl.NumberFormat().format(n.jsonData?.droplets)}</b>`),t.updateInnerHTML("bm-user-nextlevel",`Next level in <b>${new Intl.NumberFormat().format(o)}</b> pixel${o==1?"":"s"}`);break;case"robots":this.disableAll=n.jsonData?.userscript?.toString().toLowerCase()=="false"}})}};var C=GM_info.script.name.toString(),x=GM_info.script.version.toString();function v(l){let t=document.createElement("script");t.textContent=`(${l})();`,document.documentElement.appendChild(t),t.remove()}v(()=>{let l=window.fetch;window.fetch=async function(...t){let e=await l.apply(this,t),n=e.clone();if((n.headers.get("content-type")||"").includes("application/json")){let a=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore";a=a.split("/").filter(Boolean).pop()||"ignore",console.log(`Sending JSON message about endpoint "${a}"`),n.json().then(s=>{window.postMessage({source:"blue-marble",endpoint:a,jsonData:s},"*")}).catch(s=>{console.error("BM - Failed to parse JSON:",s)})}return e}});var y=GM_getResourceText("CSS-Overlay");GM_addStyle(y);var d=document.createElement("link");d.href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap";d.rel="preload";d.as="style";d.onload="this.onload=null;this.rel='stylesheet'";document.head.appendChild(d);var E=new p(C,x);E.create();var L=new m;L.spontaneousResponseListener(E);console.log(`${C} (${x}) userscript has loaded!`);})();

View file

@ -23,7 +23,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-10hrs_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-64-black?style=flat"></a>
<a href="" target="_blank"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-67-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="Build" src="https://github.com/SwingTheVine/Wplace-BlueMarble/actions/workflows/build.yml/badge.svg"></a>

4
package-lock.json generated
View file

@ -7,7 +7,7 @@
"devDependencies": {
"esbuild": "^0.25.0"
},
"version": "0.25.6"
"version": "0.26.3"
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.8",
@ -467,5 +467,5 @@
}
}
},
"version": "0.25.6"
"version": "0.26.3"
}

View file

@ -1,6 +1,6 @@
{
"name": "wplace-bluemarble",
"version": "0.26.0",
"version": "0.26.3",
"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.26.0
// @version 0.26.3
// @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

@ -73,4 +73,12 @@ div#bm-overlay {
margin-top: 2px;
text-align: center;
line-height: 1.25em;
}
#bm-output-status {
font-size: small;
background-color: rgba(0, 0, 0, 0.2);
padding: 0 0.5ch;
height: 3em;
width: 100%;
}

View file

@ -77,10 +77,18 @@ export class Overlay {
// Adds the help icon for stealth mode
containerAutomation.appendChild(this.createQuestionBox(
'bm-help-stealth',
'Waits for the website to make the request, instead of sending a request.',
'Help: Waits for the website to make requests, instead of sending requests.',
outputStatusId
));
containerAutomation.appendChild(document.createElement('br')); // Line break
const outputStatus = document.createElement('textarea'); // Outputs bot status
outputStatus.id = outputStatusId;
outputStatus.readOnly = true; // Read-only input field
outputStatus.placeholder = 'Status: Sleeping...'; // Default text value
containerAutomation.appendChild(outputStatus);
// Construction of the overlay element
overlay.appendChild(containerOverlayHeader); // Adds the overlay header container to the overlay
overlay.appendChild(document.createElement('hr')); // Adds a horizontal line to the overlay
@ -94,6 +102,7 @@ export class Overlay {
/** Updates the inner HTML of the element.
* The element is discovered by it's id.
* If the element is an <input>, it will modify the value attribute instead.
* @param {string} id - The ID of the element to change
* @param {string} html - The HTML/text to update with
* @param {boolean} [doSafe] - (Optional) Should `textContent` be used instead of `innerHTML` to avoid XSS? False by default
@ -104,6 +113,12 @@ export class Overlay {
const element = document.getElementById(id); // Retrieve the element
if (!element) {return;} // Kills itself if the element does not exist
// Input elements don't have innerHTML, so we modify the value attribute instead
if (element instanceof HTMLInputElement) {
element.value = html;
return;
}
if (doSafe) {
element.textContent = html; // Populate element with plain-text HTML/text
} else {