diff --git a/dist/BlueMarble.user.js b/dist/BlueMarble.user.js index 4f3eecf..26d9ecf 100644 --- a/dist/BlueMarble.user.js +++ b/dist/BlueMarble.user.js @@ -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)},i=(t,e,i)=>e.has(t)?n("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,i),s=(t,e,i)=>(((t,e)=>{e.has(t)||n("Cannot access private method")})(t,e),i);t=new WeakSet,e=function(t,e={},n={}){const i=document.createElement(t);this.t?(this.i.appendChild(i),this.o.push(this.i),this.i=i):(this.t=i,this.i=i);for(const[t,n]of Object.entries(e))i[t]=n;for(const[t,e]of Object.entries(n))i[t]=e;return i};var o,a=class{constructor({displayName:t="My template",h:e=0,l:n="",url:i="",file:s=null,coords:o=null,u:a=null,m:r=1e3}={}){this.displayName=t,this.h=e,this.l=n,this.url=i,this.file=s,this.coords=o,this.u=a,this.m=r}async p(){const t=await createImageBitmap(this.file),e=t.width,n=t.height,i={},s=new OffscreenCanvas(this.m,this.m),o=s.getContext("2d",{v:!0});for(let a=this.coords[3];a0;)n=e[t%i]+n,t=Math.floor(t/i);return n}o=new WeakSet;var c=GM_info.script.name.toString(),h=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-o",c),e.setAttribute("bm-m","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-o")||"Blue Marble",n=t?.getAttribute("bm-m")||"",i=new Map;window.addEventListener("message",t=>{const{source:s,endpoint:o,blobID:a,blobData:r,blink:c}=t.data;if(Date.now(),"blue-marble"==s&&a&&r&&!o){const t=i.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),i.delete(a)}});const s=window.fetch;window.fetch=async function(...t){const e=await s.apply(this,t),n=e.clone(),o=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore",a=n.headers.get("content-type")||"";if(a.includes("application/json"))n.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:o,jsonData:t},"*")}).catch(t=>{});else if(a.includes("image/")&&!o.includes("openfreemap")){const t=Date.now(),e=await n.blob();return new Promise(s=>{const a=crypto.randomUUID();i.set(a,t=>{s(new Response(t,{headers:n.headers,status:n.status,statusText:n.statusText}))}),window.postMessage({source:"blue-marble",endpoint:o,blobID:a,blobData:e,blink:t})}).catch(t=>{Date.now()})}return e}});var l=GM_getResourceText("CSS-BM-File");GM_addStyle(l);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.M=null,this.$=null,this.D="#bm-5"}C(t){return this.$=t,this.M=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.D)}),this}T(){return this.M}observe(t,e=!1,n=!1){t.observe(this.$,{childList:e,subtree:n})}};var d=new class{constructor(e,n){i(this,t),this.name=e,this.version=n,this.I=null,this.k="bm-a",this.t=null,this.i=null,this.o=[]}N(t){this.I=t}S(){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={},i=()=>{}){return i(this,s(this,t,e).call(this,"div",{},n)),this}L(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"p",{},n)),this}H(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"small",{},n)),this}q(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"img",{},n)),this}P(n,i={},o=()=>{}){return o(this,s(this,t,e).call(this,"h"+n,{},i)),this}R(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"hr",{},n)),this}_(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"br",{},n)),this}j(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.S(),i(this,o,a),this}V(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"button",{},n)),this}Y(n={},i=()=>{}){const o=n.title??n.textContent??"Help: No info";delete n.textContent,n.title=`Help: ${o}`;const a={textContent:"?",className:"bm-p",onclick:()=>{this.F(this.k,o)}};return i(this,s(this,t,e).call(this,"button",a,n)),this}G(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"input",{},n)),this}U(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.S();const c=s(this,t,e).call(this,"button",{textContent:o});return this.S(),this.S(),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}W(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"textarea",{},n)),this}F(t,e,n=!1){const i=document.getElementById(t.replace(/^#/,""));i&&(i instanceof HTMLInputElement?i.value=e:n?i.textContent=e:i.innerHTML=e)}X(t,e){let n,i=!1,s=0;t=document.querySelector("#"==t?.[0]?t:"#"+t),e=document.querySelector("#"==e?.[0]?e:"#"+e),t&&e?(e.addEventListener("mousedown",function(o){i=!0,n=o.clientX-t.getBoundingClientRect().left,s=o.clientY-t.getBoundingClientRect().top,document.body.style.userSelect="none",e.classList.add("dragging")}),e.addEventListener("touchstart",function(o){i=!0;const a=o?.touches?.[0];a&&(n=a.clientX-t.getBoundingClientRect().left,s=a.clientY-t.getBoundingClientRect().top,document.body.style.userSelect="none",e.classList.add("dragging"))},{passive:!1}),document.addEventListener("mousemove",function(e){i&&(t.style.left=e.clientX-n+"px",t.style.top=e.clientY-s+"px",t.style.right="")}),document.addEventListener("touchmove",function(e){if(i){const i=e?.touches?.[0];if(!i)return;t.style.left=i.clientX-n+"px",t.style.top=i.clientY-s+"px",e.preventDefault()}},{passive:!1}),document.addEventListener("mouseup",function(){i=!1,document.body.style.userSelect="",e.classList.remove("dragging")}),document.addEventListener("touchend",function(){i=!1,document.body.style.userSelect="",e.classList.remove("dragging")}),document.addEventListener("touchcancel",function(){i=!1,document.body.style.userSelect="",e.classList.remove("dragging")})):this.A(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`)}J(t){(0,console.info)(`${this.name}: ${t}`),this.F(this.k,"Status: "+t,!0)}A(t){(0,console.error)(`${this.name}: ${t}`),this.F(this.k,"Error: "+t,!0)}}(c,h),m=new class{constructor(t,e,n){i(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.it=null,this.st="bm-n",this.ot="div#map canvas.maplibregl-canvas",this.rt=null,this.ct="",this.ht=[],this.lt=null}ut(){if(document.body.contains(this.nt))return this.nt;document.getElementById(this.st)?.remove();const t=document.querySelector(this.ot),e=document.createElement("canvas");return e.id=this.st,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 wt(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.Z,templates:{}}}async gt(t,e,n){this.lt||(this.lt=await this.wt()),this.t.J(`Creating template at ${n.join(", ")}...`);const i=new a({displayName:e,h:0,l:r(this.K||0,this.tt),file:t,coords:n});i.u=await i.p(this.m),this.lt.templates[`${i.h} ${i.l}`]={name:i.displayName,enabled:!0,tiles:i.u},this.ht=[],this.ht.push(i),this.t.J(`Template created at ${n.join(", ")}!`)}vt(){}async yt(){this.lt||(this.lt=await this.wt())}async xt(t,e){const n=this.m*this.et;e=e[0].toString().padStart(4,"0")+","+e[1].toString().padStart(4,"0");const i=this.ht;i.sort((t,e)=>t.h-e.h);const s=i.map(t=>{const n=Object.keys(t.u).filter(t=>t.startsWith(e));if(0===n.length)return null;const i=n.map(e=>t.u[e]);return i?.[0]}).filter(Boolean);s.length>0&&this.t.J(`Displaying ${s.length} template${1==s.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 s)r.drawImage(t,0,0);return await a.convertToBlob({type:"image/png"})}Mt(){}}(c,h,d),p=new class{constructor(t){this.$t=t,this.Dt=!1,this.Ct=[],this.Tt=[]}It(t){window.addEventListener("message",async e=>{const n=e.data,i=n.jsonData;if(!n||"blue-marble"!==n.source)return;if(!n.endpoint)return;const s=n.endpoint?.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).filter(t=>t&&!t.includes(".")).pop();switch(s){case"me":if(i.status&&"2"!=i.status?.toString()[0])return void t.A("You are not logged in!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(i.level)*Math.pow(30,.65),1/.65)-i.pixelsPainted);i.id||i.id,this.$t.K=i.id,t.F("bm-f",`Username: ${function(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}(i.name)}`),t.F("bm-b",`Droplets: ${(new Intl.NumberFormat).format(i.droplets)}`),t.F("bm-6",`Next level in ${(new Intl.NumberFormat).format(e)} pixel${1==e?"":"s"}`);break;case"pixel":const s=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.Ct.length&&(!s.length||!c.length))return void t.A("Coordinates are malformed!\nDid you try clicking the canvas first?");this.Ct=[...s,...c];const h=(o=s,a=c,[parseInt(o[0])%4*1e3+parseInt(a[0]),parseInt(o[1])%4*1e3+parseInt(a[1])]),l=document.querySelectorAll("span");for(const t of l)if(t.textContent.trim().includes(`${h[0]}, ${h[1]}`)){let e=document.querySelector("#bm-5");const n=`(Tl X: ${s[0]}, Tl Y: ${s[1]}, Px X: ${c[0]}, Px Y: ${c[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 u=n.endpoint.split("/");u=[parseInt(u[u.length-2]),parseInt(u[u.length-1].replace(".png",""))];const d=n.blobID,m=n.blobData,p=await this.$t.xt(m,u);window.postMessage({source:"blue-marble",blobID:d,blobData:p,blink:n.blink});break;case"robots":this.Dt="false"==i.userscript?.toString().toLowerCase()}var o,a})}}(m);d.N(p),d.O({id:"bm-l",style:"top: 10px; right: 75px;"}).O({id:"bm-7"}).O({id:"bm-g"}).S().q({alt:"Blue Marble Icon",src:"https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png"}).S().P(1,{textContent:c}).S().S().R().S().O({id:"bm-4"}).L({id:"bm-f",textContent:"Username:"}).S().L({id:"bm-b",textContent:"Droplets:"}).S().L({id:"bm-6",textContent:"Next level in..."}).S().S().R().S().O({id:"bm-3"}).O({id:"bm-8"}).V({id:"bm-c",className:"bm-p",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.I?.Ct;e?.[0]?(t.F("bm-h",e?.[0]||""),t.F("bm-i",e?.[1]||""),t.F("bm-j",e?.[2]||""),t.F("bm-k",e?.[3]||"")):t.A("Coordinates are malformed! Did you try clicking on the canvas first?")}}).S().G({type:"number",id:"bm-h",placeholder:"Tl X",min:0,max:2047,step:1,required:!0}).S().G({type:"number",id:"bm-i",placeholder:"Tl Y",min:0,max:2047,step:1,required:!0}).S().G({type:"number",id:"bm-j",placeholder:"Px X",min:0,max:2047,step:1,required:!0}).S().G({type:"number",id:"bm-k",placeholder:"Px Y",min:0,max:2047,step:1,required:!0}).S().S().U({id:"bm-2",textContent:"Upload Template",accept:"image/png, image/jpeg, image/webp, image/bmp, image/gif"}).S().O({id:"bm-0"}).V({id:"bm-d",textContent:"Enable"},(t,e)=>{e.onclick=()=>{const e=document.querySelector("#bm-2"),n=document.querySelector("#bm-h");if(!n.checkValidity())return n.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 s=document.querySelector("#bm-j");if(!s.checkValidity())return s.reportValidity(),void t.A("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-k");if(!o.checkValidity())return o.reportValidity(),void t.A("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(m.gt(e.files[0],e.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(n.value),Number(i.value),Number(s.value),Number(o.value)]),t.J("Drew to canvas!")):t.A("No file selected!")}}).S().S().W({id:d.k,placeholder:`Status: Sleeping...\nVersion: ${h}`,readOnly:!0}).S().O({id:"bm-1"}).O().V({id:"bm-9",className:"bm-p",innerHTML:"🎨",title:"Template Color Converter"},(t,e)=>{e.addEventListener("click",()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")})}).S().S().H({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).S().S().S().B(document.body),d.X("#bm-l","#bm-g"),p.It(d),new MutationObserver((t,e)=>{const n=document.querySelector("#color-1");if(!n)return;let i=document.querySelector("#bm-e");i||(i=document.createElement("button"),i.id="bm-e",i.textContent="Move ↑",i.className="btn btn-soft",i.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(i))}).observe(document.body,{childList:!0,subtree:!0}),function(...t){(0,console.log)(...t)}(`%c${c}%c (${h}) 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-o",c),e.setAttribute("bm-m","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-o")||"Blue Marble",n=t?.getAttribute("bm-m")||"",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-p",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-n",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 wt(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)}$t(){}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,0,0);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-f",`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-l",style:"top: 10px; right: 75px;"}).O({id:"bm-7"}).O({id:"bm-g"}).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-f",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-p",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.T?.Dt;e?.[0]?(t._("bm-h",e?.[0]||""),t._("bm-i",e?.[1]||""),t._("bm-j",e?.[2]||""),t._("bm-k",e?.[3]||"")):t.A("Coordinates are malformed! Did you try clicking on the canvas first?")}}).N().F({type:"number",id:"bm-h",placeholder:"Tl X",min:0,max:2047,step:1,required:!0}).N().F({type:"number",id:"bm-i",placeholder:"Tl Y",min:0,max:2047,step:1,required:!0}).N().F({type:"number",id:"bm-j",placeholder:"Px X",min:0,max:2047,step:1,required:!0}).N().F({type:"number",id:"bm-k",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-h");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-i");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-j");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-k");if(!o.checkValidity())return o.reportValidity(),void t.A("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(m.wt(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-p",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-l","#bm-g"),p.Tt(d),new MutationObserver((t,e)=>{const n=document.querySelector("#color-1");if(!n)return;let s=document.querySelector("#bm-e");s||(s=document.createElement("button"),s.id="bm-e",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/package-lock.json b/package-lock.json index 1a07496..aefe7b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wplace-bluemarble", - "version": "0.66.16", + "version": "0.67.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wplace-bluemarble", - "version": "0.66.16", + "version": "0.67.0", "devDependencies": { "esbuild": "^0.25.0", "terser": "^5.43.1" diff --git a/src/Template.js b/src/Template.js index 5c663d9..d73f83e 100644 --- a/src/Template.js +++ b/src/Template.js @@ -3,7 +3,6 @@ * @since 0.65.2 */ export default class Template { - /** The constructor for the {@link Template} class. * @param {Object} [params={}] - Object containing all optional params * @param {string} [params.displayName='My template'] - The display name of the template @@ -24,7 +23,7 @@ export default class Template { file = null, coords = null, chunked = null, - tileSize = 1000 + tileSize = 1000, } = {}) { this.displayName = displayName; this.sortID = sortID; @@ -41,7 +40,6 @@ export default class Template { * @since 0.65.4 */ async createTemplateTiles() { - console.log(this.coords); const shreadSize = 3; // Scale image factor. Must be odd @@ -55,42 +53,77 @@ export default class Template { const context = canvas.getContext('2d', { willReadFrequently: true }); // For every tile... - for (let pixelY = this.coords[3]; pixelY < (imageHeight + this.coords[3]);) { - + for (let pixelY = this.coords[3]; pixelY < imageHeight + this.coords[3]; ) { // Draws the partial tile first, if any // This calculates the size based on which is smaller: // A. The top left corner of the current tile to the bottom right corner of the current tile // B. The top left corner of the current tile to the bottom right corner of the image - const drawSizeY = Math.min(this.tileSize - (pixelY % this.tileSize), imageHeight - ((pixelY - this.coords[3]) * (pixelY != this.coords[3]))); - console.log(`Math.min(${this.tileSize} - (${pixelY} % ${this.tileSize}), ${imageHeight} - (${pixelY - this.coords[3]} * (${pixelY} != ${this.coords[3]})))`); + const drawSizeY = Math.min( + this.tileSize - (pixelY % this.tileSize), + imageHeight - (pixelY - this.coords[3]) + ); + console.log( + `Math.min(${this.tileSize} - (${pixelY} % ${ + this.tileSize + }), ${imageHeight} - (${pixelY - this.coords[3]}))` + ); - for (let pixelX = this.coords[2]; pixelX < (imageWidth + this.coords[2]);) { + for ( + let pixelX = this.coords[2]; + pixelX < imageWidth + this.coords[2]; + + ) { console.log(`Pixel X: ${pixelX}\nPixel Y: ${pixelY}`); // Draws the partial tile first, if any // This calculates the size based on which is smaller: // A. The top left corner of the current tile to the bottom right corner of the current tile // B. The top left corner of the current tile to the bottom right corner of the image - const drawSizeX = Math.min(this.tileSize - (pixelX % this.tileSize), imageWidth - ((pixelX - this.coords[2]) * (pixelX != this.coords[2]))); - console.log(`Math.min(${this.tileSize} - (${pixelX} % ${this.tileSize}), ${imageWidth} - (${pixelX} * (${pixelX} != ${this.coords[2]})))`); + const drawSizeX = Math.min( + this.tileSize - (pixelX % this.tileSize), + imageWidth - (pixelX - this.coords[2]) + ); + console.log( + `Math.min(${this.tileSize} - (${pixelX} % ${ + this.tileSize + }), ${imageWidth} - (${pixelX - this.coords[2]}))` + ); console.log(`Draw Size X: ${drawSizeX}\nDraw Size Y: ${drawSizeY}`); // Change the canvas size and wipe the canvas - const canvasWidth = (drawSizeX * shreadSize) + ((pixelX % this.tileSize) * shreadSize); - const canvasHeight = (drawSizeY * shreadSize) + ((pixelY % this.tileSize) * shreadSize); + const canvasWidth = + drawSizeX * shreadSize + (pixelX % this.tileSize) * shreadSize; + const canvasHeight = + drawSizeY * shreadSize + (pixelY % this.tileSize) * shreadSize; canvas.width = canvasWidth; canvas.height = canvasHeight; - console.log(`Draw X: ${drawSizeX}\nDraw Y: ${drawSizeY}\nCanvas Width: ${canvasWidth}\nCanvas Height: ${canvasHeight}`); + console.log( + `Draw X: ${drawSizeX}\nDraw Y: ${drawSizeY}\nCanvas Width: ${canvasWidth}\nCanvas Height: ${canvasHeight}` + ); context.imageSmoothingEnabled = false; // Nearest neighbor - console.log(`Getting X ${pixelX}-${pixelX + drawSizeX}\nGetting Y ${pixelY}-${pixelY + drawSizeY}`); + console.log( + `Getting X ${pixelX}-${pixelX + drawSizeX}\nGetting Y ${pixelY}-${ + pixelY + drawSizeY + }` + ); // Draws the template segment on this tile segment context.clearRect(0, 0, canvasWidth, canvasHeight); // Clear any previous drawing (only runs when canvas size does not change) - context.drawImage(bitmap, pixelX - this.coords[2], pixelY - this.coords[3], drawSizeX, drawSizeY, (pixelX % this.tileSize) * shreadSize, (pixelY % this.tileSize) * shreadSize, drawSizeX * shreadSize, drawSizeY * shreadSize); // Coordinates and size of draw area of source image, then canvas + context.drawImage( + bitmap, + pixelX - this.coords[2], + pixelY - this.coords[3], + drawSizeX, + drawSizeY, + (pixelX % this.tileSize) * shreadSize, + (pixelY % this.tileSize) * shreadSize, + drawSizeX * shreadSize, + drawSizeY * shreadSize + ); // Coordinates and size of draw area of source image, then canvas // const final = await canvas.convertToBlob({ type: 'image/png' }); // const url = URL.createObjectURL(final); // Creates a blob URL @@ -104,7 +137,7 @@ export default class Template { // For every pixel... // ... Make it transparent unless it is the "center" - if ((x % shreadSize !== 1) || (y % shreadSize !== 1)) { + if (x % shreadSize !== 1 || y % shreadSize !== 1) { const pixelIndex = (y * canvasWidth + x) * 4; // Find the pixel index in an array where every 4 indexes are 1 pixel imageData.data[pixelIndex + 3] = 0; // Make the pixel transparent on the alpha channel } @@ -115,7 +148,15 @@ export default class Template { context.putImageData(imageData, 0, 0); //templateTiles[`${(this.coords[0] + Math.floor(pixelX / 1000)).toString().padStart(4, '0')},${(this.coords[1] + Math.floor(pixelY / 1000)).toString().padStart(4, '0')},${(pixelX % 1000).toString().padStart(3, '0')},${(pixelY % 1000).toString().padStart(3, '0')}`] = await canvas.convertToBlob({ type: 'image/png' }); - templateTiles[`${(this.coords[0] + Math.floor(pixelX / 1000)).toString().padStart(4, '0')},${(this.coords[1] + Math.floor(pixelY / 1000)).toString().padStart(4, '0')},${(pixelX % 1000).toString().padStart(3, '0')},${(pixelY % 1000).toString().padStart(3, '0')}`] = await createImageBitmap(canvas); + templateTiles[ + `${(this.coords[0] + Math.floor(pixelX / 1000)) + .toString() + .padStart(4, '0')},${(this.coords[1] + Math.floor(pixelY / 1000)) + .toString() + .padStart(4, '0')},${(pixelX % 1000) + .toString() + .padStart(3, '0')},${(pixelY % 1000).toString().padStart(3, '0')}` + ] = await createImageBitmap(canvas); console.log(templateTiles); @@ -133,4 +174,4 @@ export default class Template { console.log('Template Tiles: ', templateTiles); return templateTiles; } -} \ No newline at end of file +}