diff --git a/dist/BlueMarble.user.js b/dist/BlueMarble.user.js index a8ec140..dd4e844 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.66.2 +// @version 0.66.4 // @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)=>e.has(t)?n("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,s),i=(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 o,a=class{constructor({displayName:t="My template",l:e=0,h:n="",url:s="",file:i=null,coords:o=null,u:a=null,m:r=1e3}={}){this.displayName=t,this.l=e,this.h=n,this.url=s,this.file=i,this.coords=o,this.u=a,this.m=r}async p(){console.log(this.coords);const t=await createImageBitmap(this.file),e=t.width,n=t.height,s={},i=new OffscreenCanvas(this.m,this.m),o=i.getContext("2d",{$:!0});for(let a=this.coords[3];a0;)n=e[t%s]+n,t=Math.floor(t/s);return n}o=new WeakSet;var c=GM_info.script.name.toString(),l=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-n",c),e.setAttribute("bm-l","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-n")||"Blue Marble",n=t?.getAttribute("bm-l")||"",s=new Map;window.addEventListener("message",t=>{const{source:i,endpoint:o,blobID:a,blobData:r,blink:c}=t.data,l=Date.now()-c;if(console.groupCollapsed(`%c${e}%c: ${s.size} Recieved IMAGE message about blob "${a}"`,n,""),console.log(`Blob fetch took %c${String(Math.floor(l/6e4)).padStart(2,"0")}:${String(Math.floor(l/1e3)%60).padStart(2,"0")}.${String(l%1e3).padStart(3,"0")}%c MM:SS.mmm`,n,""),console.log(s),console.groupEnd(),"blue-marble"==i&&a&&r&&!o){const t=s.get(a);"function"==typeof t?t(r):function(...t){(0,console.warn)(...t)}(`%c${e}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,n,"",a),s.delete(a)}});const i=window.fetch;window.fetch=async function(...t){const o=await i.apply(this,t),a=o.clone(),r=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore",c=a.headers.get("content-type")||"";if(c.includes("application/json"))console.log(`%c${e}%c: Sending JSON message about endpoint "${r}"`,n,""),a.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:r,jsonData:t},"*")}).catch(t=>{console.error(`%c${e}%c: Failed to parse JSON: `,n,"",t)});else if(c.includes("image/")&&!r.includes("openfreemap")){const t=Date.now(),i=await a.blob();return console.log(`%c${e}%c: ${s.size} Sending IMAGE message about endpoint "${r}"`,n,""),new Promise(o=>{const c=crypto.randomUUID();s.set(c,t=>{o(new Response(t,{headers:a.headers,status:a.status,statusText:a.statusText})),console.log(`%c${e}%c: ${s.size} Processed blob "${c}"`,n,"")}),window.postMessage({source:"blue-marble",endpoint:r,blobID:c,blobData:i,blink:t})}).catch(i=>{const o=Date.now();console.error(`%c${e}%c: Failed to Promise blob!`,n,""),console.groupCollapsed(`%c${e}%c: Details of failed blob Promise:`,n,""),console.log(`Endpoint: ${r}\nThere are ${s.size} blobs processing...\nBlink: ${t.toLocaleString()}\nTime Since Blink: ${String(Math.floor(o/6e4)).padStart(2,"0")}:${String(Math.floor(o/1e3)%60).padStart(2,"0")}.${String(o%1e3).padStart(3,"0")} MM:SS.mmm`),console.error("Exception stack:",i),console.groupEnd()})}return o}});var h=GM_getResourceText("CSS-BM-File");GM_addStyle(h);var u=document.createElement("link");u.href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",u.rel="preload",u.as="style",u.onload=function(){this.onload=null,this.rel="stylesheet"},document.head.appendChild(u),new class{constructor(){this.v=null,this.M=null,this.S="#bm-5"}D(t){return this.M=t,this.v=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.S)}),this}C(){return this.v}observe(t,e=!1,n=!1){t.observe(this.M,{childList:e,subtree:n})}};var d=new class{constructor(e,n){s(this,t),this.name=e,this.version=n,this.T=null,this.k="bm-a",this.t=null,this.i=null,this.o=[]}I(t){this.T=t}N(){return this.o.length>0&&(this.i=this.o.pop()),this}B(t){t.appendChild(this.t),this.t=null,this.i=null,this.o=[]}O(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"div",{},n)),this}P(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"p",{},n)),this}H(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"small",{},n)),this}L(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"img",{},n)),this}R(n,s={},o=()=>{}){return o(this,i(this,t,e).call(this,"h"+n,{},s)),this}Y(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"hr",{},n)),this}G(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"br",{},n)),this}X(n={},s=()=>{}){const o=i(this,t,e).call(this,"label",{textContent:n.textContent??""});delete n.textContent;const a=i(this,t,e).call(this,"input",{type:"checkbox"},n);return o.insertBefore(a,o.firstChild),this.N(),s(this,o,a),this}j(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"button",{},n)),this}q(n={},s=()=>{}){const o=n.title??n.textContent??"Help: No info";delete n.textContent,n.title=`Help: ${o}`;const a={textContent:"?",className:"bm-o",onclick:()=>{this._(this.k,o)}};return s(this,i(this,t,e).call(this,"button",a,n)),this}F(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"input",{},n)),this}J(n={},s=()=>{}){const o=n.textContent??"";delete n.textContent;const a=i(this,t,e).call(this,"div"),r=i(this,t,e).call(this,"input",{type:"file",style:"display: none;"},n);this.N();const c=i(this,t,e).call(this,"button",{textContent:o});return this.N(),this.N(),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}),s(this,a,r,c),this}V(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"textarea",{},n)),this}_(t,e,n=!1){const s=document.getElementById(t.replace(/^#/,""));s&&(s instanceof HTMLInputElement?s.value=e:n?s.textContent=e:s.innerHTML=e)}W(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.A(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`)}U(t){(0,console.info)(`${this.name}: ${t}`),this._(this.k,"Status: "+t,!0)}A(t){(0,console.error)(`${this.name}: ${t}`),this._(this.k,"Error: "+t,!0)}}(c,l),m=new class{constructor(t,e,n){s(this,o),this.name=t,this.version=e,this.t=n,this.Z="1.0.0",this.K=null,this.tt="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.m=1e3,this.et=3,this.nt=null,this.st=null,this.it="bm-m",this.ot="div#map canvas.maplibregl-canvas",this.rt=null,this.ct="",this.lt=[],this.ht=null}ut(){if(document.body.contains(this.nt))return this.nt;document.getElementById(this.it)?.remove();const t=document.querySelector(this.ot),e=document.createElement("canvas");return e.id=this.it,e.className="maplibregl-canvas",e.style.position="absolute",e.style.top="0",e.style.left="0",e.style.height=t?.clientHeight*(window.devicePixelRatio||1)+"px",e.style.width=t?.clientWidth*(window.devicePixelRatio||1)+"px",e.height=t?.clientHeight*(window.devicePixelRatio||1),e.width=t?.clientWidth*(window.devicePixelRatio||1),e.style.zIndex="8999",e.style.pointerEvents="none",t?.parentElement?.appendChild(e),this.nt=e,window.addEventListener("move",this.dt),window.addEventListener("zoom",this.bt),window.addEventListener("resize",this.ft),this.nt}async gt(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.Z,templates:{}}}async $t(t,e,n){this.ht||(this.ht=await this.gt(),console.log("Creating JSON...")),this.t.U(`Creating template at ${n.join(", ")}...`);const s=new a({displayName:e,l:0,h:r(this.K||0,this.tt),file:t,coords:n});s.u=await s.p(this.m),this.ht.templates[`${s.l} ${s.h}`]={name:s.displayName,enabled:!0,tiles:s.u},this.lt=[],this.lt.push(s),this.t.U(`Template created at ${n.join(", ")}!`),console.log(Object.keys(this.ht.templates).length),console.log(this.ht),console.log(this.lt)}wt(){}async yt(){this.ht||(this.ht=await this.gt(),console.log("Creating JSON..."))}async vt(t,e){const n=this.m*this.et;e=e[0].toString().padStart(4,"0")+","+e[1].toString().padStart(4,"0"),console.log(`Looking for "${e}"`);const s=this.lt;s.sort((t,e)=>t.l-e.l),console.log(s);const i=s.map(t=>{const n=Object.keys(t.u).filter(t=>t.startsWith(e));if(0===n.length)return null;const s=n.map(e=>t.u[e]);return s?.[0]}).filter(Boolean);console.log(i),i.length>0&&this.t.U(`Displaying ${i.length} template${1==i.length?"":"s"}.`);const o=await createImageBitmap(t),a=new OffscreenCanvas(n,n),r=a.getContext("2d");r.imageSmoothingEnabled=!1,r.beginPath(),r.rect(0,0,n,n),r.clip(),r.clearRect(0,0,n,n),r.drawImage(o,0,0,n,n);for(const t of i)console.log("Template Blob is "+typeof t),console.log(t),r.drawImage(t,e[0]*this.et,e[1]*this.et);return await a.convertToBlob({type:"image/png"})}xt(){}}(c,l,d),p=new class{constructor(t){this.Mt=t,this.St=!1,this.Dt=[],this.Ct=[]}Tt(t){window.addEventListener("message",async e=>{const n=e.data,s=n.jsonData;if(!n||"blue-marble"!==n.source)return;if(!n.endpoint)return;const i=n.endpoint?.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).filter(t=>t&&!t.includes(".")).pop();switch(console.log('%cBlue Marble%c: Recieved message about "%s"',"color: cornflowerblue;","",i),i){case"me":if(s.status&&"2"!=s.status?.toString()[0])return void t.A("You are not logged in!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(s.level)*Math.pow(30,.65),1/.65)-s.pixelsPainted);console.log(s.id),(s.id||0===s.id)&&console.log(r(s.id,"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")),this.Mt.K=s.id,t._("bm-e",`Username: ${function(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}(s.name)}`),t._("bm-b",`Droplets: ${(new Intl.NumberFormat).format(s.droplets)}`),t._("bm-6",`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))),c=new URLSearchParams(n.endpoint.split("?")[1]),l=[c.get("x"),c.get("y")];if(this.Dt.length&&(!i.length||!l.length))return void t.A("Coordinates are malformed!\nDid you try clicking the canvas first?");this.Dt=[...i,...l];const h=(o=i,a=l,[parseInt(o[0])%4*1e3+parseInt(a[0]),parseInt(o[1])%4*1e3+parseInt(a[1])]),u=document.querySelectorAll("span");for(const t of u)if(t.textContent.trim().includes(`${h[0]}, ${h[1]}`)){let e=document.querySelector("#bm-5");const n=`(Tl X: ${i[0]}, Tl Y: ${i[1]}, Px X: ${l[0]}, Px Y: ${l[1]})`;e?e.textContent=n:(e=document.createElement("span"),e.id="bm-5",e.textContent=n,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"tiles":let d=n.endpoint.split("/");d=[parseInt(d[d.length-2]),parseInt(d[d.length-1].replace(".png",""))];const m=n.blobID,p=n.blobData,b=await this.Mt.vt(p,d);window.postMessage({source:"blue-marble",blobID:m,blobData:b,blink:n.blink});break;case"robots":this.St="false"==s.userscript?.toString().toLowerCase();break}var o,a})}}(m);d.I(p),d.O({id:"bm-k",style:"top: 10px; right: 75px;"}).O({id:"bm-7"}).O({id:"bm-f"}).N().L({alt:"Blue Marble Icon",src:"https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png"}).N().R(1,{textContent:c}).N().N().Y().N().O({id:"bm-4"}).P({id:"bm-e",textContent:"Username:"}).N().P({id:"bm-b",textContent:"Droplets:"}).N().P({id:"bm-6",textContent:"Next level in..."}).N().N().Y().N().O({id:"bm-3"}).O({id:"bm-8"}).j({id:"bm-c",className:"bm-o",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.T?.Dt;e?.[0]?(t._("bm-g",e?.[0]||""),t._("bm-h",e?.[1]||""),t._("bm-i",e?.[2]||""),t._("bm-j",e?.[3]||"")):t.A("Coordinates are malformed! Did you try clicking on the canvas first?")}}).N().F({type:"number",id:"bm-g",placeholder:"Tl X",min:0,max:2047,step:1,required:!0}).N().F({type:"number",id:"bm-h",placeholder:"Tl Y",min:0,max:2047,step:1,required:!0}).N().F({type:"number",id:"bm-i",placeholder:"Px X",min:0,max:2047,step:1,required:!0}).N().F({type:"number",id:"bm-j",placeholder:"Px Y",min:0,max:2047,step:1,required:!0}).N().N().J({id:"bm-2",textContent:"Upload Template",accept:"image/png, image/jpeg, image/webp, image/bmp, image/gif"}).N().O({id:"bm-0"}).j({id:"bm-d",textContent:"Enable"},(t,e)=>{e.onclick=()=>{const e=document.querySelector("#bm-2"),n=document.querySelector("#bm-g");if(!n.checkValidity())return n.reportValidity(),void t.A("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-h");if(!s.checkValidity())return s.reportValidity(),void t.A("Coordinates are malformed! Did you try clicking on the canvas first?");const i=document.querySelector("#bm-i");if(!i.checkValidity())return i.reportValidity(),void t.A("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-j");if(!o.checkValidity())return o.reportValidity(),void t.A("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(m.$t(e.files[0],e.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(n.value),Number(s.value),Number(i.value),Number(o.value)]),t.U("Drew to canvas!")):t.A("No file selected!")}}).N().N().V({id:d.k,placeholder:`Status: Sleeping...\nVersion: ${l}`,readOnly:!0}).N().O({id:"bm-1"}).O().j({id:"bm-9",className:"bm-o",innerHTML:"🎨",title:"Template Color Converter"},(t,e)=>{e.addEventListener("click",()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")})}).N().N().H({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).N().N().N().B(document.body),d.W("#bm-k","#bm-f"),p.Tt(d),function(...t){(0,console.log)(...t)}(`%c${c}%c (${l}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file +(()=>{var t,e,n=t=>{throw TypeError(t)},s=(t,e,s)=>e.has(t)?n("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,s),i=(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 o,a=class{constructor({displayName:t="My template",l:e=0,h:n="",url:s="",file:i=null,coords:o=null,u:a=null,m:r=1e3}={}){this.displayName=t,this.l=e,this.h=n,this.url=s,this.file=i,this.coords=o,this.u=a,this.m=r}async p(){console.log(this.coords);const t=await createImageBitmap(this.file),e=t.width,n=t.height,s={},i=new OffscreenCanvas(this.m,this.m),o=i.getContext("2d",{$:!0});for(let a=this.coords[3];a0;)n=e[t%s]+n,t=Math.floor(t/s);return n}o=new WeakSet;var c=GM_info.script.name.toString(),l=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-n",c),e.setAttribute("bm-l","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-n")||"Blue Marble",n=t?.getAttribute("bm-l")||"",s=new Map;window.addEventListener("message",t=>{const{source:i,endpoint:o,blobID:a,blobData:r,blink:c}=t.data,l=Date.now()-c;if(console.groupCollapsed(`%c${e}%c: ${s.size} Recieved IMAGE message about blob "${a}"`,n,""),console.log(`Blob fetch took %c${String(Math.floor(l/6e4)).padStart(2,"0")}:${String(Math.floor(l/1e3)%60).padStart(2,"0")}.${String(l%1e3).padStart(3,"0")}%c MM:SS.mmm`,n,""),console.log(s),console.groupEnd(),"blue-marble"==i&&a&&r&&!o){const t=s.get(a);"function"==typeof t?t(r):function(...t){(0,console.warn)(...t)}(`%c${e}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,n,"",a),s.delete(a)}});const i=window.fetch;window.fetch=async function(...t){const o=await i.apply(this,t),a=o.clone(),r=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore",c=a.headers.get("content-type")||"";if(c.includes("application/json"))console.log(`%c${e}%c: Sending JSON message about endpoint "${r}"`,n,""),a.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:r,jsonData:t},"*")}).catch(t=>{console.error(`%c${e}%c: Failed to parse JSON: `,n,"",t)});else if(c.includes("image/")&&!r.includes("openfreemap")){const t=Date.now(),i=await a.blob();return console.log(`%c${e}%c: ${s.size} Sending IMAGE message about endpoint "${r}"`,n,""),new Promise(o=>{const c=crypto.randomUUID();s.set(c,t=>{o(new Response(t,{headers:a.headers,status:a.status,statusText:a.statusText})),console.log(`%c${e}%c: ${s.size} Processed blob "${c}"`,n,"")}),window.postMessage({source:"blue-marble",endpoint:r,blobID:c,blobData:i,blink:t})}).catch(i=>{const o=Date.now();console.error(`%c${e}%c: Failed to Promise blob!`,n,""),console.groupCollapsed(`%c${e}%c: Details of failed blob Promise:`,n,""),console.log(`Endpoint: ${r}\nThere are ${s.size} blobs processing...\nBlink: ${t.toLocaleString()}\nTime Since Blink: ${String(Math.floor(o/6e4)).padStart(2,"0")}:${String(Math.floor(o/1e3)%60).padStart(2,"0")}.${String(o%1e3).padStart(3,"0")} MM:SS.mmm`),console.error("Exception stack:",i),console.groupEnd()})}return o}});var h=GM_getResourceText("CSS-BM-File");GM_addStyle(h);var u=document.createElement("link");u.href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",u.rel="preload",u.as="style",u.onload=function(){this.onload=null,this.rel="stylesheet"},document.head.appendChild(u),new class{constructor(){this.v=null,this.M=null,this.S="#bm-5"}D(t){return this.M=t,this.v=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.S)}),this}C(){return this.v}observe(t,e=!1,n=!1){t.observe(this.M,{childList:e,subtree:n})}};var d=new class{constructor(e,n){s(this,t),this.name=e,this.version=n,this.T=null,this.k="bm-a",this.t=null,this.i=null,this.o=[]}I(t){this.T=t}N(){return this.o.length>0&&(this.i=this.o.pop()),this}B(t){t.appendChild(this.t),this.t=null,this.i=null,this.o=[]}O(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"div",{},n)),this}L(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"p",{},n)),this}P(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"small",{},n)),this}H(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"img",{},n)),this}R(n,s={},o=()=>{}){return o(this,i(this,t,e).call(this,"h"+n,{},s)),this}Y(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"hr",{},n)),this}G(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"br",{},n)),this}X(n={},s=()=>{}){const o=i(this,t,e).call(this,"label",{textContent:n.textContent??""});delete n.textContent;const a=i(this,t,e).call(this,"input",{type:"checkbox"},n);return o.insertBefore(a,o.firstChild),this.N(),s(this,o,a),this}j(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"button",{},n)),this}q(n={},s=()=>{}){const o=n.title??n.textContent??"Help: No info";delete n.textContent,n.title=`Help: ${o}`;const a={textContent:"?",className:"bm-o",onclick:()=>{this._(this.k,o)}};return s(this,i(this,t,e).call(this,"button",a,n)),this}F(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"input",{},n)),this}J(n={},s=()=>{}){const o=n.textContent??"";delete n.textContent;const a=i(this,t,e).call(this,"div"),r=i(this,t,e).call(this,"input",{type:"file",style:"display: none;"},n);this.N();const c=i(this,t,e).call(this,"button",{textContent:o});return this.N(),this.N(),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}),s(this,a,r,c),this}V(n={},s=()=>{}){return s(this,i(this,t,e).call(this,"textarea",{},n)),this}_(t,e,n=!1){const s=document.getElementById(t.replace(/^#/,""));s&&(s instanceof HTMLInputElement?s.value=e:n?s.textContent=e:s.innerHTML=e)}W(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.A(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`)}U(t){(0,console.info)(`${this.name}: ${t}`),this._(this.k,"Status: "+t,!0)}A(t){(0,console.error)(`${this.name}: ${t}`),this._(this.k,"Error: "+t,!0)}}(c,l),m=new class{constructor(t,e,n){s(this,o),this.name=t,this.version=e,this.t=n,this.Z="1.0.0",this.K=null,this.tt="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.m=1e3,this.et=3,this.nt=null,this.st=null,this.it="bm-m",this.ot="div#map canvas.maplibregl-canvas",this.rt=null,this.ct="",this.lt=[],this.ht=null}ut(){if(document.body.contains(this.nt))return this.nt;document.getElementById(this.it)?.remove();const t=document.querySelector(this.ot),e=document.createElement("canvas");return e.id=this.it,e.className="maplibregl-canvas",e.style.position="absolute",e.style.top="0",e.style.left="0",e.style.height=t?.clientHeight*(window.devicePixelRatio||1)+"px",e.style.width=t?.clientWidth*(window.devicePixelRatio||1)+"px",e.height=t?.clientHeight*(window.devicePixelRatio||1),e.width=t?.clientWidth*(window.devicePixelRatio||1),e.style.zIndex="8999",e.style.pointerEvents="none",t?.parentElement?.appendChild(e),this.nt=e,window.addEventListener("move",this.dt),window.addEventListener("zoom",this.bt),window.addEventListener("resize",this.ft),this.nt}async gt(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.Z,templates:{}}}async $t(t,e,n){this.ht||(this.ht=await this.gt(),console.log("Creating JSON...")),this.t.U(`Creating template at ${n.join(", ")}...`);const s=new a({displayName:e,l:0,h:r(this.K||0,this.tt),file:t,coords:n});s.u=await s.p(this.m),this.ht.templates[`${s.l} ${s.h}`]={name:s.displayName,enabled:!0,tiles:s.u},this.lt=[],this.lt.push(s),this.t.U(`Template created at ${n.join(", ")}!`),console.log(Object.keys(this.ht.templates).length),console.log(this.ht),console.log(this.lt)}wt(){}async vt(){this.ht||(this.ht=await this.gt(),console.log("Creating JSON..."))}async yt(t,e){const n=this.m*this.et;e=e[0].toString().padStart(4,"0")+","+e[1].toString().padStart(4,"0"),console.log(`Looking for "${e}"`);const s=this.lt;s.sort((t,e)=>t.l-e.l),console.log(s);const i=s.map(t=>{const n=Object.keys(t.u).filter(t=>t.startsWith(e));if(0===n.length)return null;const s=n.map(e=>t.u[e]);return s?.[0]}).filter(Boolean);console.log(i),i.length>0&&this.t.U(`Displaying ${i.length} template${1==i.length?"":"s"}.`);const o=await createImageBitmap(t),a=new OffscreenCanvas(n,n),r=a.getContext("2d");r.imageSmoothingEnabled=!1,r.beginPath(),r.rect(0,0,n,n),r.clip(),r.clearRect(0,0,n,n),r.drawImage(o,0,0,n,n);for(const t of i)console.log("Template Blob is "+typeof t),console.log(t),r.drawImage(t,e[0]*this.et,e[1]*this.et);return await a.convertToBlob({type:"image/png"})}xt(){}}(c,l,d),p=new class{constructor(t){this.Mt=t,this.St=!1,this.Dt=[],this.Ct=[]}Tt(t){window.addEventListener("message",async e=>{const n=e.data,s=n.jsonData;if(!n||"blue-marble"!==n.source)return;if(!n.endpoint)return;const i=n.endpoint?.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).filter(t=>t&&!t.includes(".")).pop();switch(console.log('%cBlue Marble%c: Recieved message about "%s"',"color: cornflowerblue;","",i),i){case"me":if(s.status&&"2"!=s.status?.toString()[0])return void t.A("You are not logged in!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(s.level)*Math.pow(30,.65),1/.65)-s.pixelsPainted);console.log(s.id),(s.id||0===s.id)&&console.log(r(s.id,"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")),this.Mt.K=s.id,t._("bm-e",`Username: ${function(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}(s.name)}`),t._("bm-b",`Droplets: ${(new Intl.NumberFormat).format(s.droplets)}`),t._("bm-6",`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))),c=new URLSearchParams(n.endpoint.split("?")[1]),l=[c.get("x"),c.get("y")];if(this.Dt.length&&(!i.length||!l.length))return void t.A("Coordinates are malformed!\nDid you try clicking the canvas first?");this.Dt=[...i,...l];const h=(o=i,a=l,[parseInt(o[0])%4*1e3+parseInt(a[0]),parseInt(o[1])%4*1e3+parseInt(a[1])]),u=document.querySelectorAll("span");for(const t of u)if(t.textContent.trim().includes(`${h[0]}, ${h[1]}`)){let e=document.querySelector("#bm-5");const n=`(Tl X: ${i[0]}, Tl Y: ${i[1]}, Px X: ${l[0]}, Px Y: ${l[1]})`;e?e.textContent=n:(e=document.createElement("span"),e.id="bm-5",e.textContent=n,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"tiles":let d=n.endpoint.split("/");d=[parseInt(d[d.length-2]),parseInt(d[d.length-1].replace(".png",""))];const m=n.blobID,p=n.blobData,b=await this.Mt.yt(p,d);window.postMessage({source:"blue-marble",blobID:m,blobData:b,blink:n.blink});break;case"robots":this.St="false"==s.userscript?.toString().toLowerCase();break}var o,a})}}(m);d.I(p),d.O({id:"bm-k",style:"top: 10px; right: 75px;"}).O({id:"bm-7"}).O({id:"bm-f"}).N().H({alt:"Blue Marble Icon",src:"https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png"}).N().R(1,{textContent:c}).N().N().Y().N().O({id:"bm-4"}).L({id:"bm-e",textContent:"Username:"}).N().L({id:"bm-b",textContent:"Droplets:"}).N().L({id:"bm-6",textContent:"Next level in..."}).N().N().Y().N().O({id:"bm-3"}).O({id:"bm-8"}).j({id:"bm-c",className:"bm-o",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.T?.Dt;e?.[0]?(t._("bm-g",e?.[0]||""),t._("bm-h",e?.[1]||""),t._("bm-i",e?.[2]||""),t._("bm-j",e?.[3]||"")):t.A("Coordinates are malformed! Did you try clicking on the canvas first?")}}).N().F({type:"number",id:"bm-g",placeholder:"Tl X",min:0,max:2047,step:1,required:!0}).N().F({type:"number",id:"bm-h",placeholder:"Tl Y",min:0,max:2047,step:1,required:!0}).N().F({type:"number",id:"bm-i",placeholder:"Px X",min:0,max:2047,step:1,required:!0}).N().F({type:"number",id:"bm-j",placeholder:"Px Y",min:0,max:2047,step:1,required:!0}).N().N().J({id:"bm-2",textContent:"Upload Template",accept:"image/png, image/jpeg, image/webp, image/bmp, image/gif"}).N().O({id:"bm-0"}).j({id:"bm-d",textContent:"Enable"},(t,e)=>{e.onclick=()=>{const e=document.querySelector("#bm-2"),n=document.querySelector("#bm-g");if(!n.checkValidity())return n.reportValidity(),void t.A("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-h");if(!s.checkValidity())return s.reportValidity(),void t.A("Coordinates are malformed! Did you try clicking on the canvas first?");const i=document.querySelector("#bm-i");if(!i.checkValidity())return i.reportValidity(),void t.A("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-j");if(!o.checkValidity())return o.reportValidity(),void t.A("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(m.$t(e.files[0],e.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(n.value),Number(s.value),Number(i.value),Number(o.value)]),t.U("Drew to canvas!")):t.A("No file selected!")}}).N().N().V({id:d.k,placeholder:`Status: Sleeping...\nVersion: ${l}`,readOnly:!0}).N().O({id:"bm-1"}).O().j({id:"bm-9",className:"bm-o",innerHTML:"🎨",title:"Template Color Converter"},(t,e)=>{e.addEventListener("click",()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")})}).N().N().P({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).N().N().N().B(document.body),d.W("#bm-k","#bm-f"),p.Tt(d),new MutationObserver((t,e)=>{const n=document.querySelector("#color-1");if(!n)return;let s=document.querySelector("#bm-F");s||(s=document.createElement("button"),s.id="bm-F",s.textContent="Move ↑",s.className="btn btn-soft",s.onclick=function(){const t=this.parentNode.parentNode.parentNode.parentNode,e="Move ↑"==this.textContent;t.parentNode.className=t.parentNode.className.replace(e?"bottom":"top",e?"top":"bottom"),t.style.borderTopLeftRadius=e?"0px":"var(--radius-box)",t.style.borderTopRightRadius=e?"0px":"var(--radius-box)",t.style.borderBottomLeftRadius=e?"var(--radius-box)":"0px",t.style.borderBottomRightRadius=e?"var(--radius-box)":"0px",this.textContent=e?"Move ↓":"Move ↑"},n.parentNode.parentNode.parentNode.parentNode.querySelector("h2").parentNode.appendChild(s))}).observe(document.body,{childList:!0,subtree:!0}),function(...t){(0,console.log)(...t)}(`%c${c}%c (${l}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 28a93bf..6b3ecda 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 4a8b56b..cc6ed45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wplace-bluemarble", - "version": "0.66.2", + "version": "0.66.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wplace-bluemarble", - "version": "0.66.2", + "version": "0.66.4", "devDependencies": { "esbuild": "^0.25.0", "terser": "^5.43.1" diff --git a/package.json b/package.json index 18c7a54..4956fc3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wplace-bluemarble", - "version": "0.66.2", + "version": "0.66.4", "type": "module", "scripts": { "build": "node build/build.js", diff --git a/src/BlueMarble.meta.js b/src/BlueMarble.meta.js index a52b94e..db26f4c 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.66.2 +// @version 0.66.4 // @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/main.js b/src/main.js index 8a6fe34..36156f9 100644 --- a/src/main.js +++ b/src/main.js @@ -62,7 +62,7 @@ inject(() => { consoleWarn(`%c${name}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`, consoleStyle, '', blobID); } - + fetchedBlobQueue.delete(blobID); // Delete the blob from the queue, because we don't need to process it again } }); @@ -186,8 +186,49 @@ overlay.handleDrag('#bm-overlay', '#bm-bar-drag'); // Creates dragging capabilit apiManager.spontaneousResponseListener(overlay); // Reads spontaneous fetch responces +observeBlack(); // Observes the black palette color + consoleLog(`%c${name}%c (${version}) userscript has loaded!`, 'color: cornflowerblue;', ''); +/** Observe the black color, and add the "Move" button. + * @since 0.66.3 + */ +function observeBlack() { + const observer = new MutationObserver((mutations, observer) => { + + const black = document.querySelector('#color-1'); // Attempt to retrieve the black color element for anchoring + + if (!black) {return;} // Black color does not exist yet. Kills iteself + + let move = document.querySelector('#bm-button-move'); // Tries to find the move button + + // If the move button does not exist, we make a new one + if (!move) { + move = document.createElement('button'); + move.id = 'bm-button-move'; + move.textContent = 'Move ↑'; + move.className = 'btn btn-soft'; + move.onclick = function() { + const roundedBox = this.parentNode.parentNode.parentNode.parentNode; // Obtains the rounded box + const shouldMoveUp = (this.textContent == 'Move ↑'); + roundedBox.parentNode.className = roundedBox.parentNode.className.replace(shouldMoveUp ? 'bottom' : 'top', shouldMoveUp ? 'top' : 'bottom'); // Moves the rounded box to the top + roundedBox.style.borderTopLeftRadius = shouldMoveUp ? '0px' : 'var(--radius-box)'; + roundedBox.style.borderTopRightRadius = shouldMoveUp ? '0px' : 'var(--radius-box)'; + roundedBox.style.borderBottomLeftRadius = shouldMoveUp ? 'var(--radius-box)' : '0px'; + roundedBox.style.borderBottomRightRadius = shouldMoveUp ? 'var(--radius-box)' : '0px'; + this.textContent = shouldMoveUp ? 'Move ↓' : 'Move ↑'; + } + + // Attempts to find the "Paint Pixel" element for anchoring + const paintPixel = black.parentNode.parentNode.parentNode.parentNode.querySelector('h2'); + + paintPixel.parentNode.appendChild(move); // Adds the move button + } + }); + + observer.observe(document.body, { childList: true, subtree: true }); +} + /** Deploys the overlay to the page. * Parent/child relationships in the DOM structure below are indicated by indentation. * @since 0.58.3