@onceworlds/cli 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/cli.js +92 -19
- package/dist/emulator.js +211 -150
- package/dist/sdk.js +3 -3
- package/package.json +1 -1
package/dist/emulator.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
"use strict";(()=>{var Te=["#f6dcc5","#ebc29f","#d4a07a","#b07a55","#875839","#5e3d29","#93c9bb","#a8c595","#94bcd3","#ab9bd9","#dca3ad","#b3bccb"],ce=["#c95f56","#dc8a4f","#e2bd52","#9cc27a","#5a8a5e","#4f9a8e","#6fb7c8","#5b87c5","#465089","#8b68a8","#dc8fae","#f2eee6","#a9a8ad","#5d5c63","#2b2a30","#80604d"],De=["Happy","Grin","Shades","Wink","Surprised","Determined","Joyful","Shy"],Oe=["None","Sprout","Cap","Beanie","Crown","Headphones","Horns","Antenna","Bow","Halo","Party hat","Cat ears","Short hair","Tuft","Bob","Spikes","Bun","Curls","Long","Mop"];var _e=["Plain","Band","Spots","Stripes","Star"];var wo={skin:Te.length,shirt:ce.length,pants:ce.length,face:De.length,hat:Oe.length,top:_e.length},jt=[[5,6],[3,4],[6,7],[9,8],[10,0],[12,13]];function je(t){let e=2166136261;for(let h of t)e=Math.imul(e^h.charCodeAt(0),16777619)>>>0;let o=h=>(e=Math.imul(e^e>>>13,2654435761)>>>0,e%h),r=o(Te.length),n=r>=6?jt[r-6][o(2)]:o(ce.length),a=o(2)===0?n:[8,13,14,15][o(4)],i=o(5)===0?1:12+o(Oe.length-12),s=o(2)===0?0:o(_e.length);return{skin:r,shirt:n,pants:a,face:o(De.length),hat:i,top:s}}var S={roomMaxPlayersDefault:16,roomMaxPlayersCap:30,teamsMax:8,messageBytes:16*1024,presenceBytes:1024,stateKeyLength:64,stateValueBytes:16*1024,stateKeys:256,privateKeys:16,privateValueBytes:4*1024,privateBytesPerPlayer:8*1024,messagesPerSecond:60,messagesPerSecondMin:10,roomBytesPerSecond:128*1024,roomBytesPerSecondMin:16*1024,presenceHz:20,presenceHzMin:5,roomMessagesPerSecond:900,roomBytesPerSecondTotal:2*1024*1024,matchCountdownMs:3e3,matchCountdownMaxMs:1e4,matchIdleMs:45e3,matchAbandonMs:12e4,idleAfterMs:3e4,idleAbandonMs:5*6e4,rankedPairMatchesPerDay:5,chatLength:200,chatIntervalMs:750,chatHistory:50,chatChannelsPerPlayer:10,saveValueBytes:64*1024,saveKeysPerGame:100,saveBytesPerGame:1024*1024,guestSaveBytesPerGame:128*1024,serverDataKeys:128,serverDataBytes:512*1024,serverDataServersPerGame:5e3,serverDataBytesPerGame:64*1024*1024,serverDataIdleDays:120,gameDataKeys:32,gameDataListMax:100,gameDataItemBytes:1024,gameDataValueBytes:8*1024,gameDataMapFields:1e3,gameDataMapPerPlayer:100,gameDataNumberMax:1e15,gameDataWritesPerMinute:30,deployFiles:2e3,deployFileBytes:25*1024*1024,deployHtmlBytes:10*1024*1024,deployPathLength:200,deployTotalBytes:100*1024*1024,envVars:50,envValueBytes:4*1024,envTotalBytes:16*1024,proxyRequestBytes:1024*1024,proxyTextRequestBytes:256*1024,proxySpeechRequestBytes:16*1024,proxyResponseBytes:10*1024*1024,proxyMaxOutputTokens:4096,proxyCallsPerDay:2e3,proxyCallsPerDayMax:1e5,proxyCallsPerPlayerPerDay:100,proxyCallsPerNetworkPerDay:1e3,proxyMediaCallsPerDay:100,proxyMediaCallsPerDayMax:1e4,proxyMediaCallsPerPlayerPerDay:20,proxyMediaCallsPerNetworkPerDay:25,proxyUnitsPerDay:2e6,proxyUnitsPerDayMax:1e8,proxyUnitsPerPlayerPerDay:25e4,proxyUnitsPerGuestPerDay:1e5,proxyUnitsPerNetworkPerDay:5e5,errorReportsPerPage:10,consoleLineLength:2e3,consoleLinesPerSecond:50,gameNameLength:60,gameDescriptionLength:1e3,galleryItems:5,mediaImageBytes:5*1024*1024,mediaVideoBytes:30*1024*1024,mediaGifBytes:1024*1024,mediaGifSide:512,mediaUploadsPerDay:200,mediaBytesPerDay:500*1024*1024,badgesPerGame:50,controlHints:12,controlHintKeys:4,controlKeyLength:12,controlActionLength:40,helpLength:400,badgeNameLength:50,badgeDescriptionLength:200,leaderboardsPerGame:25,leaderboardTop:100,gamesPerOwner:50,gamesCreatedPerCreatorPerDay:3,uploadAccountAgeMs:10080*6e4,deploysPerOwnerPerDay:100,draftsPerOwnerPerDay:1e3,draftsKeptPerGame:3,cliTokensPerAccount:10,cliDeviceCodeSeconds:600,deploymentsKeptPerGame:10,deployBytesPerOwnerPerDay:2*1024*1024*1024,deployEntriesPerOwnerPerDay:1e5,bioLength:500,exportRows:2e3,exportSaveChars:4*1024*1024,exportEveryMs:60*6e4,friendsMax:200,friendRequestsMax:100,friendRequestsIncomingMax:50,friendRequestsPerDay:20,friendRequestsPerNetworkPerDay:120,friendRequestPushesPerDay:5,passwordMinLength:8,passwordMaxLength:72,signupsPerNetworkPerDay:100,signupsPerWidePerDay:300,guestsPerNetworkPerDay:300,guestsPerWidePerDay:1500,visitsPerNetworkPerDay:10,visitSeconds:10,errorsPerDeployment:100,controlButtons:4,controlLabelLength:12,partySize:6,partyChatHistory:50,messageLength:500,messagesPerPage:50,groupChatMembers:20,groupChatNameLength:40,conversationsListed:50,notificationsListed:50,invitesPerRequest:10,inviteLiveMs:30*6e4,partyInviteMs:60*6e4};var Be=/^[a-z0-9]{12}$/,V=2;function ge(t){return`${t.mode}.${t.max}.${t.teams}.${t.ranked?1:0}${t.min!==V?`.${t.min}`:""}`}var It=/^pub:([a-z0-9-]+)\.(\d+)\.(\d)\.([01])(?:\.(\d+))?:(\d+)$/;function Ne(t){let e=It.exec(t);if(!e)return null;let o={mode:e[1],max:Number(e[2]),teams:Number(e[3]),ranked:e[4]==="1",min:e[5]===void 0?V:Number(e[5])};return{...o,name:ge(o),n:Number(e[6])}}function Ge(t,e,o){let r=typeof t=="string"?Number(t):t;return typeof r!="number"||!Number.isInteger(r)?Math.min(o,e):Math.min(e,Math.max(1,r))}var Ie=t=>t.replace(/[\u0000-\u001f\u007f]/g," ").replace(/\s+/g," ").trim();var Bt=/^[a-z0-9][a-z0-9-]{0,19}$/;function Ue(t){if(!t||typeof t!="object")return null;let e=t,o=[];for(let n of Array.isArray(e.buttons)?e.buttons:[]){if(o.length>=S.controlButtons)break;let{id:a,label:i}=n??{};if(typeof a!="string"||!Bt.test(a)||o.some(h=>h.id===a))continue;let s=typeof i=="string"?i.replace(/[\u0000-\u001f\u007f]/g,"").replace(/\s+/g," ").trim().slice(0,S.controlLabelLength).trim():"";o.push({id:a,label:s||a})}let r=e.stick===!0;return r||o.length>0?{stick:r,zone:e.zone==="corner"?"corner":"wide",buttons:o}:null}var U="host:ow.settings",Nt=/^[a-z][a-zA-Z0-9]{0,15}$/;function He(t){if(!Array.isArray(t))return[];let e=[];for(let o of t){if(e.length>=6)break;let{id:r,label:n,options:a,default:i}=o??{};if(typeof r!="string"||!Nt.test(r)||e.some(g=>g.id===r)||!Array.isArray(a))continue;let s=[];for(let g of a){let l=typeof g=="object"&&g!==null?g.value:g;if(typeof l!="string"&&typeof l!="number"||typeof l=="number"&&!Number.isFinite(l)||s.length>=8||s.some(m=>m.value===l))continue;let y=typeof g=="object"&&g!==null&&typeof g.label=="string"?g.label:String(l);s.push({value:l,label:Ie(y).slice(0,20)||String(l)})}if(s.length<2)continue;let h=typeof n=="string"?Ie(n).slice(0,24):"";e.push({id:r,label:h||r,options:s,default:s.some(g=>g.value===i)?i:s[0].value})}return e}function Fe(t,e){let o=e!==null&&typeof e=="object"?e[t.id]:void 0;return t.options.some(r=>r.value===o)?o:t.default}var he='{"t":"ping"}';var qe=4001,Ke=4003,Ve=4008,We=4006;var Ye="onceworlds:hello",Je="onceworlds:connect",Gt=/^[a-z0-9]{1,32}~(?:(?:0|[1-9]\d{0,3})\.(?:0|[1-9]\d{0,4})\.(?:0|[1-9]\d{0,5}))?~[0-9a-z]{1,11}~[lp]~[A-Za-z0-9_-]{43}$/;function Xe(t){let e=t!==null&&typeof t=="object"?t.build:void 0;return typeof e=="string"&&Gt.test(e)?e:null}var Ze="onceworlds-console";var Qe="allow-scripts allow-pointer-lock allow-forms allow-orientation-lock",et=["autoplay","gamepad","screen-wake-lock","accelerometer","gyroscope"].map(t=>`${t} *`).join("; ");var tt=new Set(["server","join","deploy","watch","player","embed","k","console","tester","live","demo",Ze]);function ot(t){return t?.ownCountdown!==!0}var Ut=/^#(?:[0-9a-f]{3}){1,2}$/i,$={panel:"#111216",text:"#f7f7f8",accent:"#d33e00"},ue=4.5,me=3,W=["#4ade80","#15803d"];function nt(t){let e=[];if(t==null)return{look:null,notes:e};if(typeof t!="object")return{look:null,notes:["a look is { accent, panel, text } or null"]};let o=t,r=l=>{let y=o[l];return y==null?null:typeof y=="string"&&Ut.test(y)?at(y):(e.push(`${l} is not #rgb or #rrggbb`),null)},n=r("panel"),a=r("text"),i=r("accent");if(n||a){let l=E(a??$.text,n??$.panel);l<ue&&(e.push(`text on panel is ${l.toFixed(1)}:1, under ${ue}:1: the platform's are used`),n=a=null)}let s=n??$.panel,h=a??$.text;if(i){let l=E(i,s);l<me&&(e.push(`accent on panel is ${l.toFixed(1)}:1, under ${me}:1: the platform's is used`),i=null)}if(!i&&n&&E($.accent,n)<me&&(i=h),!n&&!a&&!i)return{look:null,notes:e};let g=i?Ht(i):null;return{look:{panel:n,text:a,muted:n||a?Ft(h,s):null,accent:i,accentHover:i?it(i,g==="#ffffff"?"#000000":"#ffffff",.14):null,onAccent:g,ok:n?E(W[0],n)>=E(W[1],n)?W[0]:W[1]:null},notes:e}}function at(t){let e=t.slice(1).toLowerCase();return`#${e.length===3?[...e].map(o=>o+o).join(""):e}`}function H(t){let e=at(t);return[parseInt(e.slice(1,3),16),parseInt(e.slice(3,5),16),parseInt(e.slice(5,7),16)]}function rt(t){let[e,o,r]=H(t).map(n=>{let a=n/255;return a<=.04045?a/12.92:((a+.055)/1.055)**2.4});return .2126*e+.7152*o+.0722*r}function E(t,e){let[o,r]=[rt(t),rt(e)].sort((n,a)=>a-n);return(o+.05)/(r+.05)}function Ht(t){return E(t,"#000000")>E(t,"#ffffff")?"#000000":"#ffffff"}function it(t,e,o){let[r,n]=[H(t),H(e)];return`#${r.map((a,i)=>Math.round(a+(n[i]-a)*o).toString(16).padStart(2,"0")).join("")}`}function Ft(t,e){for(let o=.3;o>.001;o-=.05){let r=it(t,e,o);if(E(r,e)>=ue)return r}return t}var Y=class{port=null;handlers;events;onConnect;solo;demo;onActivity;constructor(e,o,r,n,a={}){this.handlers=o,this.events=r,this.onConnect=n,this.solo=a.solo===!0,this.demo=a.demo===!0,this.onActivity=a.onActivity??null,window.addEventListener("message",i=>{i.source!==e.contentWindow||i.origin!=="null"||i.data?.type===Ye&&this.connect(i.source,Xe(i.data))})}activity(e,o){try{this.onActivity?.(e,o)}catch{}}emit(e,o){this.port?.postMessage({kind:"event",name:e,data:o})}connect(e,o){this.port?.close();let r=new MessageChannel,n=r.port1;this.port=n,n.onmessage=i=>this.receive(n,i.data);let a={type:Je,...this.solo?{solo:!0}:{},...this.demo?{demo:!0}:{}};e.postMessage(a,"*",[r.port2]),this.onConnect(o)}async receive(e,o){if(!(e!==this.port||!o||typeof o!="object")){if(o.kind==="event"){Object.hasOwn(this.events,o.name)&&(this.events[o.name](o.data),this.activity(String(o.name),null));return}if(o.kind==="req")try{if(!Object.hasOwn(this.handlers,o.method))throw new Error(`Unknown method: ${String(o.method)}`);let r=this.handlers[o.method],n=await r(o.params);e.postMessage({kind:"res",id:o.id,ok:!0,result:n??null}),this.activity(String(o.method),null)}catch(r){let n=r instanceof Error?r.message:String(r);e.postMessage({kind:"res",id:o.id,ok:!1,error:n}),this.activity(String(o.method),n)}}}};var J=class{pressed=new Set;press(e){this.pressed.add(e)}take(e){let o=new Set(e),r=!1;for(let n of this.pressed)o.has(n)||(o.add(n),r=!0);return this.pressed.clear(),{buttons:[...o],owed:r}}};var st=["--ow-panel","--ow-face-edge","--ow-hover","--ow-on-accent","--text","--muted","--line","--line-strong","--fill","--fill-strong","--ok","--accent-fill","--accent-fill-hover","--accent-hover"],lt=["--ow-ctl-edge","--ow-ctl-fill","--ow-ctl-stick","--ow-ctl-knob","--ow-ctl-label","--ow-ctl-shadow","--ow-ctl-held","--ow-ctl-main","--ow-ctl-main-edge","--ow-ctl-main-label","--ow-ctl-main-shadow","--ow-ctl-main-held"];function x(t,e){return`rgba(${H(t).join(", ")}, ${e})`}function pt(t){let e={};if(!t)return e;if(t.panel&&(e["--ow-panel"]=t.panel,e["--ow-face-edge"]=t.panel),t.ok&&(e["--ok"]=t.ok),t.panel||t.text){let o=t.text??$.text;t.text&&(e["--text"]=t.text),t.muted&&(e["--muted"]=t.muted),e["--line"]=x(o,.09),e["--line-strong"]=x(o,.16),e["--fill"]=x(o,.06),e["--fill-strong"]=x(o,.1),e["--ow-hover"]=x(o,.16)}return t.accent&&t.accentHover&&t.onAccent&&(e["--accent-fill"]=t.accent,e["--accent-fill-hover"]=t.accentHover,e["--accent-hover"]=t.accent,e["--ow-on-accent"]=t.onAccent),e}function dt(t){let e={};return t&&(t.text&&(e["--ow-ctl-edge"]=x(t.text,.4),e["--ow-ctl-knob"]=x(t.text,.9),e["--ow-ctl-label"]=t.text,e["--ow-ctl-held"]=x(t.text,.35)),t.panel&&(e["--ow-ctl-fill"]=x(t.panel,.4),e["--ow-ctl-stick"]=x(t.panel,.3),e["--ow-ctl-shadow"]=x(t.panel,.5)),t.accent&&t.accentHover&&t.onAccent&&(e["--ow-ctl-main"]=x(t.accent,.85),e["--ow-ctl-main-edge"]=t.accent,e["--ow-ctl-main-label"]=t.onAccent,e["--ow-ctl-main-shadow"]="none",e["--ow-ctl-main-held"]=t.accentHover)),e}function X(t,e,o){for(let r of e)Object.hasOwn(o,r)?t.style.setProperty(r,o[r]):t.style.removeProperty(r);t.toggleAttribute("data-look",e.some(r=>Object.hasOwn(o,r)))}var M=52,xe=.12,fe=96,qt=400,Kt=2e4,Z=class{parent;root;zone;base;knob;buttonBox;send;onLayout;layout=null;touch;blocked=!1;keyboard=!1;stickPointer=null;center={x:0,y:0};x=0;y=0;buttons=new Map;held=new Map;fingers=new Map;report=new J;queued=0;sent="";placed={stick:null,buttons:null};constructor(e,o,r=()=>{}){this.send=o,this.onLayout=r,this.parent=e,this.touch=matchMedia("(pointer: coarse)").matches,this.root=L("div","ow-controls"),this.root.hidden=!0,this.zone=L("div","ow-stick-zone"),this.base=L("div","ow-stick"),this.knob=L("div","ow-stick-knob"),this.base.append(this.knob),this.zone.append(this.base),this.buttonBox=L("div","ow-control-buttons"),this.root.append(this.zone,this.buttonBox),e.append(this.root),this.zone.addEventListener("pointerdown",n=>this.stickDown(n)),this.zone.addEventListener("pointermove",n=>this.stickMove(n));for(let n of["pointerup","pointercancel","lostpointercapture"])this.zone.addEventListener(n,a=>this.stickUp(a));this.root.addEventListener("contextmenu",n=>n.preventDefault())}setLayout(e){this.layout=Ue(e);let o=this.buttons;this.buttons=new Map,(this.layout?.buttons??[]).forEach((r,n)=>{let a=o.get(r.id)??this.button(r.id);o.delete(r.id),a.className=`ow-control-btn ow-control-btn-${n}`,a.classList.toggle("ow-held",[...this.held.values()].includes(r.id)),a.textContent=r.label,a.isConnected||this.buttonBox.append(a),this.buttons.set(r.id,a)});for(let[r,n]of o){for(let[a,i]of this.held)i===r&&this.letGo(a);n.remove()}this.zone.hidden=!this.layout?.stick,this.zone.classList.toggle("ow-stick-corner",this.layout?.zone==="corner"),this.zone.hidden&&this.stickPointer!==null&&this.letGo(this.stickPointer),this.render(),this.onLayout()}setLook(e){X(this.root,lt,e)}reservedBoxes(){if(this.root.hidden)return this.blocked&&this.layout&&this.touch&&!this.keyboard?this.placed:{stick:null,buttons:null};let e=this.zone.hidden?null:gt(this.base),o=null;for(let r of this.buttons.values()){let n=gt(r);!n.width||!n.height||(o=o?Wt(o,n):n)}return this.placed={stick:e,buttons:o},this.placed}setTouch(e){this.touch=e,this.render()}setKeyboard(e){this.keyboard=e,this.render()}setBlocked(e){this.blocked=e,this.render()}render(){let e=!!this.layout&&this.touch&&!this.blocked&&!this.keyboard;this.root.hidden!==!e&&(e||this.reset(),this.root.hidden=!e,this.onLayout())}reset(){for(let e of[...this.held.keys()])this.letGo(e);this.stickPointer!==null&&this.letGo(this.stickPointer),this.endStick()}letGo(e){e===this.stickPointer&&this.endStick();let o=this.held.get(e);this.held.delete(e),o!==void 0&&![...this.held.values()].includes(o)&&this.buttons.get(o)?.classList.remove("ow-held");let r=this.fingers.get(e);this.fingers.delete(e),r&&Vt(this.parent,e,r),this.changed()}button(e){let o=L("button","ow-control-btn");o.type="button",o.tabIndex=-1,o.addEventListener("pointerdown",n=>{n.preventDefault(),ct(o,n.pointerId),o.classList.add("ow-held"),this.held.set(n.pointerId,e),this.report.press(e),this.fingers.set(n.pointerId,{x:n.clientX,y:n.clientY}),this.changed()}),o.addEventListener("pointermove",n=>{this.held.get(n.pointerId)===e&&this.fingers.set(n.pointerId,{x:n.clientX,y:n.clientY})});let r=n=>{this.held.get(n.pointerId)===e&&(this.held.delete(n.pointerId),this.fingers.delete(n.pointerId),[...this.held.values()].includes(e)||o.classList.remove("ow-held"),this.changed())};for(let n of["pointerup","pointercancel","lostpointercapture"])o.addEventListener(n,a=>r(a));return o}stickDown(e){if(this.stickPointer!==null)return;e.preventDefault(),ct(this.zone,e.pointerId),this.stickPointer=e.pointerId,this.fingers.set(e.pointerId,{x:e.clientX,y:e.clientY});let o=this.zone.getBoundingClientRect(),r=this.base.getBoundingClientRect(),n=M+8;this.center={x:Math.min(Math.max(e.clientX,o.left+n),o.right-n),y:Math.min(Math.max(e.clientY,o.top+n),o.bottom-n)},this.base.style.transform=`translate(${this.center.x-(r.left+r.width/2)}px, ${this.center.y-(r.top+r.height/2)}px)`,this.base.classList.add("ow-active"),this.stickMove(e)}stickMove(e){if(e.pointerId!==this.stickPointer)return;this.fingers.set(e.pointerId,{x:e.clientX,y:e.clientY});let o=e.clientX-this.center.x,r=e.clientY-this.center.y,n=Math.hypot(o,r);n>M&&(o=o/n*M,r=r/n*M),this.knob.style.transform=`translate(${o}px, ${r}px)`;let a=Math.min(n,M)/M,i=a<xe?0:(a-xe)/(1-xe)/(a||1);this.x=ht(o/M*i),this.y=ht(r/M*i),this.changed()}stickUp(e){e.pointerId===this.stickPointer&&(this.fingers.delete(e.pointerId),this.endStick())}endStick(){this.stickPointer=null,this.x=0,this.y=0,this.base.classList.remove("ow-active"),this.base.style.transform="",this.knob.style.transform="",this.changed()}changed(){this.queued||(this.queued=requestAnimationFrame(()=>{this.queued=0;let{buttons:e,owed:o}=this.report.take(this.held.values()),r={x:this.x,y:this.y,buttons:e};o&&this.changed();let n=JSON.stringify(r);n!==this.sent&&(this.sent=n,this.send(r))}))}};function Vt(t,e,o){let r=L("div","ow-tap-shield");r.style.left=`${o.x-fe/2}px`,r.style.top=`${o.y-fe/2}px`,r.style.width=r.style.height=`${fe}px`,t.append(r);let n=setTimeout(()=>r.remove(),Kt),a=()=>{clearTimeout(n),n=setTimeout(()=>r.remove(),qt)};for(let i of["pointerup","pointercancel","lostpointercapture"])r.addEventListener(i,s=>s.pointerId===e&&a());r.addEventListener("contextmenu",i=>i.preventDefault());try{r.setPointerCapture(e)}catch{a()}}function ct(t,e){try{t.setPointerCapture(e)}catch{}}function gt(t){let e=t.getBoundingClientRect(),o=getComputedStyle(t).transform;if(!o||o==="none")return e;let r=new DOMMatrixReadOnly(o);if(r.b||r.c||!r.a||!r.d)return e;let n=e.width/Math.abs(r.a),a=e.height/Math.abs(r.d),i=e.left+e.width/2-r.e,s=e.top+e.height/2-r.f;return{left:i-n/2,top:s-a/2,width:n,height:a}}function Wt(t,e){let o=Math.min(t.left,e.left),r=Math.min(t.top,e.top);return{left:o,top:r,width:Math.max(t.left+t.width,e.left+e.width)-o,height:Math.max(t.top+t.height,e.top+e.height)-r}}function ht(t){return Math.round(t*1e3)/1e3}function L(t,e,o){let r=document.createElement(t);return r.className=e,o!==void 0&&(r.textContent=o),r}function Yt(t,e){return t!=="lobby"?{surface:t,hidden:!1}:{surface:e?"none":"lobby",hidden:e}}var be=t=>Math.max(0,Math.ceil(t/1e3)),we=t=>{let e=t.slice(0,2).map(o=>o.name);return t.length>2?`${e.join(", ")} +${t.length-2}`:e.join(", ")};function Jt(t){let{you:e,host:o,kind:r,match:n,now:a}=t,i=[...t.players].sort((p,k)=>p.id===e?-1:k.id===e?1:p.id===o?-1:k.id===o?1:p.name.localeCompare(k.name)).map(p=>({id:p.id,name:p.name,ready:!!p.ready,host:p.id===o,you:p.id===e,away:p.connected===!1,idle:p.connected!==!1&&!!p.idle})),s=t.players.filter(p=>p.connected!==!1),h=t.players.find(p=>p.id===e),g=o===e&&n.phase==="lobby",l=t.schema.map(p=>({id:p.id,label:p.label,value:Fe(p,t.written),options:p.options,editable:g})),y={n:s.filter(p=>p.ready||r!=="public"&&p.id===o).length,of:s.length},m={surface:"none",rows:i,count:`${t.players.length} / ${t.max}`,ready:y,status:"",action:{kind:"none",label:"",disabled:!0},settings:l,seconds:null},Ce=n.participants?.includes(e)??!1,Ae=o===e&&r!=="public";if(n.phase==="starting"){if(!Ce)return{...m,surface:"watching",status:"Watching"};let p=Ae?{kind:"stop",label:"Stop",disabled:!1}:{kind:"unready",label:"Not ready",disabled:!1};return t.ownCountdown?{...m,surface:"countdown",action:p,seconds:null,status:"Get ready"}:{...m,surface:"countdown",action:p,seconds:Math.max(1,be((n.startsAt??a)-a)),status:"Get ready"}}if(n.phase==="playing"){if(n.paused){let p=s.filter(k=>n.participants?.includes(k.id)).length;return n.paused.reason==="host"?{...m,surface:"paused",status:"Paused"}:{...m,surface:"paused",seconds:be(n.paused.since+S.matchAbandonMs-a),status:`Waiting for players \xB7 ${p} / ${n.min}`}}return Ce?m:{...m,surface:"watching",status:"Watching"}}let P=s.filter(p=>!p.ready&&(r==="public"||p.id!==o));if(m.surface="lobby",Ae){let p=s.length<n.min;return m.action={kind:"start",label:"Start",disabled:p||P.length>0},m.status=p?`Need ${n.min} players`:P.length?`Waiting for ${we(P)}`:"",m}if(m.action={kind:h?.ready?"unready":"ready",label:h?.ready?"Not ready":"Ready",disabled:!1},r==="public")s.length<n.min?m.status=`Need ${n.min} players`:n.waitUntil!==void 0&&P.length?(m.seconds=be(n.waitUntil-a),m.status=`${we(P)} \xB7 ${m.seconds}s`):m.status=`${s.length-P.length} / ${s.length} ready`;else{let p=P.filter(k=>k.id!==e);m.status=h?.ready?p.length?`Waiting for ${we(p)}`:`Waiting for ${t.players.find(k=>k.id===o)?.name??"the host"}`:""}return m}function c(t,e="",o){let r=document.createElement(t);return e&&(r.className=e),o!==void 0&&(r.textContent=o),r}var Q=class{mode=null;ownCountdown=!1;hiddenByGame=!1;state=null;schema=[];timer=0;opts;root;card;title;count;list;settingsBox;status;action;invite;bar;barFaces;barStatus;barAction;countdown;numeral;cancel;pause;pauseStatus;pauseTimer;chip;last=null;lastNumeral=-1;listSignature="";settingsSignature="";faceSignature="";constructor(e,o){this.opts=o,this.root=c("div","ow-lobby"),this.root.hidden=!0,this.card=c("section","ow-lobby-card"),this.card.setAttribute("aria-label","Lobby");let r=c("header","ow-lobby-head");this.title=c("h2","","Lobby"),this.count=c("span","ow-lobby-count"),r.append(this.title,this.count),this.list=c("ul","ow-lobby-players"),this.settingsBox=c("div","ow-lobby-settings"),this.status=c("p","ow-lobby-status"),this.status.setAttribute("role","status"),this.action=this.button("ow-btn ow-btn-primary ow-lobby-action",()=>this.press()),this.invite=this.button("ow-btn ow-lobby-invite",()=>this.opts.onInvite()),this.invite.textContent="Invite";let n=c("div","ow-lobby-actions");n.append(this.action,this.invite),this.card.append(r,this.list,this.settingsBox,this.status,n),this.bar=c("div","ow-lobby-bar"),this.barFaces=c("span","ow-lobby-faces"),this.barStatus=c("span","ow-lobby-bar-status"),this.barStatus.setAttribute("role","status"),this.barAction=this.button("ow-btn ow-btn-primary ow-lobby-action",()=>this.press()),this.bar.append(this.barFaces,this.barStatus,this.barAction),this.countdown=c("div","ow-lobby-countdown"),this.numeral=c("b"),this.numeral.setAttribute("aria-hidden","true");let a=c("span","","Get ready");a.setAttribute("aria-hidden","true"),this.cancel=this.button("ow-btn ow-lobby-cancel",()=>this.press()),this.countdown.append(this.numeral,a,this.cancel),this.pause=c("div","ow-lobby-pause");let i=c("div","ow-lobby-pause-box");this.pauseStatus=c("p","ow-lobby-pause-status"),this.pauseStatus.setAttribute("role","status"),this.pauseTimer=c("p","ow-lobby-pause-timer"),i.append(this.pauseStatus,this.pauseTimer),this.pause.append(i),this.chip=c("div","ow-lobby-chip"),this.chip.setAttribute("role","status"),this.root.append(this.card,this.bar,this.countdown,this.pause,this.chip),e.append(this.root)}setSchema(e){this.schema=e,this.render()}enable(e,o={}){this.mode=e,this.ownCountdown=o.ownCountdown===!0,this.root.dataset.mode=e??"",e||this.reset(),this.render()}setLook(e){X(this.root,st,e)}reservedBox(){if(this.root.hidden)return null;let e=!this.countdown.hidden&&this.countdown.classList.contains("ow-lobby-countdown-bare"),o=this.bar.hidden?e&&!this.cancel.hidden?this.cancel:null:this.bar;return o?o.getBoundingClientRect():null}setHidden(e){this.hiddenByGame=e,this.render()}setRoom(e,o=0){if(!e)return this.reset();this.state={you:e.you,host:e.host,kind:e.room.startsWith("private:")?"private":e.room.startsWith("room:")?"named":"public",max:Math.max(o,e.players.length),players:e.players.map(r=>({...r})),match:e.match??{phase:"lobby",n:0,min:1},written:e.state?.[U]},this.render()}handle(e){let o=this.state;if(o){switch(e.t){case"join":o.players=[...o.players.filter(r=>r.id!==e.player.id),{...e.player}];break;case"leave":o.players=o.players.filter(r=>r.id!==e.id);break;case"away":o.players=o.players.map(r=>r.id===e.id?{...r,connected:!1}:r);break;case"back":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{connected:n,...a}=r;return a});break;case"ready":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{ready:n,...a}=r;return e.ready?{...a,ready:!0}:a});break;case"unready":o.players=o.players.map(({ready:r,...n})=>n);break;case"host":o.host=e.id;break;case"idle":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{idle:n,...a}=r;return e.idle?{...a,idle:!0}:a});break;case"name":o.players=o.players.map(r=>r.id===e.id?{...r,name:e.name}:r);break;case"match":o.match=e.match;break;case"state":if(e.k!==U)return;o.written=e.v;break;default:return}this.render()}}chooseSetting(e,o){let r=this.state,n=this.schema.find(i=>i.id===e);if(!r||!n||!n.options.some(i=>i.value===o))return null;let a={...r.written!==null&&typeof r.written=="object"?r.written:{},[e]:o};return r.written=a,this.render(),a}setReadyLocal(e){let o=this.state?.players.find(r=>r.id===this.state?.you);o&&(e?o.ready=!0:delete o.ready,this.render())}button(e,o){let r=c("button",e);return r.type="button",r.addEventListener("pointerdown",n=>n.preventDefault()),r.addEventListener("click",o),r}press(){let e=this.last?.action.kind;e==="start"?this.opts.onStart():e==="stop"?this.opts.onStop():e==="ready"?(this.setReadyLocal(!0),this.opts.onReady(!0)):e==="unready"&&(this.setReadyLocal(!1),this.opts.onReady(!1))}reset(){this.state=null,this.last=null,this.hiddenByGame=!1,window.clearInterval(this.timer),this.timer=0,this.root.hidden=!0,this.opts.onLayout?.()}render(){this.draw(),this.opts.onLayout?.()}draw(){if(!this.mode||!this.state){this.root.hidden=!0;return}let e=Jt({...this.state,schema:this.schema,now:this.opts.now(),ownCountdown:this.ownCountdown});this.last=e;let o=Yt(e.surface,this.hiddenByGame);this.hiddenByGame=o.hidden;let r=o.surface==="lobby";if(this.root.hidden=o.surface==="none",this.card.hidden=!(r&&this.mode==="card"),this.bar.hidden=!(r&&this.mode==="bar"),this.countdown.hidden=e.surface!=="countdown",this.countdown.classList.toggle("ow-lobby-countdown-bare",e.surface==="countdown"&&e.seconds===null),this.pause.hidden=e.surface!=="paused",this.chip.hidden=e.surface!=="watching",this.root.classList.toggle("ow-lobby-dim",r&&this.mode==="card"),r&&this.mode==="card"&&this.renderCard(e),r&&this.mode==="bar"&&this.renderBar(e),e.surface==="countdown"&&e.seconds!==null&&e.seconds!==this.lastNumeral&&(this.lastNumeral=e.seconds,this.numeral.textContent=String(e.seconds),this.numeral.style.animation="none",this.numeral.offsetWidth,this.numeral.style.animation=""),e.surface==="countdown"&&(this.cancel.textContent=e.action.label),e.surface!=="countdown"&&(this.lastNumeral=-1),e.surface==="paused"&&(this.pauseStatus.textContent=e.status,this.pauseTimer.textContent=e.seconds!==null?`Ends in ${Xt(e.seconds)}`:""),e.surface==="watching"){let[a,...i]=e.status.split(" \xB7 "),s=c("span","ow-lobby-chip-more",i.length?` \xB7 ${i.join(" \xB7 ")}`:"");this.chip.replaceChildren(a,s)}let n=e.seconds!==null;n&&!this.timer?this.timer=window.setInterval(()=>this.render(),250):!n&&this.timer&&(window.clearInterval(this.timer),this.timer=0)}renderCard(e){this.count.textContent=e.count,this.settingsBox.hidden=e.settings.length===0,this.status.textContent=e.status,this.status.hidden=e.status==="",this.setAction(this.action,e);let o=JSON.stringify(e.settings);o!==this.settingsSignature&&(this.settingsSignature=o,this.settingsBox.replaceChildren(...e.settings.map(n=>this.settingRow(n))));let r=JSON.stringify(e.rows);r!==this.listSignature&&(this.listSignature=r,this.list.replaceChildren(...e.rows.map(n=>{let a=c("li",n.away||n.idle?"ow-lobby-away":n.ready?"ow-lobby-ready":""),i=c("img","ow-headshot");i.src=`/avatar/${encodeURIComponent(n.id)}/head.svg`,i.alt="";let s=c("span","ow-lobby-name",n.name),h=[n.away?"Reconnecting":n.idle?"Idle":"",n.you?"You":"",n.host?"Host":""].filter(Boolean).join(" \xB7 ");return a.append(i,s),h&&a.append(c("span","ow-player-notes",h)),a.append(c("span",`ow-lobby-check${n.ready?" ow-lobby-check-on":""}`,n.ready?"Ready":"")),a})))}settingRow(e){let o=c("div","ow-lobby-setting");if(o.append(c("span","ow-lobby-setting-label",e.label)),!e.editable)return o.append(c("span","ow-lobby-setting-value",e.options.find(n=>n.value===e.value)?.label??String(e.value))),o;let r=c("div","ow-segments");r.setAttribute("role","radiogroup"),r.setAttribute("aria-label",e.label);for(let n of e.options){let a=this.button(`ow-segment${n.value===e.value?" ow-segment-on":""}`,()=>this.opts.onSetting(e.id,n.value));a.textContent=n.label,a.setAttribute("role","radio"),a.setAttribute("aria-checked",String(n.value===e.value)),r.append(a)}return o.append(r),o}renderBar(e){this.barStatus.textContent=e.status||`${e.ready.n} / ${e.ready.of} ready`,this.setAction(this.barAction,e);let o=JSON.stringify(e.rows.slice(0,5).map(r=>[r.id,r.ready]));o!==this.faceSignature&&(this.faceSignature=o,this.barFaces.replaceChildren(...e.rows.slice(0,5).map(r=>{let n=c("img",`ow-headshot${r.ready?" ow-lobby-face-ready":""}`);return n.src=`/avatar/${encodeURIComponent(r.id)}/head.svg`,n.alt="",n})))}setAction(e,o){e.hidden=o.action.kind==="none",e.textContent=o.action.label,e.disabled=o.action.disabled,e.classList.toggle("ow-btn-primary",o.action.kind!=="unready")}};function Xt(t){return`${Math.floor(t/60)}:${String(t%60).padStart(2,"0")}`}function mt(t,e){let o=[];for(let{kind:r,box:n}of e){if(!n||!(n.width>0)||!(n.height>0))continue;let a=Math.max(0,n.left-t.left),i=Math.max(0,n.top-t.top),s=Math.min(t.width,n.left+n.width-t.left),h=Math.min(t.height,n.top+n.height-t.top);if(!(s-a>.01&&h-i>.01))continue;let g=Math.floor(a+.01),l=Math.floor(i+.01);o.push({kind:r,x:g,y:l,w:Math.ceil(s-.01)-g,h:Math.ceil(h-.01)-l})}return o}var ee=class{measure;send;nextFrame;queued=!1;sent=null;constructor(e,o,r=n=>requestAnimationFrame(n)){this.measure=e,this.send=o,this.nextFrame=r}changed(){this.queued||(this.queued=!0,this.nextFrame(()=>{this.queued=!1;let e=this.measure();if(!e)return;let o=JSON.stringify(e);o!==this.sent&&(this.sent=o,this.send(e))}))}resend(){this.sent=null,this.changed()}};var ve=t=>`ow:resume:${t}`;function T(t,e){try{e?sessionStorage.setItem(ve(t),JSON.stringify({...e,at:Date.now()})):sessionStorage.removeItem(ve(t))}catch{}}function ut(t){try{let e=sessionStorage.getItem(ve(t));if(!e)return null;let o=performance.getEntriesByType("navigation")[0];if(o&&o.type!=="reload"&&o.type!=="back_forward")return te(t);let r=JSON.parse(e);return typeof r.key!="string"||typeof r.rejoin!="string"||typeof r.at!="number"||Date.now()-r.at>18e4||Number(r.rejoin.split(".")[0])*1e3<Date.now()?te(t):{key:r.key,rejoin:r.rejoin}}catch{return null}}var Zt=t=>`ow:own-server:${t}`;function xt(t,e){try{sessionStorage.setItem(Zt(t),e)}catch{}}function te(t){return T(t,null),null}var oe=class extends Error{constructor(o,r=0,n=0,a=""){super(o);this.status=r;this.retryAfterMs=n;this.code=a;this.name="RequestError"}status;retryAfterMs;code;get retryable(){return this.status===0||this.status===408||this.status===429||this.status>=500}};var re=class{constructor(e=48*1024){this.max=e}max;used=0;async run(e,o){let r=new TextEncoder().encode(e).byteLength;if(this.used+r>this.max)throw new oe("Progress is waiting to sync when you return to the game.");this.used+=r;try{return await o()}finally{this.used-=r}}};var ye=/^[2-9]$/.test(new URLSearchParams(location.search).get("player")??"")?new URLSearchParams(location.search).get("player"):null;var Qt=null;function ft(){return Qt?.n??null}var Zo=new re;var bt=[300,700,1500,3e3,5e3,8e3],eo=9e4,to=1e4,vt=()=>Array.from(crypto.getRandomValues(new Uint8Array(10)),t=>"abcdefghijklmnopqrstuvwxyz0123456789"[t%36]).join(""),yt=vt();function kt(){yt=vt()}var wt=null;var St=!1;function zt(t){St=t}var oo=5e4,ro=4e3,ne=class{ws=null;key=null;rejoin=null;you="";closed=!1;attempt=0;droppedAt=0;sleeping=!1;lastHeard=0;heardCount=0;pingAt=0;hintedHidden=!1;pingTimer=0;watchTimer=0;retryTimer=0;page=yt;slug;options;callbacks;onVisible=()=>{this.hint(),document.visibilityState==="visible"&&this.wake()};onOnline=()=>this.wake();onShow=e=>e.persisted&&this.wake();onHide=()=>this.hint();constructor(e,o,r){this.slug=e,this.options=o,this.callbacks=r,this.key=o.key??null,this.rejoin=o.rejoin??null,document.addEventListener("visibilitychange",this.onVisible),addEventListener("online",this.onOnline),addEventListener("pageshow",this.onShow),addEventListener("pagehide",this.onHide)}join(){return new Promise((e,o)=>this.open(e,o))}send(e){this.ws?.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(e))}hint(){let e=document.visibilityState==="hidden";e===this.hintedHidden||this.ws?.readyState!==WebSocket.OPEN||(this.hintedHidden=e,this.send({t:"vis",hidden:e}))}ping(){let e=this.ws;e?.readyState===WebSocket.OPEN&&(this.pingAt&&Date.now()-this.pingAt<5e3||(this.pingAt=Date.now(),e.send(he)))}close(){this.closed=!0,T(this.slug,null),this.dispose(),this.ws?.close(1e3)}reload(){return this.closed=!0,this.dispose(),this.ws?.close(We,"Updating"),this.key?.startsWith("pub:")&&this.rejoin?{key:this.key,rejoin:this.rejoin}:null}open(e,o){this.retryTimer=0;let r=new URL(`/api/games/${this.slug}/rooms/connect`,location.href);r.protocol=location.protocol==="https:"?"wss:":"ws:",this.key?(r.searchParams.set("key",this.key),this.rejoin&&r.searchParams.set("rejoin",this.rejoin)):this.options.server?(r.searchParams.set("server",this.options.server),this.options.private&&r.searchParams.set("own","1")):this.options.name?r.searchParams.set("name",this.options.name):(this.options.mode&&r.searchParams.set("mode",this.options.mode),this.options.follow&&r.searchParams.set("follow",this.options.follow)),this.options.maxPlayers&&r.searchParams.set("max",String(this.options.maxPlayers)),this.options.minPlayers&&r.searchParams.set("min",String(this.options.minPlayers)),this.options.countdown!==void 0&&r.searchParams.set("countdown",String(this.options.countdown)),this.options.teams&&r.searchParams.set("teams",String(this.options.teams)),this.options.ranked&&r.searchParams.set("ranked","1"),ye&&r.searchParams.set("devplayer",ye);let n=ft();n&&r.searchParams.set("tester",n),r.searchParams.set("page",this.page),this.options.build&&r.searchParams.set("build",this.options.build),wt&&r.searchParams.set("pass",wt),St&&r.searchParams.set("demo","1");let a=new WebSocket(r);this.ws=a,this.lastHeard=Date.now();let i=!1;a.onopen=()=>{this.lastHeard=Date.now(),window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),this.pingTimer=window.setInterval(()=>a.readyState===WebSocket.OPEN&&this.ping(),to),this.watchTimer=window.setInterval(()=>{a===this.ws&&a.readyState===WebSocket.OPEN&&Date.now()-this.lastHeard>oo&&this.lost(a)},5e3)},a.onmessage=g=>{this.lastHeard=Date.now(),this.heardCount++;let l;try{l=JSON.parse(g.data)}catch{return}if(l.t==="pong"){this.pingAt&&this.callbacks.onRtt?.(Date.now()-this.pingAt),this.pingAt=0;return}if(l.t==="welcome"&&(l.rejoin&&(this.rejoin=l.rejoin),delete l.rejoin,l.room.startsWith("pub:")&&this.rejoin&&T(this.slug,{key:l.room,rejoin:this.rejoin})),l.t==="leave"&&l.kicked&&l.id===this.you){this.close(),this.finish("kicked");return}if(l.t==="welcome"&&(this.hintedHidden=!1,this.hint()),l.t==="welcome"&&!i&&(i=!0,this.key=l.room,this.you=l.you,this.attempt=0,this.droppedAt&&(this.droppedAt=0,this.callbacks.onConnection?.(!0)),e)){let{t:y,...m}=l;e(m),e=void 0;return}this.callbacks.onMessage(l)};let s=!1,h=g=>{if(!s&&(s=!0,window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),!(this.closed||a!==this.ws))){if(g.code===qe)return this.finish("replaced");if(g.code===Ve&&i&&document.visibilityState==="hidden"){this.sleeping=!0,this.droppedAt||(this.droppedAt=Date.now(),this.callbacks.onConnection?.(!1));return}if(g.code===Ke){if(i||!o)return this.finish("kicked");this.closed=!0,this.dispose(),T(this.slug,null),o(Object.assign(new Error("You were removed from this server."),{kicked:!0}));return}if(!i&&o){this.closed=!0,this.dispose(),o(new Error(this.options.name||this.options.server?"Could not join that server. It may be full.":"Could not join a server. Try again soon."));return}this.retry()}};a.onclose=h,a.onerror=()=>{window.setTimeout(()=>{a.readyState===WebSocket.CLOSED&&h({code:1006})},1e3)}}retry(){if(this.closed)return;let e=Date.now();if(this.droppedAt||(this.droppedAt=e,this.callbacks.onConnection?.(!1)),e-this.droppedAt>eo)return this.finish("disconnected");if(this.retryTimer)return;let o=bt[Math.min(this.attempt++,bt.length-1)]*(.5+Math.random());this.retryTimer=window.setTimeout(()=>{this.retryTimer=0,this.closed||this.open()},o)}lost(e){if(!(e!==this.ws||this.closed)){e.onopen=e.onmessage=e.onclose=e.onerror=null,window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer);try{e.close()}catch{}this.retry()}}wake(){if(this.closed)return;if(this.sleeping){this.sleeping=!1,this.droppedAt=Date.now(),this.attempt=0,this.open();return}let e=this.ws;if(!e||e.readyState===WebSocket.CLOSING||e.readyState===WebSocket.CLOSED){this.retryTimer&&(window.clearTimeout(this.retryTimer),this.retryTimer=0,this.open());return}if(e.readyState!==WebSocket.OPEN)return;let o=this.heardCount;try{e.send(he)}catch{return this.lost(e)}window.setTimeout(()=>e===this.ws&&!this.closed&&this.heardCount===o&&this.lost(e),ro)}dispose(){window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),window.clearTimeout(this.retryTimer),this.retryTimer=0,document.removeEventListener("visibilitychange",this.onVisible),removeEventListener("online",this.onOnline),removeEventListener("pageshow",this.onShow),removeEventListener("pagehide",this.onHide)}finish(e){this.closed=!0,this.dispose(),T(this.slug,null),this.callbacks.onClose(e)}};var Rt=`:root {
|
|
1
|
+
"use strict";(()=>{var He=["#f6dcc5","#ebc29f","#d4a07a","#b07a55","#875839","#5e3d29","#93c9bb","#a8c595","#94bcd3","#ab9bd9","#dca3ad","#b3bccb"],ve=["#c95f56","#dc8a4f","#e2bd52","#9cc27a","#5a8a5e","#4f9a8e","#6fb7c8","#5b87c5","#465089","#8b68a8","#dc8fae","#f2eee6","#a9a8ad","#5d5c63","#2b2a30","#80604d"],Fe=["Happy","Grin","Shades","Wink","Surprised","Determined","Joyful","Shy"],Ke=["None","Sprout","Cap","Beanie","Crown","Headphones","Horns","Antenna","Bow","Halo","Party hat","Cat ears","Short hair","Tuft","Bob","Spikes","Bun","Curls","Long","Mop"];var qe=["Plain","Band","Spots","Stripes","Star"];var Ho={skin:He.length,shirt:ve.length,pants:ve.length,face:Fe.length,hat:Ke.length,top:qe.length},ro=[[5,6],[3,4],[6,7],[9,8],[10,0],[12,13]];function Ve(t){let e=2166136261;for(let d of t)e=Math.imul(e^d.charCodeAt(0),16777619)>>>0;let o=d=>(e=Math.imul(e^e>>>13,2654435761)>>>0,e%d),r=o(He.length),n=r>=6?ro[r-6][o(2)]:o(ve.length),a=o(2)===0?n:[8,13,14,15][o(4)],i=o(5)===0?1:12+o(Ke.length-12),s=o(2)===0?0:o(qe.length);return{skin:r,shirt:n,pants:a,face:o(Fe.length),hat:i,top:s}}var P={roomMaxPlayersDefault:16,roomMaxPlayersCap:30,teamsMax:8,messageBytes:16*1024,presenceBytes:1024,stateKeyLength:64,stateValueBytes:16*1024,stateKeys:256,privateKeys:16,privateValueBytes:4*1024,privateBytesPerPlayer:8*1024,messagesPerSecond:60,messagesPerSecondMin:10,roomBytesPerSecond:128*1024,roomBytesPerSecondMin:16*1024,presenceHz:20,presenceHzMin:5,roomMessagesPerSecond:900,roomBytesPerSecondTotal:2*1024*1024,matchCountdownMs:3e3,matchCountdownMaxMs:1e4,matchIdleMs:45e3,matchAbandonMs:12e4,idleAfterMs:3e4,idleAbandonMs:5*6e4,rankedPairMatchesPerDay:5,chatLength:200,chatIntervalMs:750,chatHistory:50,chatChannelsPerPlayer:10,saveValueBytes:64*1024,saveKeysPerGame:100,saveBytesPerGame:1024*1024,guestSaveBytesPerGame:128*1024,serverDataKeys:128,serverDataBytes:512*1024,serverDataServersPerGame:5e3,serverDataBytesPerGame:64*1024*1024,serverDataIdleDays:120,gameDataKeys:32,gameDataListMax:100,gameDataItemBytes:1024,gameDataValueBytes:8*1024,gameDataMapFields:1e3,gameDataMapPerPlayer:100,gameDataNumberMax:1e15,gameDataWritesPerMinute:30,deployFiles:2e3,deployFileBytes:25*1024*1024,deployHtmlBytes:10*1024*1024,deployPathLength:200,deployTotalBytes:100*1024*1024,envVars:50,envValueBytes:4*1024,envTotalBytes:16*1024,proxyRequestBytes:1024*1024,proxyTextRequestBytes:256*1024,proxySpeechRequestBytes:16*1024,proxyResponseBytes:10*1024*1024,proxyMaxOutputTokens:4096,proxyCallsPerDay:2e3,proxyCallsPerDayMax:1e5,proxyCallsPerPlayerPerDay:100,proxyCallsPerNetworkPerDay:1e3,proxyMediaCallsPerDay:100,proxyMediaCallsPerDayMax:1e4,proxyMediaCallsPerPlayerPerDay:20,proxyMediaCallsPerNetworkPerDay:25,proxyUnitsPerDay:2e6,proxyUnitsPerDayMax:1e8,proxyUnitsPerPlayerPerDay:25e4,proxyUnitsPerGuestPerDay:1e5,proxyUnitsPerNetworkPerDay:5e5,errorReportsPerPage:10,consoleLineLength:2e3,consoleLinesPerSecond:50,gameNameLength:60,gameDescriptionLength:1e3,galleryItems:5,mediaImageBytes:5*1024*1024,mediaVideoBytes:30*1024*1024,mediaGifBytes:1024*1024,mediaGifSide:512,mediaUploadsPerDay:200,mediaBytesPerDay:500*1024*1024,badgesPerGame:50,controlHints:12,controlHintKeys:4,controlKeyLength:12,controlActionLength:40,helpLength:400,badgeNameLength:50,badgeDescriptionLength:200,leaderboardsPerGame:25,leaderboardTop:100,gamesPerOwner:50,gamesCreatedPerCreatorPerDay:3,uploadAccountAgeMs:10080*6e4,deploysPerOwnerPerDay:100,draftsPerOwnerPerDay:1e3,draftsKeptPerGame:3,cliTokensPerAccount:10,cliDeviceCodeSeconds:600,deploymentsKeptPerGame:10,deployBytesPerOwnerPerDay:2*1024*1024*1024,deployEntriesPerOwnerPerDay:1e5,bioLength:500,exportRows:2e3,exportSaveChars:4*1024*1024,exportEveryMs:60*6e4,friendsMax:200,friendRequestsMax:100,friendRequestsIncomingMax:50,friendRequestsPerDay:20,friendRequestsPerNetworkPerDay:120,friendRequestPushesPerDay:5,passwordMinLength:8,passwordMaxLength:72,signupsPerNetworkPerDay:100,signupsPerWidePerDay:300,guestsPerNetworkPerDay:300,guestsPerWidePerDay:1500,visitsPerNetworkPerDay:10,visitSeconds:10,errorsPerDeployment:100,controlButtons:4,controlLabelLength:12,partySize:6,partyChatHistory:50,messageLength:500,messagesPerPage:50,groupChatMembers:20,groupChatNameLength:40,conversationsListed:50,notificationsListed:50,invitesPerRequest:10,inviteLiveMs:30*6e4,partyInviteMs:60*6e4};var Ye=/^[a-z0-9]{12}$/,ee=2;function ke(t){return`${t.mode}.${t.max}.${t.teams}.${t.ranked?1:0}${t.min!==ee?`.${t.min}`:""}`}var no=/^pub:([a-z0-9-]+)\.(\d+)\.(\d)\.([01])(?:\.(\d+))?:(\d+)$/;function Je(t){let e=no.exec(t);if(!e)return null;let o={mode:e[1],max:Number(e[2]),teams:Number(e[3]),ranked:e[4]==="1",min:e[5]===void 0?ee:Number(e[5])};return{...o,name:ke(o),n:Number(e[6])}}function Xe(t,e,o){let r=typeof t=="string"?Number(t):t;return typeof r!="number"||!Number.isInteger(r)?Math.min(o,e):Math.min(e,Math.max(1,r))}var We=t=>t.replace(/[\u0000-\u001f\u007f]/g," ").replace(/\s+/g," ").trim();var ao=/^[a-z0-9][a-z0-9-]{0,19}$/;function Ze(t){if(!t||typeof t!="object")return null;let e=t,o=[];for(let n of Array.isArray(e.buttons)?e.buttons:[]){if(o.length>=P.controlButtons)break;let{id:a,label:i}=n??{};if(typeof a!="string"||!ao.test(a)||o.some(d=>d.id===a))continue;let s=typeof i=="string"?i.replace(/[\u0000-\u001f\u007f]/g,"").replace(/\s+/g," ").trim().slice(0,P.controlLabelLength).trim():"";o.push({id:a,label:s||a})}let r=e.stick===!0;return r||o.length>0?{stick:r,zone:e.zone==="corner"?"corner":"wide",buttons:o}:null}var V="host:ow.settings",io=/^[a-z][a-zA-Z0-9]{0,15}$/;function Qe(t){if(!Array.isArray(t))return[];let e=[];for(let o of t){if(e.length>=6)break;let{id:r,label:n,options:a,default:i}=o??{};if(typeof r!="string"||!io.test(r)||e.some(c=>c.id===r)||!Array.isArray(a))continue;let s=[];for(let c of a){let p=typeof c=="object"&&c!==null?c.value:c;if(typeof p!="string"&&typeof p!="number"||typeof p=="number"&&!Number.isFinite(p)||s.length>=8||s.some(u=>u.value===p))continue;let x=typeof c=="object"&&c!==null&&typeof c.label=="string"?c.label:String(p);s.push({value:p,label:We(x).slice(0,20)||String(p)})}if(s.length<2)continue;let d=typeof n=="string"?We(n).slice(0,24):"";e.push({id:r,label:d||r,options:s,default:s.some(c=>c.value===i)?i:s[0].value})}return e}function et(t,e){let o=e!==null&&typeof e=="object"?e[t.id]:void 0;return t.options.some(r=>r.value===o)?o:t.default}var Se='{"t":"ping"}';var tt=4001,ot=4003,rt=4008,nt=4006;var at="onceworlds:hello",it="onceworlds:connect",so=/^[a-z0-9]{1,32}~(?:(?:0|[1-9]\d{0,3})\.(?:0|[1-9]\d{0,4})\.(?:0|[1-9]\d{0,5}))?~[0-9a-z]{1,11}~[lp]~[A-Za-z0-9_-]{43}$/;function st(t){let e=t!==null&&typeof t=="object"?t.build:void 0;return typeof e=="string"&&so.test(e)?e:null}var lt="onceworlds-console";var pt="allow-scripts allow-pointer-lock allow-forms allow-orientation-lock",dt=["autoplay","gamepad","screen-wake-lock","accelerometer","gyroscope"].map(t=>`${t} *`).join("; "),ct=100*1024*1024;var gt=new Set(["server","join","deploy","watch","player","embed","k","console","tester","live","demo",lt]);var ze="onceworlds:page",lo=["ran","blocked","failed","threw","loaded"];function ht(t){if(t===null||typeof t!="object")return null;let{what:e,detail:o}=t;return typeof e!="string"||!lo.includes(e)?null:{what:e,detail:typeof o=="string"?o.slice(0,200):""}}var po=`(function(){var n=0,s=function(w,d){if(n++<12)try{parent.postMessage({type:${JSON.stringify(ze)},what:w,detail:String(d).slice(0,200)},"*")}catch(e){}};s("ran",document.readyState);addEventListener("securitypolicyviolation",function(e){s("blocked",e.effectiveDirective+" "+e.blockedURI)});addEventListener("error",function(e){var t=e.target;t&&t.tagName?s("failed",t.tagName+" "+(t.src||t.href)):s("threw",e.message+" "+e.filename+":"+e.lineno)},true);addEventListener("load",function(){s("loaded",typeof onceworlds)})})();`,Yo=`<script>${po}<\/script>`;function ut(t){return t?.ownCountdown!==!0}function mt(t){let e=t?.lobby;return e==="card"||e==="bar"?e:e==="game"?null:typeof t?.minPlayers=="number"||typeof t?.minPlayersPrivate=="number"||typeof t?.countdown=="number"||Array.isArray(t?.settings)&&t.settings.length>0?"bar":null}function xt(t){return t.key==="Enter"&&!t.isComposing&&!t.ctrlKey&&!t.metaKey&&!t.altKey&&!t.shiftKey}var ft=400;var co=/^#(?:[0-9a-f]{3}){1,2}$/i,T={panel:"#111216",text:"#f7f7f8",accent:"#d33e00"},Ee=4.5,Re=3,te=["#4ade80","#15803d"];function wt(t){let e=[];if(t==null)return{look:null,notes:e};if(typeof t!="object")return{look:null,notes:["a look is { accent, panel, text } or null"]};let o=t,r=p=>{let x=o[p];return x==null?null:typeof x=="string"&&co.test(x)?yt(x):(e.push(`${p} is not #rgb or #rrggbb`),null)},n=r("panel"),a=r("text"),i=r("accent");if(n||a){let p=A(a??T.text,n??T.panel);p<Ee&&(e.push(`text on panel is ${p.toFixed(1)}:1, under ${Ee}:1: the platform's are used`),n=a=null)}let s=n??T.panel,d=a??T.text;if(i){let p=A(i,s);p<Re&&(e.push(`accent on panel is ${p.toFixed(1)}:1, under ${Re}:1: the platform's is used`),i=null)}if(!i&&n&&A(T.accent,n)<Re&&(i=d),!n&&!a&&!i)return{look:null,notes:e};let c=i?go(i):null;return{look:{panel:n,text:a,muted:n||a?ho(d,s):null,accent:i,accentHover:i?vt(i,c==="#ffffff"?"#000000":"#ffffff",.14):null,onAccent:c,ok:n?A(te[0],n)>=A(te[1],n)?te[0]:te[1]:null},notes:e}}function yt(t){let e=t.slice(1).toLowerCase();return`#${e.length===3?[...e].map(o=>o+o).join(""):e}`}function W(t){let e=yt(t);return[parseInt(e.slice(1,3),16),parseInt(e.slice(3,5),16),parseInt(e.slice(5,7),16)]}function bt(t){let[e,o,r]=W(t).map(n=>{let a=n/255;return a<=.04045?a/12.92:((a+.055)/1.055)**2.4});return .2126*e+.7152*o+.0722*r}function A(t,e){let[o,r]=[bt(t),bt(e)].sort((n,a)=>a-n);return(o+.05)/(r+.05)}function go(t){return A(t,"#000000")>A(t,"#ffffff")?"#000000":"#ffffff"}function vt(t,e,o){let[r,n]=[W(t),W(e)];return`#${r.map((a,i)=>Math.round(a+(n[i]-a)*o).toString(16).padStart(2,"0")).join("")}`}function ho(t,e){for(let o=.3;o>.001;o-=.05){let r=vt(t,e,o);if(A(r,e)>=Ee)return r}return t}var oe=class{port=null;handlers;events;onConnect;solo;demo;onActivity;onPage;constructor(e,o,r,n,a={}){this.handlers=o,this.events=r,this.onConnect=n,this.solo=a.solo===!0,this.demo=a.demo===!0,this.onActivity=a.onActivity??null,this.onPage=a.onPage??null,window.addEventListener("message",i=>{if(!(i.source!==e.contentWindow||i.origin!=="null")&&(i.data?.type===at&&this.connect(i.source,st(i.data)),i.data?.type===ze)){let s=ht(i.data);s&&this.onPage?.(s)}})}activity(e,o){try{this.onActivity?.(e,o)}catch{}}emit(e,o){this.port?.postMessage({kind:"event",name:e,data:o})}connect(e,o){this.port?.close();let r=new MessageChannel,n=r.port1;this.port=n,n.onmessage=i=>this.receive(n,i.data);let a={type:it,...this.solo?{solo:!0}:{},...this.demo?{demo:!0}:{}};e.postMessage(a,"*",[r.port2]),this.onConnect(o)}async receive(e,o){if(!(e!==this.port||!o||typeof o!="object")){if(o.kind==="event"){Object.hasOwn(this.events,o.name)&&(this.events[o.name](o.data),this.activity(String(o.name),null));return}if(o.kind==="req")try{if(!Object.hasOwn(this.handlers,o.method))throw new Error(`Unknown method: ${String(o.method)}`);let r=this.handlers[o.method],n=await r(o.params);e.postMessage({kind:"res",id:o.id,ok:!0,result:n??null}),this.activity(String(o.method),null)}catch(r){let n=r instanceof Error?r.message:String(r);e.postMessage({kind:"res",id:o.id,ok:!1,error:n}),this.activity(String(o.method),n)}}}};var uo="ow-game-storage",mo=256,kt="guest";function Pe(t){let e=0,o=new Set,r=[t];for(;r.length;){let n=r.pop();if(typeof n=="string")e+=n.length*2;else if(typeof n!="object"||n===null)e+=8;else{if(o.has(n))continue;if(o.add(n),n instanceof ArrayBuffer)e+=n.byteLength;else if(ArrayBuffer.isView(n))e+=n.buffer.byteLength;else if(typeof Blob=="function"&&n instanceof Blob)e+=n.size;else if(n instanceof Map)for(let[a,i]of n)r.push(a,i);else if(n instanceof Set)for(let a of n)r.push(a);else if(Array.isArray(n))r.push(...n.slice(0,1e5),...n.length>1e5?[n.slice(1e5)]:[]);else for(let[a,i]of Object.entries(n))r.push(a,i)}}return e}function L(t){if(typeof t!="string"||t.length>mo)throw new Error("Bad name");return t}function St(t){if(t===null)return null;if(typeof t=="string")return L(t);if(Array.isArray(t)&&t.length<=32)return t.map(L);throw new Error("Bad key path")}function xo(t){if(typeof t!="object"||t===null)throw new Error("Bad stores");let e=Object.keys(t);if(e.length>1e3)throw new Error("Too many stores");let o={};for(let r of e){let n=t[L(r)];if(typeof n!="object"||n===null||!Array.isArray(n.indexes)||n.indexes.length>1e3)throw new Error("Bad store");let a=Number(n.nextKey),i=n.indexes.map(s=>{let d=St(s?.keyPath);if(d===null)throw new Error("Bad index");return{name:L(s.name),keyPath:d,unique:s.unique===!0,multiEntry:s.multiEntry===!0}});o[r]={keyPath:St(n.keyPath),autoIncrement:n.autoIncrement===!0,nextKey:Number.isFinite(a)?a:1,indexes:i}}return o}function k(t){return new Promise((e,o)=>{t.onsuccess=()=>e(t.result),t.onerror=()=>o(t.error??new Error("Storage failed"))})}function Me(t){return new Promise((e,o)=>{t.oncomplete=()=>e(),t.onabort=t.onerror=()=>o(t.error??new Error("Storage failed"))})}var re=class{database=null;named=null;owner;factory;limit;constructor(e,o={}){this.owner=e,this.factory=o.factory??(()=>indexedDB),this.limit=o.limit??ct}open(){return this.database??=new Promise((e,o)=>{let r=this.factory().open(uo,1);r.onupgradeneeded=()=>{r.result.createObjectStore("dbs",{keyPath:["owner","db"]}),r.result.createObjectStore("records")},r.onsuccess=()=>e(r.result),r.onerror=()=>o(r.error??new Error("No storage in this browser"))}),this.database}who(){return this.named??=this.owner().then(async({game:e,player:o})=>{let r=`${e}
|
|
2
|
+
${o??kt}`;return o!==null&&await this.adopt(`${e}
|
|
3
|
+
${kt}`,r),r}),this.named}async adopt(e,o){let n=(await this.open()).transaction(["dbs","records"],"readwrite"),a=Me(n),i=n.objectStore("dbs"),s=n.objectStore("records"),d=await k(i.getAll(this.ownerRange(e)));for(let c of d){let p=this.dbRange(e,c.db);if(!await k(i.getKey([o,c.db]))){let x=await k(s.getAllKeys(p));for(let u of x){let E=await k(s.get(u));s.put(E,[o,...u.slice(1)])}i.put({...c,owner:o})}s.delete(p),i.delete([e,c.db])}await a}ownerRange(e){return IDBKeyRange.bound([e],[`${e}\0`],!1,!0)}dbRange(e,o){return IDBKeyRange.bound([e,o],[e,`${o}\0`],!1,!0)}storeRange(e,o,r){return IDBKeyRange.bound([e,o,r],[e,o,`${r}\0`],!1,!0)}async read({db:e}){L(e);let o=await this.who(),n=(await this.open()).transaction(["dbs","records"]),a=await k(n.objectStore("dbs").get([o,e]));if(!a)return null;let i=n.objectStore("records"),s=this.dbRange(o,e),[d,c]=await Promise.all([k(i.getAllKeys(s)),k(i.getAll(s))]);return{version:a.version,stores:a.stores,records:d.map((p,x)=>({store:p[2],key:p[3],value:c[x].value}))}}async commit(e){let o=L(e?.db),r=Number(e.version);if(!Number.isFinite(r)||r<0)throw new Error("Bad version");let n=e.ops;if(!Array.isArray(n))throw new Error("Bad changes");let a=e.stores===void 0?void 0:xo(e.stores),i=await this.who(),d=(await this.open()).transaction(["dbs","records"],"readwrite"),c=Me(d),p=d.objectStore("dbs"),x=d.objectStore("records");try{let u=await k(p.getAll(this.ownerRange(i))),E=u.find(l=>l.db===o)??{owner:i,db:o,version:r,stores:{},bytes:0},q=u.reduce((l,f)=>l+(f===E?0:f.bytes),0),b=E.bytes;for(let l of n){let f=L(l?.store);if("clear"in l){b-=await this.sum(x,this.storeRange(i,o,f)),x.delete(this.storeRange(i,o,f));continue}let ye=[i,o,f,"put"in l?l.put:l.remove],Ge=await k(x.get(ye));if(Ge&&(b-=Ge.bytes),"put"in l){let Ue=Pe(l.value)+Pe(l.put)+64;b+=Ue,x.put({value:l.value,bytes:Ue},ye)}else x.delete(ye)}if(a)for(let l of Object.keys(E.stores))Object.hasOwn(a,l)||(b-=await this.sum(x,this.storeRange(i,o,l)),x.delete(this.storeRange(i,o,l)));if(q+=Pe(a??E.stores),q+b>this.limit)throw new Error("QuotaExceededError");p.put({owner:i,db:o,version:r,stores:a??E.stores,bytes:Math.max(0,b)})}catch(u){try{d.abort()}catch{}throw c.catch(()=>{}),u}return await c,null}async sum(e,o){return(await k(e.getAll(o))).reduce((n,a)=>n+a.bytes,0)}async remove({db:e}){L(e);let o=await this.who(),n=(await this.open()).transaction(["dbs","records"],"readwrite"),a=Me(n);return n.objectStore("records").delete(this.dbRange(o,e)),n.objectStore("dbs").delete([o,e]),await a,null}async list(){let e=await this.who(),o=await this.open();return(await k(o.transaction("dbs").objectStore("dbs").getAll(this.ownerRange(e)))).map(n=>({name:n.db,version:n.version}))}};var ne=class{pressed=new Set;press(e){this.pressed.add(e)}take(e){let o=new Set(e),r=!1;for(let n of this.pressed)o.has(n)||(o.add(n),r=!0);return this.pressed.clear(),{buttons:[...o],owed:r}}};var zt=["--ow-panel","--ow-face-edge","--ow-hover","--ow-on-accent","--text","--muted","--line","--line-strong","--fill","--fill-strong","--ok","--accent-fill","--accent-fill-hover","--accent-hover"],Rt=["--ow-ctl-edge","--ow-ctl-fill","--ow-ctl-stick","--ow-ctl-knob","--ow-ctl-label","--ow-ctl-shadow","--ow-ctl-held","--ow-ctl-main","--ow-ctl-main-edge","--ow-ctl-main-label","--ow-ctl-main-shadow","--ow-ctl-main-held"];function y(t,e){return`rgba(${W(t).join(", ")}, ${e})`}function Et(t){let e={};if(!t)return e;if(t.panel&&(e["--ow-panel"]=t.panel,e["--ow-face-edge"]=t.panel),t.ok&&(e["--ok"]=t.ok),t.panel||t.text){let o=t.text??T.text;t.text&&(e["--text"]=t.text),t.muted&&(e["--muted"]=t.muted),e["--line"]=y(o,.09),e["--line-strong"]=y(o,.16),e["--fill"]=y(o,.06),e["--fill-strong"]=y(o,.1),e["--ow-hover"]=y(o,.16)}return t.accent&&t.accentHover&&t.onAccent&&(e["--accent-fill"]=t.accent,e["--accent-fill-hover"]=t.accentHover,e["--accent-hover"]=t.accent,e["--ow-on-accent"]=t.onAccent),e}function Pt(t){let e={};return t&&(t.text&&(e["--ow-ctl-edge"]=y(t.text,.4),e["--ow-ctl-knob"]=y(t.text,.9),e["--ow-ctl-label"]=t.text,e["--ow-ctl-held"]=y(t.text,.35)),t.panel&&(e["--ow-ctl-fill"]=y(t.panel,.4),e["--ow-ctl-stick"]=y(t.panel,.3),e["--ow-ctl-shadow"]=y(t.panel,.5)),t.accent&&t.accentHover&&t.onAccent&&(e["--ow-ctl-main"]=y(t.accent,.85),e["--ow-ctl-main-edge"]=t.accent,e["--ow-ctl-main-label"]=t.onAccent,e["--ow-ctl-main-shadow"]="none",e["--ow-ctl-main-held"]=t.accentHover)),e}function ae(t,e,o){for(let r of e)Object.hasOwn(o,r)?t.style.setProperty(r,o[r]):t.style.removeProperty(r);t.toggleAttribute("data-look",e.some(r=>Object.hasOwn(o,r)))}var $=52,Ae=.12,Le=96,fo=400,bo=2e4,ie=class{parent;root;zone;base;knob;buttonBox;send;onLayout;layout=null;touch;blocked=!1;keyboard=!1;stickPointer=null;center={x:0,y:0};x=0;y=0;buttons=new Map;held=new Map;fingers=new Map;report=new ne;queued=0;sent="";placed={stick:null,buttons:null};constructor(e,o,r=()=>{}){this.send=o,this.onLayout=r,this.parent=e,this.touch=matchMedia("(pointer: coarse)").matches,this.root=D("div","ow-controls"),this.root.hidden=!0,this.zone=D("div","ow-stick-zone"),this.base=D("div","ow-stick"),this.knob=D("div","ow-stick-knob"),this.base.append(this.knob),this.zone.append(this.base),this.buttonBox=D("div","ow-control-buttons"),this.root.append(this.zone,this.buttonBox),e.append(this.root),this.zone.addEventListener("pointerdown",n=>this.stickDown(n)),this.zone.addEventListener("pointermove",n=>this.stickMove(n));for(let n of["pointerup","pointercancel","lostpointercapture"])this.zone.addEventListener(n,a=>this.stickUp(a));this.root.addEventListener("contextmenu",n=>n.preventDefault())}setLayout(e){this.layout=Ze(e);let o=this.buttons;this.buttons=new Map,(this.layout?.buttons??[]).forEach((r,n)=>{let a=o.get(r.id)??this.button(r.id);o.delete(r.id),a.className=`ow-control-btn ow-control-btn-${n}`,a.classList.toggle("ow-held",[...this.held.values()].includes(r.id)),a.textContent=r.label,a.isConnected||this.buttonBox.append(a),this.buttons.set(r.id,a)});for(let[r,n]of o){for(let[a,i]of this.held)i===r&&this.letGo(a);n.remove()}this.zone.hidden=!this.layout?.stick,this.zone.classList.toggle("ow-stick-corner",this.layout?.zone==="corner"),this.zone.hidden&&this.stickPointer!==null&&this.letGo(this.stickPointer),this.render(),this.onLayout()}setLook(e){ae(this.root,Rt,e)}reservedBoxes(){if(this.root.hidden)return this.blocked&&this.layout&&this.touch&&!this.keyboard?this.placed:{stick:null,buttons:null};let e=this.zone.hidden?null:At(this.base),o=null;for(let r of this.buttons.values()){let n=At(r);!n.width||!n.height||(o=o?yo(o,n):n)}return this.placed={stick:e,buttons:o},this.placed}setTouch(e){this.touch=e,this.render()}setKeyboard(e){this.keyboard=e,this.render()}setBlocked(e){this.blocked=e,this.render()}render(){let e=!!this.layout&&this.touch&&!this.blocked&&!this.keyboard;this.root.hidden!==!e&&(e||this.reset(),this.root.hidden=!e,this.onLayout())}reset(){for(let e of[...this.held.keys()])this.letGo(e);this.stickPointer!==null&&this.letGo(this.stickPointer),this.endStick()}letGo(e){e===this.stickPointer&&this.endStick();let o=this.held.get(e);this.held.delete(e),o!==void 0&&![...this.held.values()].includes(o)&&this.buttons.get(o)?.classList.remove("ow-held");let r=this.fingers.get(e);this.fingers.delete(e),r&&wo(this.parent,e,r),this.changed()}button(e){let o=D("button","ow-control-btn");o.type="button",o.tabIndex=-1,o.addEventListener("pointerdown",n=>{n.preventDefault(),Mt(o,n.pointerId),o.classList.add("ow-held"),this.held.set(n.pointerId,e),this.report.press(e),this.fingers.set(n.pointerId,{x:n.clientX,y:n.clientY}),this.changed()}),o.addEventListener("pointermove",n=>{this.held.get(n.pointerId)===e&&this.fingers.set(n.pointerId,{x:n.clientX,y:n.clientY})});let r=n=>{this.held.get(n.pointerId)===e&&(this.held.delete(n.pointerId),this.fingers.delete(n.pointerId),[...this.held.values()].includes(e)||o.classList.remove("ow-held"),this.changed())};for(let n of["pointerup","pointercancel","lostpointercapture"])o.addEventListener(n,a=>r(a));return o}stickDown(e){if(this.stickPointer!==null)return;e.preventDefault(),Mt(this.zone,e.pointerId),this.stickPointer=e.pointerId,this.fingers.set(e.pointerId,{x:e.clientX,y:e.clientY});let o=this.zone.getBoundingClientRect(),r=this.base.getBoundingClientRect(),n=$+8;this.center={x:Math.min(Math.max(e.clientX,o.left+n),o.right-n),y:Math.min(Math.max(e.clientY,o.top+n),o.bottom-n)},this.base.style.transform=`translate(${this.center.x-(r.left+r.width/2)}px, ${this.center.y-(r.top+r.height/2)}px)`,this.base.classList.add("ow-active"),this.stickMove(e)}stickMove(e){if(e.pointerId!==this.stickPointer)return;this.fingers.set(e.pointerId,{x:e.clientX,y:e.clientY});let o=e.clientX-this.center.x,r=e.clientY-this.center.y,n=Math.hypot(o,r);n>$&&(o=o/n*$,r=r/n*$),this.knob.style.transform=`translate(${o}px, ${r}px)`;let a=Math.min(n,$)/$,i=a<Ae?0:(a-Ae)/(1-Ae)/(a||1);this.x=Lt(o/$*i),this.y=Lt(r/$*i),this.changed()}stickUp(e){e.pointerId===this.stickPointer&&(this.fingers.delete(e.pointerId),this.endStick())}endStick(){this.stickPointer=null,this.x=0,this.y=0,this.base.classList.remove("ow-active"),this.base.style.transform="",this.knob.style.transform="",this.changed()}changed(){this.queued||(this.queued=requestAnimationFrame(()=>{this.queued=0;let{buttons:e,owed:o}=this.report.take(this.held.values()),r={x:this.x,y:this.y,buttons:e};o&&this.changed();let n=JSON.stringify(r);n!==this.sent&&(this.sent=n,this.send(r))}))}};function wo(t,e,o){let r=D("div","ow-tap-shield");r.style.left=`${o.x-Le/2}px`,r.style.top=`${o.y-Le/2}px`,r.style.width=r.style.height=`${Le}px`,t.append(r);let n=setTimeout(()=>r.remove(),bo),a=()=>{clearTimeout(n),n=setTimeout(()=>r.remove(),fo)};for(let i of["pointerup","pointercancel","lostpointercapture"])r.addEventListener(i,s=>s.pointerId===e&&a());r.addEventListener("contextmenu",i=>i.preventDefault());try{r.setPointerCapture(e)}catch{a()}}function Mt(t,e){try{t.setPointerCapture(e)}catch{}}function At(t){let e=t.getBoundingClientRect(),o=getComputedStyle(t).transform;if(!o||o==="none")return e;let r=new DOMMatrixReadOnly(o);if(r.b||r.c||!r.a||!r.d)return e;let n=e.width/Math.abs(r.a),a=e.height/Math.abs(r.d),i=e.left+e.width/2-r.e,s=e.top+e.height/2-r.f;return{left:i-n/2,top:s-a/2,width:n,height:a}}function yo(t,e){let o=Math.min(t.left,e.left),r=Math.min(t.top,e.top);return{left:o,top:r,width:Math.max(t.left+t.width,e.left+e.width)-o,height:Math.max(t.top+t.height,e.top+e.height)-r}}function Lt(t){return Math.round(t*1e3)/1e3}function D(t,e,o){let r=document.createElement(t);return r.className=e,o!==void 0&&(r.textContent=o),r}function Y(t,e){let o=[];for(let{kind:r,box:n}of e){if(!n||!(n.width>0)||!(n.height>0))continue;let a=Math.max(0,n.left-t.left),i=Math.max(0,n.top-t.top),s=Math.min(t.width,n.left+n.width-t.left),d=Math.min(t.height,n.top+n.height-t.top);if(!(s-a>.01&&d-i>.01))continue;let c=Math.floor(a+.01),p=Math.floor(i+.01);o.push({kind:r,x:c,y:p,w:Math.ceil(s-.01)-c,h:Math.ceil(d-.01)-p})}return o}var se=class{measure;send;nextFrame;queued=!1;sent=null;constructor(e,o,r=n=>requestAnimationFrame(n)){this.measure=e,this.send=o,this.nextFrame=r}changed(){this.queued||(this.queued=!0,this.nextFrame(()=>{this.queued=!1;let e=this.measure();if(!e)return;let o=JSON.stringify(e);o!==this.sent&&(this.sent=o,this.send(e))}))}resend(){this.sent=null,this.changed()}};var $t=t=>Math.max(0,Math.ceil(t/1e3)),$e=t=>{let e=t.slice(0,2).map(o=>o.name);return t.length>2?`${e.join(", ")} +${t.length-2}`:e.join(", ")};function vo(t){let{you:e,host:o,kind:r,match:n,now:a}=t,i=[...t.players].sort((l,f)=>l.id===e?-1:f.id===e?1:l.id===o?-1:f.id===o?1:l.name.localeCompare(f.name)).map(l=>({id:l.id,name:l.name,ready:!!l.ready,host:l.id===o,you:l.id===e,away:l.connected===!1,idle:l.connected!==!1&&!!l.idle})),s=t.players.filter(l=>l.connected!==!1),d=t.players.find(l=>l.id===e),c=o===e&&n.phase==="lobby",p=t.schema.map(l=>({id:l.id,label:l.label,value:et(l,t.written),options:l.options,editable:c})),x={n:s.filter(l=>l.ready||r!=="public"&&l.id===o).length,of:s.length},u={surface:"none",rows:i,count:`${t.players.length} / ${t.max}`,ready:x,status:"",action:{kind:"none",label:"",disabled:!0},settings:p,seconds:null},E=n.participants?.includes(e)??!1,q=o===e&&r!=="public";if(n.phase==="starting"){if(!E)return{...u,surface:"watching",status:"Watching"};let l=q?{kind:"stop",label:"Stop",disabled:!1}:{kind:"unready",label:"Not ready",disabled:!1};return t.ownCountdown?{...u,surface:"countdown",action:l,seconds:null,status:"Get ready"}:{...u,surface:"countdown",action:l,seconds:Math.max(1,$t((n.startsAt??a)-a)),status:"Get ready"}}if(n.phase==="playing"){if(n.paused){let l=s.filter(f=>n.participants?.includes(f.id)).length;return n.paused.reason==="host"?{...u,surface:"paused",status:"Paused"}:{...u,surface:"paused",seconds:$t(n.paused.since+P.matchAbandonMs-a),status:`Waiting for players \xB7 ${l} / ${n.min}`}}return E?u:{...u,surface:"watching",status:"Watching"}}let b=s.filter(l=>!l.ready&&(r==="public"||l.id!==o));if(u.surface="lobby",q){let l=s.length<n.min;return u.action={kind:"start",label:"Start",disabled:l||b.length>0},u.status=l?`Need ${n.min} players`:b.length?`Waiting for ${$e(b)}`:"",u}if(u.action={kind:d?.ready?"unready":"ready",label:d?.ready?"Not ready":"Ready",disabled:!1},r==="public")s.length<n.min?u.status=`Need ${n.min} players`:n.waitUntil!==void 0&&b.length?u.status=b.some(l=>l.id===e)?"Waiting for you":`Waiting for ${$e(b)}`:u.status=`${s.length-b.length} / ${s.length} ready`;else{let l=b.filter(f=>f.id!==e);u.status=d?.ready?l.length?`Waiting for ${$e(l)}`:`Waiting for ${t.players.find(f=>f.id===o)?.name??"the host"}`:""}return u}function h(t,e="",o){let r=document.createElement(t);return e&&(r.className=e),o!==void 0&&(r.textContent=o),r}var le=class{mode=null;ownCountdown=!1;targetOk=!1;targetTimer=0;lastKey=-1/0;state=null;schema=[];timer=0;opts;root;card;title;count;list;settingsBox;status;action;invite;bar;barFaces;barStatus;barAction;countdown;numeral;cancel;pause;pauseStatus;pauseTimer;chip;last=null;lastNumeral=-1;listSignature="";settingsSignature="";faceSignature="";constructor(e,o){this.opts=o,this.root=h("div","ow-lobby"),this.root.hidden=!0;for(let s of["pointerdown","mousedown"])this.root.addEventListener(s,d=>d.preventDefault());this.card=h("section","ow-lobby-card"),this.card.setAttribute("aria-label","Lobby");let r=h("header","ow-lobby-head");this.title=h("h2","","Lobby"),this.count=h("span","ow-lobby-count"),r.append(this.title,this.count),this.list=h("ul","ow-lobby-players"),this.settingsBox=h("div","ow-lobby-settings"),this.status=h("p","ow-lobby-status"),this.status.setAttribute("role","status"),this.action=this.button("ow-btn ow-btn-primary ow-lobby-action",()=>this.press()),this.invite=this.button("ow-btn ow-lobby-invite",()=>this.opts.onInvite()),this.invite.textContent="Invite";let n=h("div","ow-lobby-actions");n.append(this.action,this.invite),this.card.append(r,this.list,this.settingsBox,this.status,n),this.bar=h("div","ow-lobby-bar"),this.barFaces=h("span","ow-lobby-faces"),this.barStatus=h("span","ow-lobby-bar-status"),this.barStatus.setAttribute("role","status"),this.barAction=this.button("ow-btn ow-btn-primary ow-lobby-action",()=>this.press()),this.bar.append(this.barFaces,this.barStatus,this.barAction),this.countdown=h("div","ow-lobby-countdown"),this.numeral=h("b"),this.numeral.setAttribute("aria-hidden","true");let a=h("span","","Get ready");a.setAttribute("aria-hidden","true"),this.cancel=this.button("ow-btn ow-lobby-cancel",()=>this.press()),this.countdown.append(this.numeral,a,this.cancel),this.pause=h("div","ow-lobby-pause");let i=h("div","ow-lobby-pause-box");this.pauseStatus=h("p","ow-lobby-pause-status"),this.pauseStatus.setAttribute("role","status"),this.pauseTimer=h("p","ow-lobby-pause-timer"),i.append(this.pauseStatus,this.pauseTimer),this.pause.append(i),this.chip=h("div","ow-lobby-chip"),this.chip.setAttribute("role","status"),this.root.append(this.card,this.bar,this.countdown,this.pause,this.chip),e.append(this.root)}setSchema(e){this.schema=e,this.render()}enable(e,o={}){this.mode=e,this.ownCountdown=o.ownCountdown===!0,this.root.dataset.mode=e??"",e||this.reset(),this.render()}setLook(e){ae(this.root,zt,e)}reservedBox(){if(this.root.hidden)return null;let e=!this.countdown.hidden&&this.countdown.classList.contains("ow-lobby-countdown-bare"),o=this.bar.hidden?e&&!this.cancel.hidden?this.cancel:null:this.bar;return o?o.getBoundingClientRect():null}link(e){let o=!this.root.hidden&&(this.last?.surface==="lobby"||this.last?.surface==="countdown"),r=this.pressable()?.getBoundingClientRect()??null;if(!(r!==null&&r.left>=e.left&&r.top>=e.top&&r.left+r.width<=e.left+e.width&&r.top+r.height<=e.top+e.height))return{keys:o,button:null,cover:null};let[a]=Y(e,[{kind:"lobby",box:r}]),[i]=this.mode==="bar"?Y(e,[{kind:"lobby",box:this.bar.getBoundingClientRect()}]):[{x:0,y:0,w:e.width,h:e.height}];return!a||!i?{keys:o,button:null,cover:null}:{keys:o,button:{x:a.x,y:a.y,w:a.w,h:a.h},cover:{x:i.x,y:i.y,w:i.w,h:i.h}}}setTarget(e,o){window.clearTimeout(this.targetTimer),e&&(this.targetTimer=window.setTimeout(()=>this.setTarget(!1,!1),1600)),this.targetOk!==e&&(this.targetOk=e,this.applyTarget()),this.pressable()?.classList.toggle("ow-lobby-hover",e&&o)}pressKey(e=performance.now()){this.pressable()===null||e-this.lastKey<ft||(this.lastKey=e,this.press())}pressTarget(){this.pressable()&&this.press()}setKeyMark(e){this.root.classList.toggle("ow-lobby-keys",e)}pressable(){let e=this.last;return this.root.hidden||!e||e.surface!=="lobby"||e.action.kind==="none"||e.action.disabled?null:this.mode==="card"?this.action:this.barAction}applyTarget(){let e=this.targetOk&&this.pressable()!==null;if(this.root.classList.toggle("ow-lobby-through",e),!e)for(let o of[this.action,this.barAction])o.classList.remove("ow-lobby-hover")}setRoom(e,o=0){if(!e)return this.reset();this.state={you:e.you,host:e.host,kind:e.room.startsWith("private:")?"private":e.room.startsWith("room:")?"named":"public",max:Math.max(o,e.players.length),players:e.players.map(r=>({...r})),match:e.match??{phase:"lobby",n:0,min:1},written:e.state?.[V]},this.render()}handle(e){let o=this.state;if(o){switch(e.t){case"join":o.players=[...o.players.filter(r=>r.id!==e.player.id),{...e.player}];break;case"leave":o.players=o.players.filter(r=>r.id!==e.id);break;case"away":o.players=o.players.map(r=>r.id===e.id?{...r,connected:!1}:r);break;case"back":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{connected:n,...a}=r;return a});break;case"ready":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{ready:n,...a}=r;return e.ready?{...a,ready:!0}:a});break;case"unready":o.players=o.players.map(({ready:r,...n})=>n);break;case"host":o.host=e.id;break;case"idle":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{idle:n,...a}=r;return e.idle?{...a,idle:!0}:a});break;case"name":o.players=o.players.map(r=>r.id===e.id?{...r,name:e.name}:r);break;case"match":o.match=e.match;break;case"state":if(e.k!==V)return;o.written=e.v;break;default:return}this.render()}}chooseSetting(e,o){let r=this.state,n=this.schema.find(i=>i.id===e);if(!r||!n||!n.options.some(i=>i.value===o))return null;let a={...r.written!==null&&typeof r.written=="object"?r.written:{},[e]:o};return r.written=a,this.render(),a}setReadyLocal(e){let o=this.state?.players.find(r=>r.id===this.state?.you);o&&(e?o.ready=!0:delete o.ready,this.render())}button(e,o){let r=h("button",e);return r.type="button",r.addEventListener("pointerdown",n=>n.preventDefault()),r.addEventListener("click",o),r}press(){let e=this.last?.action.kind;e==="start"?this.opts.onStart():e==="stop"?this.opts.onStop():e==="ready"?(this.setReadyLocal(!0),this.opts.onReady(!0)):e==="unready"&&(this.setReadyLocal(!1),this.opts.onReady(!1)),this.opts.onPressed?.()}reset(){this.state=null,this.last=null,this.setTarget(!1,!1),window.clearInterval(this.timer),this.timer=0,this.root.hidden=!0,this.opts.onLayout?.()}render(){this.draw(),this.opts.onLayout?.()}draw(){if(!this.mode||!this.state){this.root.hidden=!0;return}let e=vo({...this.state,schema:this.schema,now:this.opts.now(),ownCountdown:this.ownCountdown});this.last=e;let o=e.surface==="lobby";if(this.root.hidden=e.surface==="none",this.card.hidden=!(o&&this.mode==="card"),this.bar.hidden=!(o&&this.mode==="bar"),this.countdown.hidden=e.surface!=="countdown",this.countdown.classList.toggle("ow-lobby-countdown-bare",e.surface==="countdown"&&e.seconds===null),this.pause.hidden=e.surface!=="paused",this.chip.hidden=e.surface!=="watching",this.root.classList.toggle("ow-lobby-dim",o&&this.mode==="card"),o&&this.mode==="card"&&this.renderCard(e),o&&this.mode==="bar"&&this.renderBar(e),this.applyTarget(),e.surface==="countdown"&&e.seconds!==null&&e.seconds!==this.lastNumeral&&(this.lastNumeral=e.seconds,this.numeral.textContent=String(e.seconds),this.numeral.style.animation="none",this.numeral.offsetWidth,this.numeral.style.animation=""),e.surface==="countdown"&&(this.cancel.textContent=e.action.label),e.surface!=="countdown"&&(this.lastNumeral=-1),e.surface==="paused"&&(this.pauseStatus.textContent=e.status,this.pauseTimer.textContent=e.seconds!==null?`Ends in ${ko(e.seconds)}`:""),e.surface==="watching"){let[n,...a]=e.status.split(" \xB7 "),i=h("span","ow-lobby-chip-more",a.length?` \xB7 ${a.join(" \xB7 ")}`:"");this.chip.replaceChildren(n,i)}let r=e.seconds!==null;r&&!this.timer?this.timer=window.setInterval(()=>this.render(),250):!r&&this.timer&&(window.clearInterval(this.timer),this.timer=0)}renderCard(e){this.count.textContent=e.count,this.settingsBox.hidden=e.settings.length===0,this.status.textContent=e.status,this.status.hidden=e.status==="",this.setAction(this.action,e);let o=JSON.stringify(e.settings);o!==this.settingsSignature&&(this.settingsSignature=o,this.settingsBox.replaceChildren(...e.settings.map(n=>this.settingRow(n))));let r=JSON.stringify(e.rows);r!==this.listSignature&&(this.listSignature=r,this.list.replaceChildren(...e.rows.map(n=>{let a=h("li",n.away||n.idle?"ow-lobby-away":n.ready?"ow-lobby-ready":""),i=h("img","ow-headshot");i.src=`/avatar/${encodeURIComponent(n.id)}/head.svg`,i.alt="";let s=h("span","ow-lobby-name",n.name),d=[n.away?"Reconnecting":n.idle?"Idle":"",n.you?"You":"",n.host?"Host":""].filter(Boolean).join(" \xB7 ");return a.append(i,s),d&&a.append(h("span","ow-player-notes",d)),a.append(h("span",`ow-lobby-check${n.ready?" ow-lobby-check-on":""}`,n.ready?"Ready":"")),a})))}settingRow(e){let o=h("div","ow-lobby-setting");if(o.append(h("span","ow-lobby-setting-label",e.label)),!e.editable)return o.append(h("span","ow-lobby-setting-value",e.options.find(n=>n.value===e.value)?.label??String(e.value))),o;let r=h("div","ow-segments");r.setAttribute("role","radiogroup"),r.setAttribute("aria-label",e.label);for(let n of e.options){let a=this.button(`ow-segment${n.value===e.value?" ow-segment-on":""}`,()=>this.opts.onSetting(e.id,n.value));a.textContent=n.label,a.setAttribute("role","radio"),a.setAttribute("aria-checked",String(n.value===e.value)),r.append(a)}return o.append(r),o}renderBar(e){this.barStatus.textContent=e.status||`${e.ready.n} / ${e.ready.of} ready`,this.setAction(this.barAction,e);let o=JSON.stringify(e.rows.slice(0,5).map(r=>[r.id,r.ready]));o!==this.faceSignature&&(this.faceSignature=o,this.barFaces.replaceChildren(...e.rows.slice(0,5).map(r=>{let n=h("img",`ow-headshot${r.ready?" ow-lobby-face-ready":""}`);return n.src=`/avatar/${encodeURIComponent(r.id)}/head.svg`,n.alt="",n})))}setAction(e,o){e.hidden=o.action.kind==="none",e.textContent=o.action.label,e.disabled=o.action.disabled,e.setAttribute("aria-keyshortcuts","Enter"),e.classList.toggle("ow-btn-primary",o.action.kind!=="unready")}};function ko(t){return`${Math.floor(t/60)}:${String(t%60).padStart(2,"0")}`}var Ce=t=>`ow:resume:${t}`;function I(t,e){try{e?sessionStorage.setItem(Ce(t),JSON.stringify({...e,at:Date.now()})):sessionStorage.removeItem(Ce(t))}catch{}}function Ct(t){try{let e=sessionStorage.getItem(Ce(t));if(!e)return null;let o=performance.getEntriesByType("navigation")[0];if(o&&o.type!=="reload"&&o.type!=="back_forward")return pe(t);let r=JSON.parse(e);return typeof r.key!="string"||typeof r.rejoin!="string"||typeof r.at!="number"||Date.now()-r.at>18e4||Number(r.rejoin.split(".")[0])*1e3<Date.now()?pe(t):{key:r.key,rejoin:r.rejoin}}catch{return null}}var So=t=>`ow:own-server:${t}`;function Tt(t,e){try{sessionStorage.setItem(So(t),e)}catch{}}function pe(t){return I(t,null),null}var de=class extends Error{constructor(o,r=0,n=0,a=""){super(o);this.status=r;this.retryAfterMs=n;this.code=a;this.name="RequestError"}status;retryAfterMs;code;get retryable(){return this.status===0||this.status===408||this.status===429||this.status>=500}};var ce=class{constructor(e=48*1024){this.max=e}max;used=0;async run(e,o){let r=new TextEncoder().encode(e).byteLength;if(this.used+r>this.max)throw new de("Progress is waiting to sync when you return to the game.");this.used+=r;try{return await o()}finally{this.used-=r}}};var Te=/^[2-9]$/.test(new URLSearchParams(location.search).get("player")??"")?new URLSearchParams(location.search).get("player"):null;var zo=null;function Dt(){return zo?.n??null}var Mr=new ce;var Ot=[300,700,1500,3e3,5e3,8e3],Ro=9e4,Eo=1e4,It=()=>Array.from(crypto.getRandomValues(new Uint8Array(10)),t=>"abcdefghijklmnopqrstuvwxyz0123456789"[t%36]).join(""),Bt=It();function jt(){Bt=It()}var _t=null;var Nt=!1;function Gt(t){Nt=t}var Po=5e4,Mo=4e3,ge=class{ws=null;key=null;rejoin=null;you="";closed=!1;attempt=0;droppedAt=0;sleeping=!1;lastHeard=0;heardCount=0;pingAt=0;hintedHidden=!1;pingTimer=0;watchTimer=0;retryTimer=0;page=Bt;slug;options;callbacks;onVisible=()=>{this.hint(),document.visibilityState==="visible"&&this.wake()};onOnline=()=>this.wake();onShow=e=>e.persisted&&this.wake();onHide=()=>this.hint();constructor(e,o,r){this.slug=e,this.options=o,this.callbacks=r,this.key=o.key??null,this.rejoin=o.rejoin??null,document.addEventListener("visibilitychange",this.onVisible),addEventListener("online",this.onOnline),addEventListener("pageshow",this.onShow),addEventListener("pagehide",this.onHide)}join(){return new Promise((e,o)=>this.open(e,o))}send(e){this.ws?.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(e))}hint(){let e=document.visibilityState==="hidden";e===this.hintedHidden||this.ws?.readyState!==WebSocket.OPEN||(this.hintedHidden=e,this.send({t:"vis",hidden:e}))}ping(){let e=this.ws;e?.readyState===WebSocket.OPEN&&(this.pingAt&&Date.now()-this.pingAt<5e3||(this.pingAt=Date.now(),e.send(Se)))}close(){this.closed=!0,I(this.slug,null),this.dispose(),this.ws?.close(1e3)}reload(){return this.closed=!0,this.dispose(),this.ws?.close(nt,"Updating"),this.key?.startsWith("pub:")&&this.rejoin?{key:this.key,rejoin:this.rejoin}:null}open(e,o){this.retryTimer=0;let r=new URL(`/api/games/${this.slug}/rooms/connect`,location.href);r.protocol=location.protocol==="https:"?"wss:":"ws:",this.key?(r.searchParams.set("key",this.key),this.rejoin&&r.searchParams.set("rejoin",this.rejoin)):this.options.server?(r.searchParams.set("server",this.options.server),this.options.private&&r.searchParams.set("own","1")):this.options.name?r.searchParams.set("name",this.options.name):(this.options.mode&&r.searchParams.set("mode",this.options.mode),this.options.follow&&r.searchParams.set("follow",this.options.follow)),this.options.maxPlayers&&r.searchParams.set("max",String(this.options.maxPlayers)),this.options.minPlayers&&r.searchParams.set("min",String(this.options.minPlayers)),this.options.countdown!==void 0&&r.searchParams.set("countdown",String(this.options.countdown)),this.options.teams&&r.searchParams.set("teams",String(this.options.teams)),this.options.ranked&&r.searchParams.set("ranked","1"),Te&&r.searchParams.set("devplayer",Te);let n=Dt();n&&r.searchParams.set("tester",n),r.searchParams.set("page",this.page),this.options.build&&r.searchParams.set("build",this.options.build),_t&&r.searchParams.set("pass",_t),Nt&&r.searchParams.set("demo","1");let a=new WebSocket(r);this.ws=a,this.lastHeard=Date.now();let i=!1;a.onopen=()=>{this.lastHeard=Date.now(),window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),this.pingTimer=window.setInterval(()=>a.readyState===WebSocket.OPEN&&this.ping(),Eo),this.watchTimer=window.setInterval(()=>{a===this.ws&&a.readyState===WebSocket.OPEN&&Date.now()-this.lastHeard>Po&&this.lost(a)},5e3)},a.onmessage=c=>{this.lastHeard=Date.now(),this.heardCount++;let p;try{p=JSON.parse(c.data)}catch{return}if(p.t==="pong"){this.pingAt&&this.callbacks.onRtt?.(Date.now()-this.pingAt),this.pingAt=0;return}if(p.t==="welcome"&&(p.rejoin&&(this.rejoin=p.rejoin),delete p.rejoin,p.room.startsWith("pub:")&&this.rejoin&&I(this.slug,{key:p.room,rejoin:this.rejoin})),p.t==="leave"&&p.kicked&&p.id===this.you){this.close(),this.finish("kicked");return}if(p.t==="welcome"&&(this.hintedHidden=!1,this.hint()),p.t==="welcome"&&!i&&(i=!0,this.key=p.room,this.you=p.you,this.attempt=0,this.droppedAt&&(this.droppedAt=0,this.callbacks.onConnection?.(!0)),e)){let{t:x,...u}=p;e(u),e=void 0;return}this.callbacks.onMessage(p)};let s=!1,d=c=>{if(!s&&(s=!0,window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),!(this.closed||a!==this.ws))){if(c.code===tt)return this.finish("replaced");if(c.code===rt&&i&&document.visibilityState==="hidden"){this.sleeping=!0,this.droppedAt||(this.droppedAt=Date.now(),this.callbacks.onConnection?.(!1));return}if(c.code===ot){if(i||!o)return this.finish("kicked");this.closed=!0,this.dispose(),I(this.slug,null),o(Object.assign(new Error("You were removed from this server."),{kicked:!0}));return}if(!i&&o){this.closed=!0,this.dispose(),o(new Error(this.options.name||this.options.server?"Could not join that server. It may be full.":"Could not join a server. Try again soon."));return}this.retry()}};a.onclose=d,a.onerror=()=>{window.setTimeout(()=>{a.readyState===WebSocket.CLOSED&&d({code:1006})},1e3)}}retry(){if(this.closed)return;let e=Date.now();if(this.droppedAt||(this.droppedAt=e,this.callbacks.onConnection?.(!1)),e-this.droppedAt>Ro)return this.finish("disconnected");if(this.retryTimer)return;let o=Ot[Math.min(this.attempt++,Ot.length-1)]*(.5+Math.random());this.retryTimer=window.setTimeout(()=>{this.retryTimer=0,this.closed||this.open()},o)}lost(e){if(!(e!==this.ws||this.closed)){e.onopen=e.onmessage=e.onclose=e.onerror=null,window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer);try{e.close()}catch{}this.retry()}}wake(){if(this.closed)return;if(this.sleeping){this.sleeping=!1,this.droppedAt=Date.now(),this.attempt=0,this.open();return}let e=this.ws;if(!e||e.readyState===WebSocket.CLOSING||e.readyState===WebSocket.CLOSED){this.retryTimer&&(window.clearTimeout(this.retryTimer),this.retryTimer=0,this.open());return}if(e.readyState!==WebSocket.OPEN)return;let o=this.heardCount;try{e.send(Se)}catch{return this.lost(e)}window.setTimeout(()=>e===this.ws&&!this.closed&&this.heardCount===o&&this.lost(e),Mo)}dispose(){window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),window.clearTimeout(this.retryTimer),this.retryTimer=0,document.removeEventListener("visibilitychange",this.onVisible),removeEventListener("online",this.onOnline),removeEventListener("pageshow",this.onShow),removeEventListener("pagehide",this.onHide)}finish(e){this.closed=!0,this.dispose(),I(this.slug,null),this.callbacks.onClose(e)}};var Ut=`:root {
|
|
2
4
|
color-scheme: light;
|
|
3
5
|
/* Site pages: as wide as this at most, with gutters that grow with the window. */
|
|
4
6
|
--page: 1440px;
|
|
@@ -57,9 +59,8 @@
|
|
|
57
59
|
--play-fill-hover: #ff8366;
|
|
58
60
|
--play-ink: #121418;
|
|
59
61
|
--play-text: var(--ok);
|
|
60
|
-
/* Live: players in a game right now. The store's signal colour: a dot, a count
|
|
62
|
+
/* Live: players in a game right now. The store's signal colour: a dot, a count. */
|
|
61
63
|
--live: #3ddc84;
|
|
62
|
-
--live-ink: #0b2a17;
|
|
63
64
|
--live-text: #12813f;
|
|
64
65
|
/* The phone tab bar (and popups opened from it). */
|
|
65
66
|
--dock-bg: var(--bar);
|
|
@@ -383,12 +384,33 @@ h3 {
|
|
|
383
384
|
color: var(--danger);
|
|
384
385
|
}
|
|
385
386
|
|
|
386
|
-
.
|
|
387
|
+
/* (A row's buttons are always this size: a list reads the same whatever its row can do.) */
|
|
388
|
+
.btn-small,
|
|
389
|
+
.row-actions .btn {
|
|
387
390
|
min-height: 32px;
|
|
388
391
|
padding: 0 12px;
|
|
389
392
|
font-size: 13px;
|
|
390
393
|
}
|
|
391
394
|
|
|
395
|
+
/* Fingers: small buttons and links stay easy to hit (padding on the links, which doesn't move anything around them). */
|
|
396
|
+
@media (pointer: coarse) {
|
|
397
|
+
.btn-small,
|
|
398
|
+
.row-actions .btn {
|
|
399
|
+
min-height: 40px;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.see-all,
|
|
403
|
+
.clear-search {
|
|
404
|
+
margin: -10px 0;
|
|
405
|
+
padding: 10px 0;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.label-row a,
|
|
409
|
+
.auth-switch a {
|
|
410
|
+
padding: 10px 4px;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
392
414
|
/* A plain file picker (a form that posts its file, like Upload files' Cover): its button is a small .btn. */
|
|
393
415
|
input[type='file'] {
|
|
394
416
|
max-width: 100%;
|
|
@@ -438,10 +460,14 @@ input[type='file']::file-selector-button:hover {
|
|
|
438
460
|
|
|
439
461
|
.link-btn {
|
|
440
462
|
padding: 6px 10px;
|
|
463
|
+
border: 0;
|
|
464
|
+
background: none;
|
|
441
465
|
color: var(--text);
|
|
466
|
+
font-family: inherit;
|
|
442
467
|
font-weight: 600;
|
|
443
468
|
font-size: 14px;
|
|
444
469
|
text-decoration: none;
|
|
470
|
+
cursor: pointer;
|
|
445
471
|
}
|
|
446
472
|
|
|
447
473
|
.link-btn:hover {
|
|
@@ -461,6 +487,7 @@ input[type='text'],
|
|
|
461
487
|
input[type='email'],
|
|
462
488
|
input[type='password'],
|
|
463
489
|
input[type='search'],
|
|
490
|
+
input[type='number'],
|
|
464
491
|
input:not([type]),
|
|
465
492
|
select,
|
|
466
493
|
textarea {
|
|
@@ -1268,6 +1295,15 @@ button.icon-btn:hover {
|
|
|
1268
1295
|
background: var(--accent);
|
|
1269
1296
|
}
|
|
1270
1297
|
|
|
1298
|
+
/* The chat is open over the page: one tab is lit, Chat. */
|
|
1299
|
+
.tabbar:has(> button[aria-expanded='true']) > a[aria-current='page'] {
|
|
1300
|
+
color: var(--dock-muted);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
.tabbar:has(> button[aria-expanded='true']) > a[aria-current='page']::before {
|
|
1304
|
+
content: none;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1271
1307
|
.tabbar > a:focus-visible,
|
|
1272
1308
|
.tabbar > button:focus-visible {
|
|
1273
1309
|
outline: 2px solid var(--accent);
|
|
@@ -1528,7 +1564,6 @@ body:has(.tabbar) .footer-inner {
|
|
|
1528
1564
|
color: var(--muted);
|
|
1529
1565
|
font-size: 14px;
|
|
1530
1566
|
font-weight: 600;
|
|
1531
|
-
font-variant-numeric: tabular-nums;
|
|
1532
1567
|
}
|
|
1533
1568
|
|
|
1534
1569
|
.see-all {
|
|
@@ -1771,6 +1806,21 @@ body:has(.tabbar) .footer-inner {
|
|
|
1771
1806
|
left: 0;
|
|
1772
1807
|
}
|
|
1773
1808
|
|
|
1809
|
+
@media (max-width: 560px) {
|
|
1810
|
+
.storenav {
|
|
1811
|
+
flex-wrap: wrap;
|
|
1812
|
+
height: auto;
|
|
1813
|
+
}
|
|
1814
|
+
.storenav-links {
|
|
1815
|
+
flex: 1 1 100%;
|
|
1816
|
+
height: 46px;
|
|
1817
|
+
}
|
|
1818
|
+
.storenav-filters,
|
|
1819
|
+
.storenav-random {
|
|
1820
|
+
height: 40px;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1774
1824
|
.storenav-filters {
|
|
1775
1825
|
display: flex;
|
|
1776
1826
|
}
|
|
@@ -2423,17 +2473,6 @@ body:has(.tabbar) .footer-inner {
|
|
|
2423
2473
|
background: var(--live);
|
|
2424
2474
|
}
|
|
2425
2475
|
|
|
2426
|
-
.btn.btn-live {
|
|
2427
|
-
border-color: transparent;
|
|
2428
|
-
background: var(--live);
|
|
2429
|
-
color: var(--live-ink);
|
|
2430
|
-
font-weight: 700;
|
|
2431
|
-
}
|
|
2432
|
-
|
|
2433
|
-
.btn.btn-live:hover {
|
|
2434
|
-
background: color-mix(in srgb, var(--live) 85%, #fff);
|
|
2435
|
-
}
|
|
2436
|
-
|
|
2437
2476
|
/* Every game: its title (with See all on home, Clear on a search), the filters that are on, and the grid. */
|
|
2438
2477
|
.browse-head {
|
|
2439
2478
|
display: flex;
|
|
@@ -2898,6 +2937,14 @@ body:has(.tabbar) .footer-inner {
|
|
|
2898
2937
|
padding: 96px 16px;
|
|
2899
2938
|
}
|
|
2900
2939
|
|
|
2940
|
+
.lib-empty-actions {
|
|
2941
|
+
display: flex;
|
|
2942
|
+
flex-wrap: wrap;
|
|
2943
|
+
justify-content: center;
|
|
2944
|
+
gap: 10px;
|
|
2945
|
+
margin-top: 20px;
|
|
2946
|
+
}
|
|
2947
|
+
|
|
2901
2948
|
/* A repo whose first deploy failed, in the side: its square says so. */
|
|
2902
2949
|
.lib-icon.mine-failed {
|
|
2903
2950
|
color: var(--danger);
|
|
@@ -2950,11 +2997,15 @@ body:has(.tabbar) .footer-inner {
|
|
|
2950
2997
|
height: clamp(22px, 10.4cqi, 36px);
|
|
2951
2998
|
border-radius: 5px;
|
|
2952
2999
|
object-fit: cover;
|
|
2953
|
-
background: var(--fill);
|
|
2954
3000
|
font-size: 12px;
|
|
2955
3001
|
font-weight: 800;
|
|
2956
3002
|
}
|
|
2957
3003
|
|
|
3004
|
+
/* (A letter's square keeps its game's colour.) */
|
|
3005
|
+
.lib-icon:not(.gcard-letter) {
|
|
3006
|
+
background: var(--fill);
|
|
3007
|
+
}
|
|
3008
|
+
|
|
2958
3009
|
@container side (min-width: 320px) {
|
|
2959
3010
|
.lib-list a {
|
|
2960
3011
|
min-height: 42px;
|
|
@@ -3683,6 +3734,11 @@ body:has(.tabbar) .footer-inner {
|
|
|
3683
3734
|
align-items: start;
|
|
3684
3735
|
}
|
|
3685
3736
|
|
|
3737
|
+
/* A page with nothing else: More like this keeps the gap it has under the game's body. */
|
|
3738
|
+
.game-top + .section {
|
|
3739
|
+
margin-top: 44px;
|
|
3740
|
+
}
|
|
3741
|
+
|
|
3686
3742
|
/* One column: Play comes first in the panel, right under the gallery. */
|
|
3687
3743
|
@media (max-width: 1000px) {
|
|
3688
3744
|
.game-top {
|
|
@@ -3979,6 +4035,12 @@ body:has(.tabbar) .footer-inner {
|
|
|
3979
4035
|
list-style: none;
|
|
3980
4036
|
}
|
|
3981
4037
|
|
|
4038
|
+
.play-pay > summary,
|
|
4039
|
+
a.play-pay {
|
|
4040
|
+
padding: 6px 0;
|
|
4041
|
+
text-decoration: underline;
|
|
4042
|
+
}
|
|
4043
|
+
|
|
3982
4044
|
.play-pay[open] > summary {
|
|
3983
4045
|
margin-bottom: 8px;
|
|
3984
4046
|
}
|
|
@@ -4365,9 +4427,11 @@ body:has(.tabbar) .footer-inner {
|
|
|
4365
4427
|
}
|
|
4366
4428
|
|
|
4367
4429
|
.fold-count {
|
|
4430
|
+
margin-left: 4px;
|
|
4368
4431
|
color: var(--muted);
|
|
4369
4432
|
font-size: 14px;
|
|
4370
4433
|
font-variant-numeric: tabular-nums;
|
|
4434
|
+
white-space: nowrap;
|
|
4371
4435
|
}
|
|
4372
4436
|
|
|
4373
4437
|
.fold-caret {
|
|
@@ -4547,6 +4611,11 @@ body:has(.tabbar) .footer-inner {
|
|
|
4547
4611
|
margin: 0 0 18px;
|
|
4548
4612
|
}
|
|
4549
4613
|
|
|
4614
|
+
/* An order: its Play or Open, then what was bought. */
|
|
4615
|
+
.market-order .form-row:has(+ .kv) {
|
|
4616
|
+
margin-bottom: 18px;
|
|
4617
|
+
}
|
|
4618
|
+
|
|
4550
4619
|
.kv dt {
|
|
4551
4620
|
color: var(--muted);
|
|
4552
4621
|
font-size: 12px;
|
|
@@ -7211,8 +7280,7 @@ body.play {
|
|
|
7211
7280
|
body.play .ow-menu,
|
|
7212
7281
|
body.play .ow-social-body,
|
|
7213
7282
|
body.play .ow-chat-log,
|
|
7214
|
-
body.play .ow-players
|
|
7215
|
-
body.play .ow-badges {
|
|
7283
|
+
body.play .ow-players {
|
|
7216
7284
|
touch-action: pan-y;
|
|
7217
7285
|
}
|
|
7218
7286
|
|
|
@@ -7742,9 +7810,11 @@ body.play input {
|
|
|
7742
7810
|
padding-bottom: 16px;
|
|
7743
7811
|
}
|
|
7744
7812
|
|
|
7813
|
+
/* Its first line level with the head's buttons. */
|
|
7745
7814
|
.ow-menu-title {
|
|
7746
7815
|
flex: 1;
|
|
7747
7816
|
min-width: 0;
|
|
7817
|
+
padding-top: 4px;
|
|
7748
7818
|
}
|
|
7749
7819
|
|
|
7750
7820
|
.ow-menu-head h2 {
|
|
@@ -7797,8 +7867,7 @@ body.play input {
|
|
|
7797
7867
|
}
|
|
7798
7868
|
|
|
7799
7869
|
.ow-section[hidden],
|
|
7800
|
-
.ow-setting[hidden]
|
|
7801
|
-
.ow-guest[hidden] {
|
|
7870
|
+
.ow-setting[hidden] {
|
|
7802
7871
|
display: none;
|
|
7803
7872
|
}
|
|
7804
7873
|
|
|
@@ -7861,11 +7930,14 @@ body.play input {
|
|
|
7861
7930
|
overflow-y: auto;
|
|
7862
7931
|
}
|
|
7863
7932
|
|
|
7933
|
+
/* A row with more buttons than room takes a second line for them: the name stays readable. */
|
|
7864
7934
|
.ow-players li {
|
|
7865
7935
|
display: flex;
|
|
7936
|
+
flex-wrap: wrap;
|
|
7866
7937
|
align-items: center;
|
|
7867
|
-
gap: 10px;
|
|
7938
|
+
gap: 2px 10px;
|
|
7868
7939
|
min-height: 40px;
|
|
7940
|
+
padding: 2px 0;
|
|
7869
7941
|
font-size: 14px;
|
|
7870
7942
|
}
|
|
7871
7943
|
|
|
@@ -7901,8 +7973,10 @@ a.ow-player-name:focus-visible {
|
|
|
7901
7973
|
}
|
|
7902
7974
|
|
|
7903
7975
|
.ow-player-actions {
|
|
7904
|
-
flex:
|
|
7976
|
+
flex: 0 1 auto;
|
|
7905
7977
|
display: flex;
|
|
7978
|
+
flex-wrap: wrap;
|
|
7979
|
+
justify-content: flex-end;
|
|
7906
7980
|
gap: 6px;
|
|
7907
7981
|
margin-left: auto;
|
|
7908
7982
|
}
|
|
@@ -8044,17 +8118,6 @@ a.ow-player-name:focus-visible {
|
|
|
8044
8118
|
white-space: nowrap;
|
|
8045
8119
|
}
|
|
8046
8120
|
|
|
8047
|
-
.ow-server {
|
|
8048
|
-
display: flex;
|
|
8049
|
-
flex-wrap: wrap;
|
|
8050
|
-
align-items: center;
|
|
8051
|
-
justify-content: space-between;
|
|
8052
|
-
gap: 4px 12px;
|
|
8053
|
-
margin-top: 6px;
|
|
8054
|
-
color: var(--muted);
|
|
8055
|
-
font-size: 13px;
|
|
8056
|
-
}
|
|
8057
|
-
|
|
8058
8121
|
.ow-text-btn {
|
|
8059
8122
|
padding: 0;
|
|
8060
8123
|
border: 0;
|
|
@@ -8118,24 +8181,6 @@ button.ow-setting-icon:hover {
|
|
|
8118
8181
|
outline-offset: 2px;
|
|
8119
8182
|
}
|
|
8120
8183
|
|
|
8121
|
-
.ow-guest {
|
|
8122
|
-
margin: 0;
|
|
8123
|
-
padding: 12px 0;
|
|
8124
|
-
border-top: 1px solid var(--line);
|
|
8125
|
-
color: var(--muted);
|
|
8126
|
-
font-size: 13px;
|
|
8127
|
-
}
|
|
8128
|
-
|
|
8129
|
-
.ow-guest a {
|
|
8130
|
-
color: var(--accent-text);
|
|
8131
|
-
font-weight: 600;
|
|
8132
|
-
text-decoration: none;
|
|
8133
|
-
}
|
|
8134
|
-
|
|
8135
|
-
.ow-guest a:hover {
|
|
8136
|
-
text-decoration: underline;
|
|
8137
|
-
}
|
|
8138
|
-
|
|
8139
8184
|
.ow-menu-foot {
|
|
8140
8185
|
display: flex;
|
|
8141
8186
|
gap: 8px;
|
|
@@ -8305,80 +8350,14 @@ button.ow-setting-icon:hover {
|
|
|
8305
8350
|
letter-spacing: 0.06em;
|
|
8306
8351
|
}
|
|
8307
8352
|
|
|
8308
|
-
.ow-
|
|
8309
|
-
list-style: none;
|
|
8310
|
-
margin: 0;
|
|
8311
|
-
padding: 0;
|
|
8312
|
-
display: flex;
|
|
8313
|
-
flex-wrap: wrap;
|
|
8314
|
-
gap: 8px;
|
|
8315
|
-
}
|
|
8316
|
-
|
|
8317
|
-
.ow-badge-item {
|
|
8318
|
-
display: block;
|
|
8319
|
-
padding: 0;
|
|
8320
|
-
border: 0;
|
|
8321
|
-
border-radius: 50%;
|
|
8322
|
-
background: none;
|
|
8323
|
-
cursor: pointer;
|
|
8324
|
-
opacity: 0.35;
|
|
8325
|
-
filter: grayscale(1);
|
|
8326
|
-
transition: opacity 0.15s ease;
|
|
8327
|
-
}
|
|
8328
|
-
|
|
8329
|
-
.ow-badge-item:hover {
|
|
8330
|
-
opacity: 0.55;
|
|
8331
|
-
}
|
|
8332
|
-
|
|
8333
|
-
.ow-badge-item.ow-earned {
|
|
8334
|
-
opacity: 1;
|
|
8335
|
-
filter: none;
|
|
8336
|
-
}
|
|
8337
|
-
|
|
8338
|
-
.ow-badge-item:focus-visible {
|
|
8339
|
-
outline: 2px solid var(--accent-hover);
|
|
8340
|
-
outline-offset: 2px;
|
|
8341
|
-
}
|
|
8342
|
-
|
|
8343
|
-
.ow-badge-icon {
|
|
8344
|
-
display: block;
|
|
8345
|
-
width: 40px;
|
|
8346
|
-
height: 40px;
|
|
8347
|
-
border-radius: 50%;
|
|
8348
|
-
object-fit: cover;
|
|
8349
|
-
}
|
|
8350
|
-
|
|
8351
|
-
.ow-badge-blank {
|
|
8353
|
+
.ow-toast .ow-badge-blank {
|
|
8352
8354
|
display: grid;
|
|
8353
8355
|
place-items: center;
|
|
8354
|
-
background: var(--fill-strong);
|
|
8355
|
-
color: var(--text);
|
|
8356
|
-
font-size: 18px;
|
|
8357
|
-
}
|
|
8358
|
-
|
|
8359
|
-
.ow-earned .ow-badge-blank,
|
|
8360
|
-
.ow-toast .ow-badge-blank {
|
|
8361
8356
|
background: var(--accent-soft);
|
|
8362
8357
|
color: var(--accent-hover);
|
|
8363
|
-
}
|
|
8364
|
-
|
|
8365
|
-
.ow-toast .ow-badge-blank {
|
|
8366
8358
|
font-size: 20px;
|
|
8367
8359
|
}
|
|
8368
8360
|
|
|
8369
|
-
.ow-badge-caption {
|
|
8370
|
-
margin: 10px 0 0;
|
|
8371
|
-
color: var(--muted);
|
|
8372
|
-
font-size: 13px;
|
|
8373
|
-
line-height: 1.45;
|
|
8374
|
-
}
|
|
8375
|
-
|
|
8376
|
-
.ow-badge-caption b {
|
|
8377
|
-
margin-right: 2px;
|
|
8378
|
-
color: var(--text);
|
|
8379
|
-
font-weight: 600;
|
|
8380
|
-
}
|
|
8381
|
-
|
|
8382
8361
|
/* loading card shown until the game's page has loaded */
|
|
8383
8362
|
.ow-loading {
|
|
8384
8363
|
position: fixed;
|
|
@@ -8402,6 +8381,39 @@ button.ow-setting-icon:hover {
|
|
|
8402
8381
|
transition: opacity 0.35s ease, visibility 0s linear 0.35s;
|
|
8403
8382
|
}
|
|
8404
8383
|
|
|
8384
|
+
/* A page that never ran: what's in the frame (a device's filter page, an error) stays in view and can be tapped, the card below it. */
|
|
8385
|
+
.ow-loading.ow-loading-clear {
|
|
8386
|
+
align-items: end;
|
|
8387
|
+
background: none;
|
|
8388
|
+
pointer-events: none;
|
|
8389
|
+
}
|
|
8390
|
+
|
|
8391
|
+
.ow-loading-clear .ow-loading-cover,
|
|
8392
|
+
.ow-loading-clear .ow-loading-icon {
|
|
8393
|
+
display: none;
|
|
8394
|
+
}
|
|
8395
|
+
|
|
8396
|
+
.ow-loading-clear .ow-loading-inner {
|
|
8397
|
+
gap: 10px;
|
|
8398
|
+
margin-bottom: calc(16px + env(safe-area-inset-bottom));
|
|
8399
|
+
padding: 16px 20px;
|
|
8400
|
+
border-radius: 16px;
|
|
8401
|
+
background: #0e0f12;
|
|
8402
|
+
pointer-events: auto;
|
|
8403
|
+
}
|
|
8404
|
+
|
|
8405
|
+
.ow-loading-clear .ow-loading-name {
|
|
8406
|
+
font-size: 16px;
|
|
8407
|
+
}
|
|
8408
|
+
|
|
8409
|
+
/* On the right: the play page's own buttons show on the left now that the card doesn't cover them. */
|
|
8410
|
+
.ow-loading.ow-loading-clear .ow-loading-close {
|
|
8411
|
+
right: calc(20px + env(safe-area-inset-right));
|
|
8412
|
+
left: auto;
|
|
8413
|
+
background: #0e0f12;
|
|
8414
|
+
pointer-events: auto;
|
|
8415
|
+
}
|
|
8416
|
+
|
|
8405
8417
|
/* The game's cover, full-bleed, blurred and darkened (a blur hides the small size it is fetched at). */
|
|
8406
8418
|
.ow-loading-cover {
|
|
8407
8419
|
position: absolute;
|
|
@@ -8576,6 +8588,26 @@ button.ow-setting-icon:hover {
|
|
|
8576
8588
|
.ow-menu {
|
|
8577
8589
|
padding: 16px;
|
|
8578
8590
|
}
|
|
8591
|
+
.ow-menu-title {
|
|
8592
|
+
padding-top: 8px;
|
|
8593
|
+
}
|
|
8594
|
+
}
|
|
8595
|
+
|
|
8596
|
+
/* The narrowest phones: rows wrap instead of pushing the menu sideways. */
|
|
8597
|
+
@media (max-width: 360px) {
|
|
8598
|
+
.ow-menu {
|
|
8599
|
+
padding: 12px;
|
|
8600
|
+
overflow-x: hidden;
|
|
8601
|
+
}
|
|
8602
|
+
.ow-menu-foot {
|
|
8603
|
+
flex-wrap: wrap;
|
|
8604
|
+
}
|
|
8605
|
+
.ow-menu-foot .ow-btn {
|
|
8606
|
+
flex: 1 1 100%;
|
|
8607
|
+
}
|
|
8608
|
+
.ow-section-head {
|
|
8609
|
+
flex-wrap: wrap;
|
|
8610
|
+
}
|
|
8579
8611
|
}
|
|
8580
8612
|
|
|
8581
8613
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -10402,6 +10434,38 @@ body.play .ow-card {
|
|
|
10402
10434
|
border-radius: 999px;
|
|
10403
10435
|
}
|
|
10404
10436
|
|
|
10437
|
+
/* Enter presses the button: one small mark, for keyboards. */
|
|
10438
|
+
.ow-lobby-keys .ow-lobby-action:not(:disabled)::after {
|
|
10439
|
+
content: '\\21B5' / '';
|
|
10440
|
+
margin-left: 8px;
|
|
10441
|
+
font-size: 0.85em;
|
|
10442
|
+
font-weight: 400;
|
|
10443
|
+
opacity: 0.65;
|
|
10444
|
+
}
|
|
10445
|
+
|
|
10446
|
+
/* A press goes through to the target under the button, inside the game's frame (shell/lobby.ts, link): it is then the player's gesture
|
|
10447
|
+
there. The strip goes through whole, and the card's own parts stay on this page. */
|
|
10448
|
+
.ow-lobby.ow-lobby-through,
|
|
10449
|
+
.ow-lobby-through > .ow-lobby-card,
|
|
10450
|
+
.ow-lobby-through > .ow-lobby-bar,
|
|
10451
|
+
.ow-lobby-through .ow-lobby-actions,
|
|
10452
|
+
.ow-lobby-through .ow-lobby-action {
|
|
10453
|
+
pointer-events: none;
|
|
10454
|
+
}
|
|
10455
|
+
|
|
10456
|
+
.ow-lobby-through > .ow-lobby-card > :not(.ow-lobby-actions),
|
|
10457
|
+
.ow-lobby-through .ow-lobby-invite {
|
|
10458
|
+
pointer-events: auto;
|
|
10459
|
+
}
|
|
10460
|
+
|
|
10461
|
+
.ow-lobby-hover.ow-btn {
|
|
10462
|
+
background: rgba(255, 255, 255, 0.16);
|
|
10463
|
+
}
|
|
10464
|
+
|
|
10465
|
+
.ow-lobby-hover.ow-btn-primary {
|
|
10466
|
+
background: var(--accent-fill-hover);
|
|
10467
|
+
}
|
|
10468
|
+
|
|
10405
10469
|
/* 3, 2, 1. */
|
|
10406
10470
|
.ow-lobby-countdown {
|
|
10407
10471
|
position: fixed;
|
|
@@ -10811,6 +10875,32 @@ body.ow-calm .ow-fold-caret {
|
|
|
10811
10875
|
overflow-wrap: anywhere;
|
|
10812
10876
|
}
|
|
10813
10877
|
|
|
10878
|
+
.upload-kinds dl {
|
|
10879
|
+
margin: 0;
|
|
10880
|
+
font-size: 14px;
|
|
10881
|
+
}
|
|
10882
|
+
|
|
10883
|
+
.upload-kinds dl > div {
|
|
10884
|
+
display: grid;
|
|
10885
|
+
grid-template-columns: 7.5em minmax(0, 1fr);
|
|
10886
|
+
gap: 12px;
|
|
10887
|
+
padding: 7px 0;
|
|
10888
|
+
border-top: 1px solid var(--line);
|
|
10889
|
+
}
|
|
10890
|
+
|
|
10891
|
+
.upload-kinds dt {
|
|
10892
|
+
font-weight: 600;
|
|
10893
|
+
}
|
|
10894
|
+
|
|
10895
|
+
.upload-kinds dd {
|
|
10896
|
+
margin: 0;
|
|
10897
|
+
color: var(--muted);
|
|
10898
|
+
}
|
|
10899
|
+
|
|
10900
|
+
.upload-kinds .fine {
|
|
10901
|
+
margin: 7px 0 12px;
|
|
10902
|
+
}
|
|
10903
|
+
|
|
10814
10904
|
.upload-form .flash {
|
|
10815
10905
|
margin: 0;
|
|
10816
10906
|
}
|
|
@@ -13537,35 +13627,6 @@ body.share-frame {
|
|
|
13537
13627
|
}
|
|
13538
13628
|
}
|
|
13539
13629
|
|
|
13540
|
-
/* The play page's menu: Share (the server's invite link, on X or a phone's share sheet), and for guests one quiet line. */
|
|
13541
|
-
.ow-share {
|
|
13542
|
-
display: flex;
|
|
13543
|
-
gap: 8px;
|
|
13544
|
-
padding: 12px 0;
|
|
13545
|
-
border-top: 1px solid var(--line);
|
|
13546
|
-
}
|
|
13547
|
-
|
|
13548
|
-
.ow-share .ow-pill {
|
|
13549
|
-
text-decoration: none;
|
|
13550
|
-
}
|
|
13551
|
-
|
|
13552
|
-
.ow-made {
|
|
13553
|
-
margin: 0;
|
|
13554
|
-
padding: 0 0 12px;
|
|
13555
|
-
color: var(--muted);
|
|
13556
|
-
font-size: 12px;
|
|
13557
|
-
}
|
|
13558
|
-
|
|
13559
|
-
.ow-made a {
|
|
13560
|
-
color: inherit;
|
|
13561
|
-
font-weight: 600;
|
|
13562
|
-
text-decoration: none;
|
|
13563
|
-
}
|
|
13564
|
-
|
|
13565
|
-
.ow-made a:hover {
|
|
13566
|
-
color: var(--text);
|
|
13567
|
-
}
|
|
13568
|
-
|
|
13569
13630
|
/* A clip frame records the game alone: the platform's corner buttons and chat stay out of the creator's view. */
|
|
13570
13631
|
.ow-clip-frame .ow-hud,
|
|
13571
13632
|
.ow-clip-frame .ow-stats {
|
|
@@ -13742,7 +13803,7 @@ body.share-frame {
|
|
|
13742
13803
|
gap: 16px;
|
|
13743
13804
|
margin-top: 12px;
|
|
13744
13805
|
}
|
|
13745
|
-
`;var
|
|
13806
|
+
`;var X=JSON.parse(document.getElementById("ow-data").textContent),Z=X.game.slug,N=new URL(location.href).searchParams,_e=/^[2-9]$/.test(N.get("player")??"")?N.get("player"):null,De=N.get("demo"),B=De===null||De==="0"?null:{paid:De!=="free"};Gt(B!==null);var Vt=document.createElement("style");Vt.textContent=`${Ut}
|
|
13746
13807
|
.ow-local-panel { position: fixed; z-index: 30; top: 64px; left: 10px; max-width: min(340px, calc(100vw - 20px)); padding: 12px 14px; border-radius: 12px; background: var(--glass); border: 1px solid var(--line); color: var(--text); font: 14px/1.45 var(--font); backdrop-filter: blur(12px); }
|
|
13747
13808
|
.ow-local-panel[hidden] { display: none; }
|
|
13748
13809
|
.ow-local-panel b { font-weight: 650; }
|
|
@@ -13750,4 +13811,4 @@ body.share-frame {
|
|
|
13750
13811
|
.ow-local-panel p { margin: 0 0 6px; }
|
|
13751
13812
|
.ow-local-toast { position: fixed; z-index: 40; left: 50%; bottom: 24px; transform: translateX(-50%); max-width: calc(100vw - 32px); padding: 10px 14px; border-radius: 10px; background: var(--glass); color: var(--text); font: 14px/1.4 var(--font); border: 1px solid var(--line); }
|
|
13752
13813
|
.ow-local-toast[hidden] { display: none; }
|
|
13753
|
-
`;document.head.append($t);document.body.classList.add("play");var R=document.getElementById("ow-game");R.setAttribute("sandbox",Qe);R.setAttribute("allow",et);var G=document.getElementById("ow-root");function ao(){let t=new URLSearchParams;for(let[o,r]of O)tt.has(o)||t.append(o,r);let e=t.toString();return e&&e.length<=400?`?${e}`:""}var _=w("div","ow-hud ow-pos-top-left"),Ee=w("div","ow-bar"),io='<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>',so='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5v8a2.5 2.5 0 0 1-2.5 2.5H10l-4.2 3.4c-.5.4-1.3 0-1.3-.6V16A2.5 2.5 0 0 1 4 13.5z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></svg>',lo='<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="10" cy="8" r="3.5" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M3.5 19.5c.8-3.4 3.3-5.5 6.5-5.5s5.7 2.1 6.5 5.5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/><path d="M19 7.5v6M16 10.5h6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>',Lt=Me("Local platform",io),Ct=Me("Chat (not on this computer)",so),At=Me("Another player",lo);Ee.append(Lt,Ct,At);_.append(Ee);var C=w("div","ow-local-panel");C.hidden=!0;G.append(_,C);var F=w("div","ow-local-toast");F.hidden=!0;G.append(F);var Et=0;function j(t){F.textContent=t,F.hidden=!1,window.clearTimeout(Et),Et=window.setTimeout(()=>F.hidden=!0,4e3)}Lt.addEventListener("click",()=>{C.hidden=!C.hidden,C.hidden||po()});Ct.addEventListener("click",()=>j("Chat is the platform\u2019s: it isn\u2019t on this computer."));At.addEventListener("click",()=>{window.open(K(),"_blank")});function K(){let t=new URL(location.href),e=Math.min(9,Number(ze??1)+1);return t.searchParams.set("player",String(e)),z&&t.searchParams.set("server",z),t.href}function po(){C.replaceChildren();let t=e=>{let o=document.createElement("p");o.innerHTML=e,C.append(o)};t(`<b>${ae(q.game.name)}</b> on this computer`),t(`You are <b>${ae(Tt?.name??"\u2026")}</b>${I?` in <code>${ae(I)}</code>`:""}`),t(`<a href="${ae(K())}" target="_blank">Open another player</a> (up to 9: <code>?player=2</code>\u2026)`),t("Saves, badges and scores are kept by <code>onceworlds serve</code> while it runs.")}function w(t,e=""){let o=document.createElement(t);return e&&(o.className=e),o}function Me(t,e){let o=w("button","ow-icon-btn");return o.type="button",o.title=t,o.setAttribute("aria-label",t),o.innerHTML=e,o}function ae(t){return t.replace(/[&<>"']/g,e=>`&#${e.charCodeAt(0)};`)}async function b(t,e={}){let o=new URL(`/__emulator/api/${t}`,location.href);ze&&o.searchParams.set("player",ze);let r=await fetch(o,{...e,headers:e.body?{"Content-Type":"application/json"}:void 0}),n=await r.json().catch(()=>null);if(!r.ok)throw new Error(n?.message??`The local platform answered ${r.status}`);return n}var co=Date.now(),le=b("me").then(({player:t,now:e})=>({player:t,timeOffset:Math.round(e-(co+Date.now())/2)})),Tt=null;le.then(t=>Tt=t.player).catch(()=>{});var d=null,I=null,B=null,de="",Pe=null,$e=!1,Re=0,Dt=0;le.then(t=>Dt=t.timeOffset).catch(()=>{});var z=Be.test(O.get("server")??"")?O.get("server"):null,ie={value:ut(pe)},v={hellos:0,joins:0,errors:[],lastAlive:0,closed:null},u=new Q(G,{now:()=>Date.now()+Dt,onSetting:(t,e)=>{let o=u.chooseSetting(t,e);o&&(d?.send({t:"state",k:U,v:o}),d?.send({t:"unready"}),u.handle({t:"unready"}),f.emit("room",{t:"unready"}))},onReady:t=>Ot(t),onStart:()=>d?.send({t:"start"}),onStop:()=>d?.send({t:"end"}),onInvite:()=>window.open(K(),"_blank"),onLayout:()=>N.changed()}),A=new Z(G,t=>f.emit("controls",t),()=>N.changed());function Ot(t){d?.send({t:"ready",ready:t}),u.setReadyLocal(t),f.emit("room",{t:"ready",id:de,ready:t})}function Le(t,e=!1){A.touch!==t&&(A.setTouch(t),e||f.emit("input",{touch:t}))}addEventListener("pointerdown",t=>t.isTrusted&&Le(t.pointerType!=="mouse"),!0);addEventListener("keydown",t=>t.isTrusted&&Le(!1),!0);var N=new ee(_t,t=>f.emit("reserved",t)),f=new Y(R,{async"session.get"(){let{player:t,timeOffset:e}=await le;return{player:t,game:{slug:pe,name:q.game.name,owner:"local"},audio:{volume:1,muted:!1},settings:{quality:"auto",reducedMotion:!1,showStats:!1},timeOffset:e,platformOrigin:location.origin}},"save.get":({key:t})=>b(`save?key=${encodeURIComponent(String(t))}`),"save.set":({key:t,value:e})=>b(`save?key=${encodeURIComponent(String(t))}`,{method:"PUT",body:JSON.stringify({value:e??null})}).then(()=>null),"save.delete":({key:t})=>b(`save?key=${encodeURIComponent(String(t))}`,{method:"DELETE"}).then(()=>null),"save.list":()=>b("saves"),async"room.join"(t){await le;let e=t??{};if(Pe=e.lobby==="card"||e.lobby==="bar"?e.lobby:null,$e=!ot(e),u.setSchema(He(e.settings)),e.party&&d)throw new Error("Parties go into matchmaking on onceworlds.com: the local platform keeps everyone where they are.");se();let o=!e.name&&!z&&!e.private&&ie.value&&mo(ie.value.key,e)?ie.value:null;if(ie.value=null,o){let r=await Pt({key:o.key,rejoin:o.rejoin,maxPlayers:e.maxPlayers,minPlayers:e.minPlayers,countdown:e.countdown,teams:e.teams,ranked:e.ranked}).catch(()=>null);if(r)return r;se()}return Pt(xo(e))},"room.leave"(){return se(),null},"net.fetch":()=>{throw new Error("onceworlds.fetch fills in secrets on onceworlds.com: it does nothing on this computer. Push a draft (onceworlds deploy) to try it.")},"badges.list":()=>b("badges"),"badges.award":({key:t})=>D?.paid?{awarded:!1}:b("badges",{method:"POST",body:JSON.stringify({key:String(t)})}).then(e=>(e.awarded&&j(`Badge earned: ${e.badge?.name??t}`),{awarded:e.awarded})),"leaderboards.submit":({board:t,score:e,lowerIsBetter:o})=>D?.paid?null:b("leaderboards",{method:"POST",body:JSON.stringify({board:String(t),score:Number(e),lowerIsBetter:o===!0})}),"leaderboards.top":({board:t,limit:e,lowerIsBetter:o})=>b(`leaderboards?board=${encodeURIComponent(String(t))}&limit=${Number(e)||10}&lower=${o===!0?1:0}`),"ratings.get":()=>null,"ratings.top":()=>[],"ui.invite"(){return window.open(K(),"_blank"),null},"ui.fullscreen"(){return document.documentElement.requestFullscreen?.().catch(()=>{}),null},"ui.tapped":()=>null,"ui.controls"(t){return A.setLayout(t),null},"ui.orientation":()=>null,"ui.menuPosition"(t){let e=t?.position;return(e==="top-left"||e==="top-right"||e==="bottom-left"||e==="bottom-right")&&(_.className=`ow-hud ow-pos-${e}`,N.changed()),null},"ui.look"(t){return Mt(t),null},"player.rename":()=>null,"demo.end":()=>D?go(D.paid):!1,"data.game.get":({key:t})=>b(`gamedata?key=${encodeURIComponent(String(t))}`),"data.game.op":t=>b("gamedata",{method:"POST",body:JSON.stringify(t)}),"player.avatar":t=>{let e=t?.id;return typeof e=="string"&&/^[A-Za-z0-9-]{1,64}$/.test(e)?je(e):null}},{"room.send":({d:t,to:e})=>d?.send({t:"msg",d:t,to:e}),"room.presence":({d:t})=>d?.send({t:"presence",d:t}),"room.hideLobby":({hidden:t})=>u.setHidden(t===!0),"room.state":({k:t,v:e,w:o})=>d?.send({t:"state",k:t,v:e,...typeof o=="number"&&Number.isSafeInteger(o)&&o>0&&o<=2147483647?{w:o}:{}}),"room.team":({id:t,team:e})=>d?.send({t:"team",id:String(t),team:Number(e)}),"room.open":({open:t})=>d?.send({t:"open",open:t===!0}),"room.result":({result:t})=>d?.send({t:"result",result:t}),"room.kick":({id:t})=>d?.send({t:"kick",id:String(t)}),"room.votekick":({id:t})=>d?.send({t:"votekick",id:String(t)}),"room.ready":({ready:t})=>{d?.send({t:"ready",ready:t===!0}),u.setReadyLocal(t===!0)},"room.unready":()=>{d?.send({t:"unready"}),u.handle({t:"unready"})},"room.transfer":({id:t})=>d?.send({t:"transfer",id:String(t)}),"room.start":({countdown:t,open:e})=>d?.send({t:"start",...Number.isFinite(t)?{countdown:Number(t)}:{},...e===!0?{open:!0}:{}}),"room.end":()=>d?.send({t:"end"}),"room.pause":({paused:t})=>d?.send({t:"pause",paused:t===!0}),"room.idle":({idle:t})=>d?.send({t:"idle",idle:t===!0}),"room.private":({k:t,v:e,id:o})=>typeof t=="string"&&d?.send({t:"private",k:t,v:e,...typeof o=="string"?{id:o}:{}}),"room.datareset":()=>d?.send({t:"datareset"}),"room.admit":({ids:t})=>d?.send({t:"admit",ids:Array.isArray(t)?t.filter(e=>typeof e=="string").slice(0,50):[]}),alive:()=>{v.lastAlive=Date.now()},stats:()=>{},hotkey:()=>{},vibrate:()=>{},input:t=>Le(t?.touch===!0,!0),error:t=>{v.errors.length<20&&v.errors.push(String(t?.message??t).slice(0,300))},"input.first":()=>{},console:()=>{},debug:()=>{}},()=>{v.hellos++,kt(),se(),_.className="ow-hud ow-pos-top-left",A.setLayout(null),Mt(null),f.emit("input",{touch:A.touch}),N.resend()},{demo:D!==null}),Se=null;function go(t){return Se??=new Promise(e=>{f.emit("pause",null);let o=w("div","ow-name ow-demo-end"),r=w("div","ow-name-form ow-demo-box"),n=w("h2");n.textContent="End of demo";let a=w("p","ow-demo-name");a.textContent=q.game.name;let i=w("button","ow-btn ow-btn-primary");i.type="button",i.textContent=t?"Buy":"Favorite",i.addEventListener("click",()=>j(t?"On onceworlds.com, Buy opens the game\u2019s store page.":"On onceworlds.com, Favorite follows the game."));let s=w("button","ow-text-btn ow-name-login");s.type="button",s.textContent="Back to game",s.addEventListener("click",()=>{o.remove(),Se=null,f.emit("resume",null),R.focus(),e(!0)}),r.append(n,a,i,s),o.append(r),G.append(o),i.focus()}),Se}function Mt(t){let{look:e}=nt(t);u.setLook(pt(e)),A.setLook(dt(e))}function _t(){let t=R.getBoundingClientRect();if(!t.width||!t.height)return null;let{stick:e,buttons:o}=A.reservedBoxes(),r=Ee.getBoundingClientRect(),n=parseFloat(getComputedStyle(_).paddingTop)||0,a=r.width&&r.height?{left:r.left-n,top:r.top-n,width:r.width+2*n,height:r.height+2*n}:null;return mt(t,[{kind:"menu",box:_.hidden?null:a},{kind:"lobby",box:u.reservedBox()},{kind:"stick",box:e},{kind:"buttons",box:o}])}for(let t of["resize","orientationchange"])addEventListener(t,()=>N.changed());typeof ResizeObserver=="function"&&new ResizeObserver(()=>N.changed()).observe(R);function ho(t){return t.slice(0,t.lastIndexOf(":"))}function mo(t,e){let o=(e.teams??0)>=2?e.teams:0,r=Math.min(S.roomMaxPlayersCap,Math.max(2,e.maxPlayers??16)),n=Ge(e.minPlayers,r,V);return ho(t)===`pub:${ge({mode:e.mode||"default",max:r,teams:o,ranked:e.ranked===!0,min:n})}`}function uo(){let t="abcdefghijklmnopqrstuvwxyz0123456789";return Array.from(crypto.getRandomValues(new Uint8Array(12)),e=>t[e%t.length]).join("")}function xo(t){let{name:e,maxPlayers:o,minPlayers:r,countdown:n,mode:a,teams:i,ranked:s}=t,h=t.minPlayersPrivate??r;if(e)return{name:e,maxPlayers:o,minPlayers:h,countdown:n,teams:i};if(t.private&&!z){z=uo(),xt(pe,z);let g=new URL(location.href);g.searchParams.set("server",z),history.replaceState(null,"",g.href)}return z?{server:z,maxPlayers:o,minPlayers:h,countdown:n,teams:i,private:t.private}:{mode:a,maxPlayers:o,minPlayers:r,countdown:n,teams:i,ranked:s}}async function Pt(t){let e=new ne(pe,t,{onMessage:n=>e===d&&fo(n),onClose:n=>e===d&&bo(n),onConnection:n=>{e===d&&(n||f.emit("room.connection",{connected:!1}))}});d=e;let o=await e.join();if(e!==d)throw new Error("Left the server while joining");let r=o.room.startsWith("private:")?{...o,invite:K()}:o;return de=o.you,B=o.match??null,I=o.room,v.joins++,Re=Ne(o.room)?.max??Math.min(t.maxPlayers??S.roomMaxPlayersDefault,S.roomMaxPlayersCap),u.enable(Pe,{ownCountdown:$e}),u.setRoom(r,Re),r}function fo(t){if(t.t==="update"||t.t==="move")return;if(t.t==="datareset"){j("This server\u2019s world was started over."),R.src=R.src;return}t.t==="chat"&&(t.entry.to||t.entry.channel)||t.t==="channel"||f.emit("room",t),t.t!=="welcome"&&u.handle(t),t.t==="welcome"?(u.setRoom(t,Re),B=t.match??null):t.t==="match"?B=t.match:t.t==="error"&&t.code==="cooldown"&&(j(t.message),u.setReadyLocal(!1),f.emit("room",{t:"ready",id:de,ready:!1}))}function bo(t){d=null,I=null,B=null,v.closed=t,u.setRoom(null),j(t==="replaced"?"You opened this game in another tab, so multiplayer moved there.":t==="kicked"?"You were removed from the server.":"Disconnected from the server."),f.emit("room.closed",{reason:t})}function se(){d&&(d.close(),d=null,I=null,B=null,u.setRoom(null))}window.__owLocal={get you(){return de},get room(){return I},get match(){return B},get lobby(){return Pe},get ownCountdown(){return $e},get hellos(){return v.hellos},get joins(){return v.joins},get errors(){return v.errors},get lastAlive(){return v.lastAlive},get closed(){return v.closed},get reserved(){return _t()},ready(t){return d?(Ot(t),!0):!1},start(t){return d?(d.send({t:"start",...Number.isFinite(t)?{countdown:Number(t)}:{}}),!0):!1},chrome(t){G.style.visibility=t?"":"hidden"}};R.src=`${q.gameOrigin}/${ao()}`;})();
|
|
13814
|
+
`;document.head.append(Vt);document.body.classList.add("play");var v=document.getElementById("ow-game");v.setAttribute("sandbox",pt);v.setAttribute("allow",dt);var K=document.getElementById("ow-root");function Lo(){let t=new URLSearchParams;for(let[o,r]of N)gt.has(o)||t.append(o,r);let e=t.toString();return e&&e.length<=400?`?${e}`:""}var G=z("div","ow-hud ow-pos-top-left"),Be=z("div","ow-bar"),$o='<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>',Co='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5v8a2.5 2.5 0 0 1-2.5 2.5H10l-4.2 3.4c-.5.4-1.3 0-1.3-.6V16A2.5 2.5 0 0 1 4 13.5z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></svg>',To='<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="10" cy="8" r="3.5" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M3.5 19.5c.8-3.4 3.3-5.5 6.5-5.5s5.7 2.1 6.5 5.5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/><path d="M19 7.5v6M16 10.5h6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>',Wt=je("Local platform",$o),Yt=je("Chat (not on this computer)",Co),Jt=je("Another player",To);Be.append(Wt,Yt,Jt);G.append(Be);var O=z("div","ow-local-panel");O.hidden=!0;K.append(G,O);var J=z("div","ow-local-toast");J.hidden=!0;K.append(J);var Ht=0;function U(t){J.textContent=t,J.hidden=!1,window.clearTimeout(Ht),Ht=window.setTimeout(()=>J.hidden=!0,4e3)}Wt.addEventListener("click",()=>{O.hidden=!O.hidden,O.hidden||Do()});Yt.addEventListener("click",()=>U("Chat is the platform\u2019s: it isn\u2019t on this computer."));Jt.addEventListener("click",()=>{window.open(Q(),"_blank")});function Q(){let t=new URL(location.href),e=Math.min(9,Number(_e??1)+1);return t.searchParams.set("player",String(e)),M&&t.searchParams.set("server",M),t.href}function Do(){O.replaceChildren();let t=e=>{let o=document.createElement("p");o.innerHTML=e,O.append(o)};t(`<b>${he(X.game.name)}</b> on this computer`),t(`You are <b>${he(Xt?.name??"\u2026")}</b>${H?` in <code>${he(H)}</code>`:""}`),t(`<a href="${he(Q())}" target="_blank">Open another player</a> (up to 9: <code>?player=2</code>\u2026)`),t("Saves, badges and scores are kept by <code>onceworlds serve</code> while it runs.")}function z(t,e=""){let o=document.createElement(t);return e&&(o.className=e),o}function je(t,e){let o=z("button","ow-icon-btn");return o.type="button",o.title=t,o.setAttribute("aria-label",t),o.innerHTML=e,o}function he(t){return t.replace(/[&<>"']/g,e=>`&#${e.charCodeAt(0)};`)}async function S(t,e={}){let o=new URL(`/__emulator/api/${t}`,location.href);_e&&o.searchParams.set("player",_e);let r=await fetch(o,{...e,headers:e.body?{"Content-Type":"application/json"}:void 0}),n=await r.json().catch(()=>null);if(!r.ok)throw new Error(n?.message??`The local platform answered ${r.status}`);return n}var Oo=Date.now(),fe=S("me").then(({player:t,now:e})=>({player:t,timeOffset:Math.round(e-(Oo+Date.now())/2)})),Xt=null;fe.then(t=>Xt=t.player).catch(()=>{});var g=null,H=null,_=null,be="",j=null,we=!1,Zt=!1,Ie=0,Qt=0;fe.then(t=>Qt=t.timeOffset).catch(()=>{});var M=Ye.test(N.get("server")??"")?N.get("server"):null,ue={value:Ct(Z)},R={hellos:0,joins:0,errors:[],lastAlive:0,closed:null},m=new le(K,{now:()=>Date.now()+Qt,onSetting:(t,e)=>{let o=m.chooseSetting(t,e);o&&(g?.send({t:"state",k:V,v:o}),g?.send({t:"unready"}),m.handle({t:"unready"}),w.emit("room",{t:"unready"}))},onReady:t=>eo(t),onStart:()=>g?.send({t:"start"}),onStop:()=>g?.send({t:"end"}),onInvite:()=>window.open(Q(),"_blank"),onLayout:()=>F.changed(),onPressed:to}),C=new ie(K,t=>w.emit("controls",t),()=>F.changed());m.setKeyMark(!C.touch);function eo(t){g?.send({t:"ready",ready:t}),m.setReadyLocal(t),w.emit("room",{t:"ready",id:be,ready:t})}function Ne(t,e=!1){C.touch!==t&&(C.setTouch(t),m.setKeyMark(!t),e||w.emit("input",{touch:t}))}addEventListener("pointerdown",t=>t.isTrusted&&Ne(t.pointerType!=="mouse"),!0);addEventListener("keydown",t=>t.isTrusted&&Ne(!1),!0);addEventListener("keydown",t=>{let e=document.activeElement;t.isTrusted&&!t.repeat&&xt(t)&&(!e||e===document.body)&&m.pressKey()});function to(){v.focus(),v.contentWindow?.focus()}function Ft(){j||Zt||(j="bar",m.enable(j,{ownCountdown:we}))}var F=new se(()=>{let t=oo();return t&&{areas:t,link:m.link(v.getBoundingClientRect())}},({areas:t,link:e})=>{w.emit("reserved",t),w.emit("lobby",e)}),me=new re(async()=>({game:Z,player:null})),w=new oe(v,{async"session.get"(){let{player:t,timeOffset:e}=await fe;return{player:t,game:{slug:Z,name:X.game.name,owner:"local"},audio:{volume:1,muted:!1},settings:{quality:"auto",reducedMotion:!1,showStats:!1},timeOffset:e,platformOrigin:location.origin}},"save.get":({key:t})=>S(`save?key=${encodeURIComponent(String(t))}`),"save.set":({key:t,value:e})=>S(`save?key=${encodeURIComponent(String(t))}`,{method:"PUT",body:JSON.stringify({value:e??null})}).then(()=>null),"save.delete":({key:t})=>S(`save?key=${encodeURIComponent(String(t))}`,{method:"DELETE"}).then(()=>null),"save.list":()=>S("saves"),"storage.open":t=>me.read(t),"storage.commit":t=>me.commit(t),"storage.delete":t=>me.remove(t),"storage.list":()=>me.list(),async"room.join"(t){await fe;let e=t??{};if(j=mt(e),Zt=e.lobby==="game",we=!ut(e),m.setSchema(Qe(e.settings)),e.party&&g)throw new Error("Parties go into matchmaking on onceworlds.com: the local platform keeps everyone where they are.");xe();let o=!e.name&&!M&&!e.private&&ue.value&&Bo(ue.value.key,e)?ue.value:null;if(ue.value=null,o){let r=await qt({key:o.key,rejoin:o.rejoin,maxPlayers:e.maxPlayers,minPlayers:e.minPlayers,countdown:e.countdown,teams:e.teams,ranked:e.ranked}).catch(()=>null);if(r)return r;xe()}return qt(No(e))},"room.leave"(){return xe(),null},"net.fetch":()=>{throw new Error("onceworlds.fetch fills in secrets on onceworlds.com: it does nothing on this computer. Push a draft (onceworlds deploy) to try it.")},"badges.list":()=>S("badges"),"badges.award":({key:t})=>B?.paid?{awarded:!1}:S("badges",{method:"POST",body:JSON.stringify({key:String(t)})}).then(e=>(e.awarded&&U(`Badge earned: ${e.badge?.name??t}`),{awarded:e.awarded})),"leaderboards.submit":({board:t,score:e,lowerIsBetter:o})=>B?.paid?null:S("leaderboards",{method:"POST",body:JSON.stringify({board:String(t),score:Number(e),lowerIsBetter:o===!0})}),"leaderboards.top":({board:t,limit:e,lowerIsBetter:o})=>S(`leaderboards?board=${encodeURIComponent(String(t))}&limit=${Number(e)||10}&lower=${o===!0?1:0}`),"ratings.get":()=>null,"ratings.top":()=>[],"ui.invite"(){return window.open(Q(),"_blank"),null},"ui.fullscreen"(){return document.documentElement.requestFullscreen?.().catch(()=>{}),null},"ui.tapped":()=>null,"ui.controls"(t){return C.setLayout(t),null},"ui.orientation":()=>null,"ui.menuPosition"(t){let e=t?.position;return(e==="top-left"||e==="top-right"||e==="bottom-left"||e==="bottom-right")&&(G.className=`ow-hud ow-pos-${e}`,F.changed()),null},"ui.look"(t){return Kt(t),null},"player.rename":()=>null,"demo.end":()=>B?_o(B.paid):!1,"data.game.get":({key:t})=>S(`gamedata?key=${encodeURIComponent(String(t))}`),"data.game.op":t=>S("gamedata",{method:"POST",body:JSON.stringify(t)}),"player.avatar":t=>{let e=t?.id;return typeof e=="string"&&/^[A-Za-z0-9-]{1,64}$/.test(e)?Ve(e):null}},{"room.send":({d:t,to:e})=>g?.send({t:"msg",d:t,to:e}),"room.presence":({d:t})=>g?.send({t:"presence",d:t}),"room.hideLobby":()=>{},"lobby.press":()=>m.pressTarget(),"lobby.target":t=>m.setTarget(t?.ok===!0,t?.hover===!0),"room.state":({k:t,v:e,w:o})=>g?.send({t:"state",k:t,v:e,...typeof o=="number"&&Number.isSafeInteger(o)&&o>0&&o<=2147483647?{w:o}:{}}),"room.team":({id:t,team:e})=>g?.send({t:"team",id:String(t),team:Number(e)}),"room.open":({open:t})=>g?.send({t:"open",open:t===!0}),"room.result":({result:t})=>g?.send({t:"result",result:t}),"room.kick":({id:t})=>g?.send({t:"kick",id:String(t)}),"room.votekick":({id:t})=>g?.send({t:"votekick",id:String(t)}),"room.ready":({ready:t})=>{Ft(),g?.send({t:"ready",ready:t===!0}),m.setReadyLocal(t===!0)},"room.unready":()=>{g?.send({t:"unready"}),m.handle({t:"unready"})},"room.transfer":({id:t})=>g?.send({t:"transfer",id:String(t)}),"room.start":({countdown:t,open:e})=>{Ft(),g?.send({t:"start",...Number.isFinite(t)?{countdown:Number(t)}:{},...e===!0?{open:!0}:{}})},"room.end":()=>g?.send({t:"end"}),"room.pause":({paused:t})=>g?.send({t:"pause",paused:t===!0}),"room.idle":({idle:t})=>g?.send({t:"idle",idle:t===!0}),"room.private":({k:t,v:e,id:o})=>typeof t=="string"&&g?.send({t:"private",k:t,v:e,...typeof o=="string"?{id:o}:{}}),"room.datareset":()=>g?.send({t:"datareset"}),"room.admit":({ids:t})=>g?.send({t:"admit",ids:Array.isArray(t)?t.filter(e=>typeof e=="string").slice(0,50):[]}),alive:()=>{R.lastAlive=Date.now()},stats:()=>{},hotkey:({key:t})=>{t==="Enter"&&m.pressKey()},vibrate:()=>{},input:t=>Ne(t?.touch===!0,!0),error:t=>{R.errors.length<20&&R.errors.push(String(t?.message??t).slice(0,300))},"input.first":()=>{},console:()=>{},debug:()=>{}},()=>{R.hellos++,jt(),xe(),G.className="ow-hud ow-pos-top-left",C.setLayout(null),Kt(null),w.emit("input",{touch:C.touch}),F.resend()},{demo:B!==null}),Oe=null;function _o(t){return Oe??=new Promise(e=>{w.emit("pause",null);let o=z("div","ow-name ow-demo-end"),r=z("div","ow-name-form ow-demo-box"),n=z("h2");n.textContent="End of demo";let a=z("p","ow-demo-name");a.textContent=X.game.name;let i=z("button","ow-btn ow-btn-primary");i.type="button",i.textContent=t?"Buy":"Favorite",i.addEventListener("click",()=>U(t?"On onceworlds.com, Buy opens the game\u2019s store page.":"On onceworlds.com, Favorite follows the game."));let s=z("button","ow-text-btn ow-name-login");s.type="button",s.textContent="Back to game",s.addEventListener("click",()=>{o.remove(),Oe=null,w.emit("resume",null),v.focus(),e(!0)}),r.append(n,a,i,s),o.append(r),K.append(o),i.focus()}),Oe}function Kt(t){let{look:e}=wt(t);m.setLook(Et(e)),C.setLook(Pt(e))}function oo(){let t=v.getBoundingClientRect();if(!t.width||!t.height)return null;let{stick:e,buttons:o}=C.reservedBoxes(),r=Be.getBoundingClientRect(),n=parseFloat(getComputedStyle(G).paddingTop)||0,a=r.width&&r.height?{left:r.left-n,top:r.top-n,width:r.width+2*n,height:r.height+2*n}:null;return Y(t,[{kind:"menu",box:G.hidden?null:a},{kind:"lobby",box:m.reservedBox()},{kind:"stick",box:e},{kind:"buttons",box:o}])}for(let t of["resize","orientationchange"])addEventListener(t,()=>F.changed());typeof ResizeObserver=="function"&&new ResizeObserver(()=>F.changed()).observe(v);function Io(t){return t.slice(0,t.lastIndexOf(":"))}function Bo(t,e){let o=(e.teams??0)>=2?e.teams:0,r=Math.min(P.roomMaxPlayersCap,Math.max(2,e.maxPlayers??16)),n=Xe(e.minPlayers,r,ee);return Io(t)===`pub:${ke({mode:e.mode||"default",max:r,teams:o,ranked:e.ranked===!0,min:n})}`}function jo(){let t="abcdefghijklmnopqrstuvwxyz0123456789";return Array.from(crypto.getRandomValues(new Uint8Array(12)),e=>t[e%t.length]).join("")}function No(t){let{name:e,maxPlayers:o,minPlayers:r,countdown:n,mode:a,teams:i,ranked:s}=t,d=t.minPlayersPrivate??r;if(e)return{name:e,maxPlayers:o,minPlayers:d,countdown:n,teams:i};if(t.private&&!M){M=jo(),Tt(Z,M);let c=new URL(location.href);c.searchParams.set("server",M),history.replaceState(null,"",c.href)}return M?{server:M,maxPlayers:o,minPlayers:d,countdown:n,teams:i,private:t.private}:{mode:a,maxPlayers:o,minPlayers:r,countdown:n,teams:i,ranked:s}}async function qt(t){let e=new ge(Z,t,{onMessage:n=>e===g&&Go(n),onClose:n=>e===g&&Uo(n),onConnection:n=>{e===g&&(n||w.emit("room.connection",{connected:!1}))}});g=e;let o=await e.join();if(e!==g)throw new Error("Left the server while joining");let r=o.room.startsWith("private:")?{...o,invite:Q()}:o;return be=o.you,_=o.match??null,H=o.room,R.joins++,Ie=Je(o.room)?.max??Math.min(t.maxPlayers??P.roomMaxPlayersDefault,P.roomMaxPlayersCap),m.enable(j,{ownCountdown:we}),m.setRoom(r,Ie),r}function Go(t){if(t.t==="update"||t.t==="move")return;if(t.t==="datareset"){U("This server\u2019s world was started over."),v.src=v.src;return}t.t==="chat"&&(t.entry.to||t.entry.channel)||t.t==="channel"||w.emit("room",t),t.t!=="welcome"&&m.handle(t),t.t==="welcome"?(m.setRoom(t,Ie),_=t.match??null):t.t==="match"?(t.match.phase!=="lobby"&&t.match.phase!==_?.phase&&to(),_=t.match):t.t==="error"&&t.code==="cooldown"&&(U(t.message),m.setReadyLocal(!1),w.emit("room",{t:"ready",id:be,ready:!1}))}function Uo(t){g=null,H=null,_=null,R.closed=t,m.setRoom(null),U(t==="replaced"?"You opened this game in another tab, so multiplayer moved there.":t==="kicked"?"You were removed from the server.":"Disconnected from the server."),w.emit("room.closed",{reason:t})}function xe(){g&&(g.close(),g=null,H=null,_=null,m.setRoom(null))}window.__owLocal={get you(){return be},get room(){return H},get match(){return _},get lobby(){return j},get ownCountdown(){return we},get hellos(){return R.hellos},get joins(){return R.joins},get errors(){return R.errors},get lastAlive(){return R.lastAlive},get closed(){return R.closed},get reserved(){return oo()},ready(t){return g?(eo(t),!0):!1},start(t){return g?(g.send({t:"start",...Number.isFinite(t)?{countdown:Number(t)}:{}}),!0):!1},chrome(t){K.style.visibility=t?"":"hidden"}};v.src=`${X.gameOrigin}/${Lo()}`;})();
|