@onceworlds/cli 0.9.5 → 0.11.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/dist/sdk.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";(()=>{var pn=Object.defineProperty;var fn=(n,e,t)=>e in n?pn(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var p=(n,e,t)=>fn(n,typeof e!="symbol"?e+"":e,t);var gn=["#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"],hn=["Happy","Grin","Shades","Wink","Surprised","Determined","Joyful","Shy"],yn=["None","Sprout","Cap","Beanie","Crown","Headphones","Horns","Antenna","Bow","Halo","Party hat","Cat ears","Short hair","Tuft","Bob","Spikes","Bun","Curls","Long","Mop"];var bn=["Plain","Band","Spots","Stripes","Star"];var wn={skin:gn.length,shirt:Ve.length,pants:Ve.length,face:hn.length,hat:yn.length,top:bn.length};function We(n){if(!n||typeof n!="object")return null;let e=n,t={};for(let[r,s]of Object.entries(wn)){let o=e[r],i=typeof o=="number"?o:typeof o=="string"&&/^[0-9]{1,3}$/.test(o)?Number(o):NaN;if(!Number.isInteger(i)||i<0||i>=s)return null;t[r]=i}return t}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 kn="host:",H="data:";function J(n){return n.startsWith(kn)||n.startsWith(H)}var Ye=/^(?!__proto__$)[A-Za-z0-9_.:-]{1,59}$/;function ke(n){return n.startsWith(H)}function ve(n){return H+n}function Qe(n){return n.startsWith("private:")||n.startsWith("room:")}function Se(n){let e=n.length;for(let t=0;t<n.length;t++){let r=n.charCodeAt(t);r<128||(r<2048?e+=1:r>=55296&&r<=56319&&t+1<n.length&&(n.charCodeAt(t+1)&64512)===56320?(e+=2,t++):e+=2)}return e}var xe=/^[A-Za-z][A-Za-z0-9_.-]{0,31}$/;var vn={counter:["add"],list:["push"],record:["best"],map:["claim","release"],value:["set"]},Sn={add:"add(key, n)",push:"push(key, item)",best:"best(key, n)",claim:"claim(key, field)",release:"release(key, field)",set:"set(key, value)"};function xn(n){return vn[n].map(e=>`ow.data.game.${Sn[e]}`).join(" or ")}function Me(n,e){let r=Math.floor(e/864e5);if(n==="daily")return{start:r*864e5,next:(r+1)*864e5};let s=r-(r+3)%7;return{start:s*864e5,next:(s+7)*864e5}}function Mn(n,e){switch(n.type){case"counter":return{type:"counter",value:n.min,...n.reset?{resetsAt:Me(n.reset,e).next}:{}};case"list":return{type:"list",items:[]};case"record":return{type:"record",value:null,by:null,at:null};case"map":return{type:"map",fields:{}};case"value":return{type:"value",value:null,at:null}}}function Rn(n,e,t){if(!e||e.type!==n.type)return Mn(n,t);if(e.type==="counter"&&n.type==="counter"){if(!n.reset)return{type:"counter",value:e.value};let o=Me(n.reset,t);return{type:"counter",value:(e.period??0)>=o.start?e.value:n.min,resetsAt:o.next}}let{period:r,...s}=e;return s}function Ze(n,e,t,r,s){if(r.guest&&!n.guests)return{code:"sign_in",message:`Log in to change '${t.key}': guests can't (a ${n.type} is for signed-in players unless onceworlds.json says "guests": true).`};let o={id:r.id,name:r.name},i=Rn(n,e,s);switch(i.type){case"counter":{if(t.op!=="add"||n.type!=="counter")break;let l=Math.min(n.max,Math.max(n.min,i.value+t.n)),c=n.reset?Me(n.reset,s):null;return{next:{type:"counter",value:l,...c?{resetsAt:c.next,period:c.start}:{}},result:{type:"counter",value:l}}}case"list":{if(t.op!=="push"||n.type!=="list")break;return{next:{type:"list",items:[{value:t.item,by:o,at:s},...i.items].slice(0,n.max)},result:{type:"list",ok:!0}}}case"record":{if(t.op!=="best"||n.type!=="record")break;return i.value!==null&&i.by&&i.at!==null&&!(n.order==="max"?t.n>i.value:t.n<i.value)?{next:i,result:{type:"record",value:i.value,by:i.by,at:i.at,record:!1}}:{next:{type:"record",value:t.n,by:o,at:s},result:{type:"record",value:t.n,by:o,at:s,record:!0}}}case"map":{if(t.op!=="claim"&&t.op!=="release"||n.type!=="map")break;let l={...i.fields},c=Object.hasOwn(l,t.field)?l[t.field]:void 0;return t.op==="release"?!c||c.by.id!==r.id?{next:i,result:{type:"map",ok:!1,...c?{holder:c.by}:{}}}:(delete l[t.field],{next:{type:"map",fields:l},result:{type:"map",ok:!0}}):c?{next:i,result:{type:"map",ok:c.by.id===r.id,holder:c.by}}:Object.values(l).filter(d=>d.by.id===r.id).length>=n.perPlayer?{code:"limit",message:`claim('${t.key}'): a player holds at most ${n.perPlayer} (onceworlds.json's "perPlayer"). Release one first.`}:Object.keys(l).length>=n.fields?{code:"full",message:`claim('${t.key}'): all ${n.fields} fields are taken (onceworlds.json's "fields").`}:(l[t.field]={by:o,at:s},{next:{type:"map",fields:l},result:{type:"map",ok:!0}})}case"value":{if(t.op!=="set"||n.type!=="value")break;return r.host?{next:{type:"value",value:t.value,at:s},result:{type:"value",ok:!0}}:{code:"not_host",message:`set('${t.key}'): only the host of one of the game's rooms sets a value. Join a room, and set it from the host's page (room.isHost).`}}}return{code:"wrong_op",message:`'${t.key}' is a ${n.type}: use ${xn(n.type)}.`}}var Je=n=>n.replace(/[\u0000-\u001f\u007f]/g," ").replace(/\s+/g," ").trim();var En=/^[a-z0-9][a-z0-9-]{0,19}$/;function Xe(n){if(!n||typeof n!="object")return null;let e=n,t=[];for(let s of Array.isArray(e.buttons)?e.buttons:[]){if(t.length>=S.controlButtons)break;let{id:o,label:i}=s??{};if(typeof o!="string"||!En.test(o)||t.some(c=>c.id===o))continue;let l=typeof i=="string"?i.replace(/[\u0000-\u001f\u007f]/g,"").replace(/\s+/g," ").trim().slice(0,S.controlLabelLength).trim():"";t.push({id:o,label:l||o})}let r=e.stick===!0;return r||t.length>0?{stick:r,zone:e.zone==="corner"?"corner":"wide",buttons:t}:null}var Y="host:ow.settings",Pn=/^[a-z][a-zA-Z0-9]{0,15}$/;function Re(n){if(!Array.isArray(n))return[];let e=[];for(let t of n){if(e.length>=6)break;let{id:r,label:s,options:o,default:i}=t??{};if(typeof r!="string"||!Pn.test(r)||e.some(d=>d.id===r)||!Array.isArray(o))continue;let l=[];for(let d of o){let m=typeof d=="object"&&d!==null?d.value:d;if(typeof m!="string"&&typeof m!="number"||typeof m=="number"&&!Number.isFinite(m)||l.length>=8||l.some(f=>f.value===m))continue;let h=typeof d=="object"&&d!==null&&typeof d.label=="string"?d.label:String(m);l.push({value:m,label:Je(h).slice(0,20)||String(m)})}if(l.length<2)continue;let c=typeof s=="string"?Je(s).slice(0,24):"";e.push({id:r,label:c||r,options:l,default:l.some(d=>d.value===i)?i:l[0].value})}return e}function et(n,e){let t=e!==null&&typeof e=="object"?e[n.id]:void 0;return n.options.some(r=>r.value===t)?t:n.default}var tt="onceworlds:hello",nt="onceworlds:connect",rt=/^[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}$/;var ot=["log","info","warn","error"],st="onceworlds-console";var it=/^[A-Za-z0-9-]{1,64}$/;function at(){let n=1,e=!1,t=()=>e?0:n,r=new Map;if(typeof AudioNode<"u"&&typeof AudioDestinationNode<"u"){let d=AudioNode.prototype.connect,m=AudioNode.prototype.disconnect,h=w=>typeof OfflineAudioContext>"u"||!(w instanceof OfflineAudioContext),f=w=>{let y=r.get(w);return y||(y=w.createGain(),y.gain.value=t(),d.call(y,w.destination),r.set(w,y)),y};AudioNode.prototype.connect=function(w,...y){return w instanceof AudioDestinationNode&&h(w.context)&&r.get(w.context)!==this?(d.call(this,f(w.context),...y),w):d.call(this,w,...y)},AudioNode.prototype.disconnect=function(...w){let y=w[0];if(y instanceof AudioDestinationNode){let k=r.get(y.context);k&&k!==this&&(w[0]=k)}return m.apply(this,w)}}let s=new WeakMap,o=new Set,i=typeof HTMLMediaElement<"u"?Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype,"volume"):void 0,l=d=>i?.set?.call(d,Ee((s.get(d)??1)*t())),c=d=>{s.has(d)||!i?.get||(s.set(d,i.get.call(d)),o.add(new WeakRef(d)))};if(i?.get&&i.set){Object.defineProperty(HTMLMediaElement.prototype,"volume",{configurable:!0,enumerable:i.enumerable,get(){return s.has(this)?s.get(this):i.get.call(this)},set(m){c(this),s.set(this,Ee(Number(m))),l(this)}});let d=HTMLMediaElement.prototype.play;HTMLMediaElement.prototype.play=function(){return c(this),l(this),d.call(this)}}return{get volume(){return n},get muted(){return e},apply(d){n=Ee(d.volume),e=d.muted;for(let[m,h]of r)h.gain.setTargetAtTime(t(),m.currentTime,.02);for(let m of o){let h=m.deref();h?l(h):o.delete(m)}}}}function Ee(n){return Number.isFinite(n)?Math.min(1,Math.max(0,n)):1}function lt(n){try{let e=n?.getAttribute("data-build");return e&&rt.test(e)?e:null}catch{return null}}var O={ms:9e3,warmupMs:1e3,flowSettleMs:1500,playSettleMs:2e3,motionGraceMs:5e3,ceilingMs:25e3,graceMs:12e3,maxBytes:6*1024*1024,posterBytes:1024*1024,long:1280,short:720,fps:30,bitsPerSecond:25e5};var $n=["video/webm;codecs=vp9","video/webm;codecs=vp8","video/webm","video/mp4;codecs=avc1","video/mp4"],Cn=3e3,ct=250,Ln="host:ow.flow";function ut(n){let e=n?.[Ln],t=e&&typeof e=="object"?e.phase:void 0;return typeof t=="string"?t:void 0}var Pe=250,oe=32,se=18,_n=.02,Ae={needed:6,of:8};function Dn(){return typeof window>"u"||typeof document>"u"?null:{document,MediaRecorder:globalThis.MediaRecorder,requestAnimationFrame:n=>window.requestAnimationFrame(n),setTimeout:(n,e)=>window.setTimeout(n,e),clearTimeout:n=>window.clearTimeout(n)}}var F=(n,e,t,r)=>typeof n=="number"&&Number.isFinite(n)?Math.min(t,Math.max(e,Math.round(n))):r;function On(n){if(!n||typeof n!="object")return null;let e=n;return e.t==="stop"?{t:"stop"}:e.t!=="start"?null:{t:"start",ms:F(e.ms,1e3,15e3,O.ms),long:F(e.long,160,1920,O.long),short:F(e.short,90,1080,O.short),fps:F(e.fps,5,60,O.fps),bitsPerSecond:F(e.bitsPerSecond,25e4,8e6,O.bitsPerSecond),maxBytes:F(e.maxBytes,64*1024,O.maxBytes,O.maxBytes)}}function ie(n){let e=null,t=0;for(let r of Array.from(n))try{if(r.isConnected===!1||r.width<64||r.height<64)continue;let s=typeof r.getBoundingClientRect=="function"?r.getBoundingClientRect():null;if(s&&(s.width<32||s.height<32))continue;let o=s?s.width*s.height:r.width*r.height;o>t&&(e=r,t=o)}catch{}return e}function Tn(n,e,t,r){let s=n>=e,o=Math.min(1,(s?t:r)/n,(s?r:t)/e);if(o>=1)return{width:n,height:e,scale:1};let i=l=>Math.max(2,Math.floor(l*o/2)*2);return{width:i(n),height:i(e),scale:o}}function In(n,e){return new Promise(t=>{e.requestAnimationFrame(()=>{try{let r=n.width,s=n.height,o=Math.min(O.long,Math.max(480,r)),i=Math.round(o*9/16),l=e.document.createElement("canvas");l.width=o,l.height=i;let c=l.getContext("2d");if(!c)return t(null);c.fillStyle="#000",c.fillRect(0,0,o,i);let d=r/s,m=d>=1.25&&d<=2.4?Math.max(o/r,i/s):Math.min(o/r,i/s);c.drawImage(n,(o-r*m)/2,(i-s*m)/2,r*m,s*m),l.toBlob(h=>h?h.arrayBuffer().then(t,()=>t(null)):t(null),"image/jpeg",.85)}catch{t(null)}})})}function Bn(n,e){let t=null,r=null;return s=>{e.requestAnimationFrame(()=>{try{if(!t){let c=e.document.createElement("canvas");c.width=oe,c.height=se,t=c.getContext("2d",{willReadFrequently:!0})}if(!t)return s(null);t.drawImage(n,0,0,oe,se);let o=t.getImageData(0,0,oe,se).data,i=r;if(r=new Uint8ClampedArray(o),!i)return s(null);let l=0;for(let c=0;c+2<o.length;c+=4){let d=o[c]*2+o[c+1]*5+o[c+2],m=i[c]*2+i[c+1]*5+i[c+2];Math.abs(d-m)>128&&l++}s(l/(oe*se))}catch{s(null)}})}}function Nn(n,e,t,r){return new Promise(s=>{let o=Bn(n,e),i=[],l=0,c=0,d=!1,m=()=>{if(r()||l>=O.ceilingMs)return s(!1);let h=null;try{h=t()}catch{}h&&h.phase!=="lobby"&&(d=!0);let f=h?.flow;if(h?.phase==="playing"&&h.paused!==!0&&(f===void 0||f==="playing")){if(c+=Pe,c>(f===void 0?O.playSettleMs:O.flowSettleMs))return s(!0)}else c=0;if(!d){if(l>=O.motionGraceMs&&i.length>=Ae.of&&i.filter(Boolean).length>=Ae.needed)return s(!0);o(w=>{i.push(w!==null&&w>=_n),i.length>Ae.of&&i.shift()})}l+=Pe,e.setTimeout(m,Pe)};m()})}function dt(n,e){let t=e.MediaRecorder;return typeof n.captureStream!="function"||typeof t!="function"?null:$n.find(r=>{try{return t.isTypeSupported(r)}catch{return!1}})??null}function mt(n,e=Dn(),t=()=>null){let r=null,s=l=>{try{n(l)}catch{}},o=l=>s({t:"none",reason:l});function i(l){if(r)return;if(!e)return o("unsupported");let c=e,d=!1,m=null;r={cancel(){d=!0,m!==null&&c.clearTimeout(m)}};let h=y=>{r=null,!d&&y&&s(y)},f=0,w=()=>{if(d)return h(null);let y=ie(c.document.querySelectorAll("canvas"));if(y){if(m=null,!dt(y,c))return h({t:"none",reason:"unsupported"});Nn(y,c,t,()=>d).then(k=>{if(d)return null;if(!k)return{t:"none",reason:"not-playing"};let E=ie(c.document.querySelectorAll("canvas"))??y;return Gn(E,l,c,()=>d,()=>!d&&s({t:"started"}))}).then(h,()=>h({t:"none",reason:"failed"}))}else++f>Cn/ct?h({t:"none",reason:"no-canvas"}):m=c.setTimeout(w,ct)};w()}return{receive(l){try{let c=On(l);if(!c)return;if(c.t==="stop"){r?.cancel(),r=null;return}i(c)}catch{r=null,o("failed")}}}}function Gn(n,e,t,r,s){let o=t.MediaRecorder,i=dt(n,t);if(!o||!i)return Promise.resolve({t:"none",reason:"unsupported"});let l=Tn(n.width,n.height,e.long,e.short),c=!1,d=n;if(l.scale<1){let f=t.document.createElement("canvas");f.width=l.width,f.height=l.height;let w=f.getContext("2d");if(!w)return Promise.resolve({t:"none",reason:"unsupported"});c=!0;let y=()=>{if(c){try{w.drawImage(n,0,0,l.width,l.height)}catch{}t.requestAnimationFrame(y)}};y(),d=f}let m,h;try{m=d.captureStream(e.fps),h=new o(m,{mimeType:i,videoBitsPerSecond:e.bitsPerSecond})}catch{return c=!1,Promise.resolve({t:"none",reason:"failed"})}return new Promise(f=>{let w=[],y=0,k=Promise.resolve(null),E=t.setTimeout(()=>{k=In(n,t)},Math.round(e.ms/2)),_=null,T=()=>{try{h.state!=="inactive"&&h.stop()}catch{}},M=()=>{c=!1,t.clearTimeout(E),_!==null&&t.clearTimeout(_);try{for(let L of m.getTracks())L.stop()}catch{}};h.ondataavailable=L=>{!L.data||L.data.size===0||(w.push(L.data),y+=L.data.size,y>e.maxBytes*.85&&T())},h.onerror=()=>{M(),f(r()?null:{t:"none",reason:"failed"})},h.onstop=()=>{if(M(),r())return f(null);let L=new Blob(w,{type:h.mimeType||i});Promise.all([L.arrayBuffer(),k.catch(()=>null)]).then(([U,N])=>{if(U.byteLength===0)return f({t:"none",reason:"failed"});if(U.byteLength>e.maxBytes)return f({t:"none",reason:"too-large"});f({t:"done",type:L.type||i,video:U,poster:N,width:l.width,height:l.height})}).catch(()=>f({t:"none",reason:"failed"}))};try{h.start(1e3)}catch{return M(),f({t:"none",reason:"failed"})}s(),_=t.setTimeout(()=>{_=null,T()},e.ms);let P=()=>{if(h.state!=="inactive"){if(r())return T();t.setTimeout(P,200)}};t.setTimeout(P,200)})}var jn=200,pt=2,K=20,ft=200;function gt(n){try{return new URLSearchParams(n).get(st)==="1"}catch{return!1}}function ht(n){return typeof n=="object"&&n!==null&&n.solo===!0?"standalone":"platform"}function yt(n){return typeof n=="object"&&n!==null&&n.demo===!0}function bt(n){try{let e=new URLSearchParams(n).get("demo");return e!==null&&e!=="0"&&e!=="false"}catch{return!1}}function wt(n,e,t=Date.now,r=setTimeout){let s=null,o=[],i=-1/0,l=0,c=0,d=!1,m=!1,h=y=>{s?s(y):o.length<jn&&o.push(y)},f=()=>{let y=t();return y-i>=1e3&&(i=y,l=0),l<S.consoleLinesPerSecond?(l++,!0):(c++,d||(d=!0,r(()=>{d=!1;let k=c;c=0,k>0&&f()&&h({level:"warn",text:`${k} more ${k===1?"line":"lines"} left out`,at:t()})},Math.max(0,1e3-(y-i)))),!1)},w=(y,k,E)=>{if(!f())return;let _=kt(e?k.split(`${e}/`).join(""):k);h({level:y,text:_,at:t(),...E?{source:E.source.slice(0,300),line:E.line,column:E.column}:{}})};for(let y of ot){let k=n[y];typeof k=="function"&&(n[y]=function(...E){if(k.apply(n,E),!m){m=!0;try{w(y,Hn(E))}catch{}finally{m=!1}}})}return{error(y,k){if(!m){m=!0;try{w("error",y,k)}catch{}finally{m=!1}}},connect(y){s=y;for(let k of o.splice(0))y(k)}}}function Hn(n){let e="",t=n;if(typeof n[0]=="string"){let r=1;e=n[0].replace(/%[sdifoOc%]/g,s=>{if(s==="%%")return"%";if(r>=n.length)return s;let o=n[r++];return s==="%c"?"":s==="%d"||s==="%i"?String(typeof o=="number"?Math.trunc(o):parseInt(Q(o),10)):s==="%f"?String(typeof o=="number"?o:parseFloat(Q(o))):s==="%s"?Q(o):V(o)}),t=n.slice(r)}for(let r of t)e+=e?` ${Q(r)}`:Q(r);return kt(e)}function Q(n){return typeof n=="string"?n:V(n)}function V(n,e=0){try{switch(typeof n){case"string":return JSON.stringify(n.length>ft?`${n.slice(0,ft)}\u2026`:n);case"bigint":return`${n}n`;case"symbol":return n.toString();case"function":return`\u0192 ${n.name||"anonymous"}()`;case"object":break;default:return String(n)}if(n===null)return"null";if(n instanceof Error)return ae(n);if(n instanceof Date)return Number.isNaN(n.getTime())?"Invalid Date":n.toISOString();if(n instanceof RegExp)return String(n);if(n instanceof Map||n instanceof Set)return`${n.constructor.name}(${n.size})`;if(ArrayBuffer.isView(n))return`${n.constructor.name}(${"length"in n?n.length:n.byteLength})`;if(typeof Element<"u"&&n instanceof Element)return`<${n.tagName.toLowerCase()}>`;if(Array.isArray(n))return e>=pt?`Array(${n.length})`:`[${n.slice(0,K).map(i=>V(i,e+1)).join(", ")}${n.length>K?`, \u2026${n.length-K} more`:""}]`;let t=typeof n.constructor=="function"&&n.constructor!==Object?`${n.constructor.name} `:"";if(e>=pt)return`${t}{\u2026}`;let r=Object.keys(n),s=r.slice(0,K).map(o=>`${/^[A-Za-z_$][\w$]*$/.test(o)?o:JSON.stringify(o)}: ${V(n[o],e+1)}`);return`${t}{${s.join(", ")}${r.length>K?`, \u2026${r.length-K} more`:""}}`}catch{return Object.prototype.toString.call(n)}}function ae(n){try{let e=`${n.name||"Error"}: ${n.message}`,t=typeof n.stack=="string"?n.stack:"";return t?t.startsWith(e)?t:`${e}
2
+ ${t}`:e}catch{return"Error"}}function kt(n){return n.length>S.consoleLineLength?`${n.slice(0,S.consoleLineLength-1)}\u2026`:n}var qn={wasd:{up:"w",down:"s",left:"a",right:"d"},arrows:{up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight"}},zn=.45,Un=.3,$e={" ":["Space",32],Enter:["Enter",13],Shift:["ShiftLeft",16],Control:["ControlLeft",17],Alt:["AltLeft",18],Escape:["Escape",27],Tab:["Tab",9],Backspace:["Backspace",8],ArrowLeft:["ArrowLeft",37],ArrowUp:["ArrowUp",38],ArrowRight:["ArrowRight",39],ArrowDown:["ArrowDown",40]},le=class{constructor(e,t){p(this,"touch");p(this,"stick",{x:0,y:0});p(this,"held",new Set);p(this,"downs",new Map);p(this,"stickMode");p(this,"buttonKeys",new Map);p(this,"down",new Map);p(this,"show");p(this,"reportTouch");this.show=e,this.reportTouch=t,this.touch=typeof matchMedia=="function"&&matchMedia("(pointer: coarse)").matches,window.addEventListener("pointerdown",r=>r.isTrusted&&this.setTouch(r.pointerType!=="mouse"),!0),window.addEventListener("keydown",r=>r.isTrusted&&this.setTouch(!1),!0),window.addEventListener("blur",()=>this.release()),document.addEventListener("visibilitychange",()=>document.hidden&&this.release())}set(e){let t=e??{};this.stickMode=t.stick==="wasd"||t.stick==="arrows"||t.stick==="analog"?t.stick:void 0;let r=Array.isArray(t.buttons)?t.buttons:[],s=e?Xe({stick:this.stickMode!==void 0,zone:t.zone,buttons:r}):null;this.buttonKeys=new Map;for(let o of s?.buttons??[]){let i=r.find(l=>l?.id===o.id)?.key;typeof i=="string"&&i&&this.buttonKeys.set(o.id,i)}this.show(s),s?this.update():this.release()}receive(e){let t=s=>typeof s=="number"&&Number.isFinite(s)?Math.max(-1,Math.min(1,s)):0;this.stick.x=t(e?.x),this.stick.y=t(e?.y);let r=new Set(Array.isArray(e?.buttons)?e.buttons.filter(s=>typeof s=="string"):[]);for(let s of r)this.held.has(s)||this.downs.set(s,(this.downs.get(s)??0)+1);this.held=r,this.update()}pressed(e){return this.held.has(e)}presses(e){return this.downs.get(e)??0}update(){let e=new Map;if(this.stickMode==="wasd"||this.stickMode==="arrows"){let t=qn[this.stickMode],r=(s,o)=>{o>(this.down.has(s)?Un:zn)&&e.set(s,vt(s))};r(t.up,-this.stick.y),r(t.down,this.stick.y),r(t.left,-this.stick.x),r(t.right,this.stick.x)}for(let t of this.held){let r=this.buttonKeys.get(t);r&&e.set(r,vt(r))}for(let[t,r]of this.down)e.has(t)||(this.down.delete(t),St(r,!1));for(let[t,r]of e)this.down.has(t)||(this.down.set(t,r),St(r,!0))}release(){this.stick.x=0,this.stick.y=0,this.held.clear(),this.update()}setTouch(e){e!==this.touch&&(this.touch=e,e||this.release(),this.reportTouch(e))}};function vt(n){let e=n==="Space"?" ":n;return Object.prototype.hasOwnProperty.call($e,e)?{key:e,code:$e[e][0],keyCode:$e[e][1]}:/^[a-z]$/i.test(e)?{key:e.toLowerCase(),code:`Key${e.toUpperCase()}`,keyCode:e.toUpperCase().charCodeAt(0)}:/^[0-9]$/.test(e)?{key:e,code:`Digit${e}`,keyCode:48+Number(e)}:{key:e,code:"",keyCode:0}}function St(n,e){try{let t={key:n.key,code:n.code,keyCode:n.keyCode,which:n.keyCode,bubbles:!0,cancelable:!0},r=new KeyboardEvent(e?"keydown":"keyup",t);r.keyCode!==n.keyCode&&(Object.defineProperty(r,"keyCode",{get:()=>n.keyCode}),Object.defineProperty(r,"which",{get:()=>n.keyCode})),(document.activeElement??document.body??document).dispatchEvent(r)}catch{}}function Fn(n){switch(n.type){case"counter":return n.value;case"list":return n.items;case"record":return n.value===null?null:{value:n.value,by:n.by,at:n.at};case"map":return n.fields;case"value":return n.value}}function xt(n=e=>console.warn(`[onceworlds] ${e}`)){let e=new Map;return t=>{let r=Date.now();r-(e.get(t)??-1/0)<5e3||(e.size>200&&e.clear(),e.set(t,r),n(t))}}function Mt(n,e){let t=new Set,r=async(s,o)=>{let i=`onceworlds.data.server.${o===null?"delete":"set"}('${String(s).slice(0,40)}')`,l=n();if(typeof s!="string"||!Ye.test(s))return e(`${i} did nothing: a key is 1-59 letters, digits or _ . : -`),!1;if(!l||l.closed)return e(`${i} did nothing: you're not in a room. Join one first (await onceworlds.rooms.join({ private: true })): server data belongs to a server.`),!1;if(!l.connected)return e(`${i} did nothing: the connection is down and the platform is reconnecting. Write it again after room.on('reconnect').`),!1;if(!l.isHost)return e(`${i} did nothing: only the room's host writes server data. Check onceworlds.data.server.canWrite, or send the change to the host (room.send) and let it write.`),!1;let c;try{c=JSON.stringify(o??null)}catch{c=void 0}return c===void 0?(e(`${i} did nothing: the value must be plain JSON data (numbers, text, lists, objects).`),!1):Se(c)>S.stateValueBytes-128?(e(`${i} did nothing: the value is ${Math.ceil(Se(c)/1024)} KB, and a key holds 16 KB. Split it into keys by area or chunk (a server keeps ${S.serverDataKeys} keys, ${S.serverDataBytes/1024} KB), or let the engine's Persist() save the world for you.`),!1):await l._writeAcked(ve(s),o??null)};return{get(s){let o=n();if(!o||typeof s!="string")return null;let i=o.state[ve(s)];return i===void 0?null:i},all(){let s=n(),o={};if(!s)return o;for(let[i,l]of Object.entries(s.state))i.startsWith("data:")&&(o[i.slice(5)]=l);return o},set:(s,o)=>r(s,o??null),delete:s=>r(s,null),get kept(){return n()?.kept??!1},get canWrite(){let s=n();return!!(s&&!s.closed&&s.isHost)},async reset(){let s=n();return s?s.owner!==s.me.id&&s.kind!=="solo"?(e("onceworlds.data.server.reset() did nothing: only a private server's owner starts its world over (room.owner)."),!1):s._resetData():(e("onceworlds.data.server.reset() did nothing: you're not in a room."),!1)},on(s,o){return s!=="change"||typeof o!="function"?()=>{}:(t.add(o),()=>t.delete(o))},_changed(s,o,i){for(let l of t)try{l(s,o??null,i)}catch(c){console.error('[onceworlds] error in data.server "change" listener',c)}}}}function Rt(n,e){let t=async(s,o,i,l)=>{if(typeof s.key!="string"||!xe.test(s.key))return e(`${o} did nothing: '${String(s.key).slice(0,40)}' isn't a game data key (1-32 letters, digits, _ . or -, declared in onceworlds.json's "data").`),l;try{return i(await(await n()).op(s))}catch(c){return e(`${o} did nothing: ${c instanceof Error?c.message:String(c)}`),l}},r=(s,o)=>`onceworlds.data.game.${s}('${String(o).slice(0,40)}')`;return{async get(s){if(typeof s!="string"||!xe.test(s))return e(`${r("get",s)}: '${String(s).slice(0,40)}' isn't a game data key (1-32 letters, digits, _ . or -).`),null;try{return Fn(await(await n()).read(s))}catch(o){return e(`${r("get",s)} read nothing: ${o instanceof Error?o.message:String(o)}`),null}},add:(s,o)=>t({key:s,op:"add",n:Number(o)},r("add",s),i=>i.type==="counter"?i.value:null,null),push:(s,o)=>t({key:s,op:"push",item:o},r("push",s),i=>i.type==="list",!1),best:(s,o)=>t({key:s,op:"best",n:Number(o)},r("best",s),i=>i.type==="record"?{value:i.value,by:i.by,at:i.at,record:i.record}:null,null),claim:(s,o)=>t({key:s,op:"claim",field:String(o)},r("claim",s),i=>i.type==="map"&&i.ok,!1),release:(s,o)=>t({key:s,op:"release",field:String(o)},r("release",s),i=>i.type==="map"&&i.ok,!1),set:(s,o)=>t({key:s,op:"set",value:o},r("set",s),i=>i.type==="value",!1)}}function Et(n,e){let t=S.gameDataNumberMax,r=o=>{switch(o.op){case"add":return{type:"counter",min:0,max:t,add:[-t,t],guests:!0};case"push":return{type:"list",max:S.gameDataListMax,bytes:S.gameDataItemBytes,guests:!0};case"best":return{type:"record",order:"max",min:-t,max:t,guests:!0};case"claim":case"release":return{type:"map",fields:S.gameDataMapFields,perPlayer:S.gameDataMapPerPlayer,guests:!0};case"set":return{type:"value",bytes:S.gameDataValueBytes,guests:!0}}},s=o=>{try{let i=e.get(`onceworlds:game:${o}`);return i?JSON.parse(i):null}catch{return null}};return{async read(o){let i=s(o);if(!i)throw new Error(`nothing is stored under '${o}' on this page yet (on its own, game data lives in this browser).`);return i},async op(o){let i=await n(),l=s(o.key),c=r(o);if(l&&l.type!==c.type)throw new Error(`'${o.key}' holds a ${l.type} on this page: it was first used that way.`);let d=Ze(c,l,JSON.parse(JSON.stringify(o??null)),{id:i.id,name:i.name,host:!0},Date.now());if("code"in d)throw new Error(d.message);return e.set(`onceworlds:game:${o.key}`,JSON.stringify(d.next)),d.result}}}function Pt(n){return{messagesPerSecond:n.messagesPerSecond*.85,messageBurst:n.messagesPerSecond*2*.85,bytesPerSecond:n.bytesPerSecond*.85,byteBurst:n.bytesPerSecond*4*.85}}var Kn=60,Vn=100,Wn=5e3,ce=class{constructor(e={}){p(this,"queue",[]);p(this,"rates",Pt({messagesPerSecond:S.messagesPerSecond,bytesPerSecond:S.roomBytesPerSecond}));p(this,"messages",this.rates.messageBurst);p(this,"bytes",this.rates.byteBurst);p(this,"budget",{messagesPerSecond:S.messagesPerSecond,bytesPerSecond:S.roomBytesPerSecond});p(this,"refilledAt");p(this,"timer",null);p(this,"warnedAt",-1/0);p(this,"dropped",0);p(this,"now");p(this,"setTimer");p(this,"clearTimer");p(this,"warn");this.now=e.now??Date.now,this.setTimer=e.setTimer??((t,r)=>setTimeout(t,r)),this.clearTimer=e.clearTimer??(t=>clearTimeout(t)),this.warn=e.warn??(t=>console.warn(`[onceworlds] ${t}`)),this.refilledAt=this.now(),e.budget&&this.setBudget(e.budget)}setBudget(e){this.refill(),this.budget={messagesPerSecond:e.messagesPerSecond,bytesPerSecond:e.bytesPerSecond},this.rates=Pt(this.budget),this.messages=Math.min(this.messages,this.rates.messageBurst),this.bytes=Math.min(this.bytes,this.rates.byteBurst),this.drain(!1)}get waiting(){return this.queue.length}event(e,t){this.queue.push({kind:"event",size:e,send:t}),this.settle()}urgent(e,t){this.queue.push({kind:"event",size:e,send:t}),this.drain(!0)}state(e,t,r){for(let s=this.queue.length-1;s>=0;s--){let o=this.queue[s];if(o.kind!=="state")break;if(o.key===e)return o.size=t,o.send=r,this.settle()}this.queue.push({kind:"state",key:e,size:t,send:r}),this.settle()}spend(e){this.refill(),this.bytes-=e}clear(){this.queue=[],this.timer!==null&&this.clearTimer(this.timer),this.timer=null}settle(){this.queue.length>this.waitingLimit(Kn,12)&&(this.squeeze(),this.tell(`${this.queue.length} messages are waiting: a room takes about ${this.budget.messagesPerSecond} messages and ${Math.round(this.budget.bytesPerSecond/1024)} KB a second from each player. State is sent at its newest value and other messages in order. Send less: batch events, write state at 10-20 Hz, and only what changed.`)),this.drain(!1)}waitingLimit(e,t){return Math.max(t,Math.round(e*this.rates.messagesPerSecond/(S.messagesPerSecond*.85)))}refill(){let e=this.now(),t=Math.max(0,(e-this.refilledAt)/1e3);this.refilledAt=e,this.messages=Math.min(this.rates.messageBurst,this.messages+t*this.rates.messagesPerSecond),this.bytes=Math.min(this.rates.byteBurst,this.bytes+t*this.rates.bytesPerSecond)}drain(e){for(this.timer!==null&&(this.clearTimer(this.timer),this.timer=null),this.refill();this.queue.length>0;){let i=this.queue[0],l=Math.min(i.size(),this.rates.byteBurst);if(!e&&(this.messages<1||this.bytes<l))break;this.queue.shift(),this.messages-=1,this.bytes-=l;try{i.send()}catch(c){console.error("[onceworlds] a message could not be sent",c)}}if(this.queue.length===0)return;let t=Math.min(this.queue[0].size(),this.rates.byteBurst),r=Math.max(0,1-this.messages)/this.rates.messagesPerSecond,s=Math.max(0,t-this.bytes)/this.rates.bytesPerSecond,o=Math.min(250,Math.max(8,Math.ceil(Math.max(r,s)*1e3)));this.timer=this.setTimer(()=>{this.timer=null,this.drain(!1)},o)}squeeze(){let e=new Set;for(let s=this.queue.length-1;s>=0;s--){let o=this.queue[s];o.kind==="state"&&(e.has(o.key)?this.queue.splice(s,1):e.add(o.key))}let t=this.queue.filter(s=>s.kind==="event").length,r=this.waitingLimit(Vn,20);for(let s=0;t>r&&s<this.queue.length;)this.queue[s].kind==="event"?(this.queue.splice(s,1),t--,this.dropped++):s++;this.dropped>0&&this.tell(`${this.dropped} messages were dropped so the rest arrive fresh: the game sends much more than a room takes (${this.budget.messagesPerSecond} messages, ${Math.round(this.budget.bytesPerSecond/1024)} KB a second per player). Send less.`)}tell(e){let t=this.now();t-this.warnedAt<Wn||(this.warnedAt=t,this.warn(e))}};function q(n){try{let e=JSON.stringify(n)??"null",t=0;for(let r=0;r<e.length;r++)e.charCodeAt(r)>127&&(t+=2);return e.length+t+32}catch{return 1024}}var Ce=Math.PI*2;function Le(n,e,t,r={},s=""){if(typeof n=="number"&&typeof e=="number"){if(r.angles?.includes(s)){let o=((e-n)%Ce+Ce+Math.PI)%Ce-Math.PI;return n+o*t}return n+(e-n)*t}if(Array.isArray(n)&&Array.isArray(e)&&n.length===e.length)return e.map((o,i)=>Le(n[i],o,t,r,s));if(n&&e&&typeof n=="object"&&typeof e=="object"&&!Array.isArray(n)&&!Array.isArray(e)){let o={};for(let i of Object.keys(e))o[i]=i in n?Le(n[i],e[i],t,r,i):e[i];return o}return t<.5?n:e}function Jn(n,e,t){if(t===void 0||!n||!e||typeof n!="object"||typeof e!="object")return!1;for(let[r,s]of Object.entries(e)){let o=n[r];if(typeof s=="number"&&typeof o=="number"&&Math.abs(s-o)>t)return!0}return!1}function At(n,e,t={}){if(n.length===0)return;let r=n[0],s=n[n.length-1];if(e<=r.at)return r.d;if(e>=s.at)return s.d;let o=n.length-2;for(;o>0&&n[o].at>e;)o--;let i=n[o],l=n[o+1];return Jn(i.d,l.d,t.snap)?l.d:Le(i.d,l.d,(e-i.at)/Math.max(1,l.at-i.at),t)}var $t=8,Ct=2e3;var Yn=3e3,Qn=15e3,Zn=5e3;function Lt(n){let e={};for(let t of Object.keys(n))J(t)&&(e[t]=n[t]);return e}var I=()=>48,Z=class{constructor(e,t,r=Date.now,s=[]){p(this,"id");p(this,"kind");p(this,"invite");p(this,"teams");p(this,"open");p(this,"ranked");p(this,"kept");p(this,"me");p(this,"owner");p(this,"players",new Map);p(this,"state",{});p(this,"host");p(this,"closed",!1);p(this,"connected",!0);p(this,"match");p(this,"listeners",new Map);p(this,"transport");p(this,"outbox",new ce);p(this,"samples",new Map);p(this,"presenceTimer",null);p(this,"pendingPresence",null);p(this,"writes",0);p(this,"written",new Map);p(this,"confirmed",{});p(this,"shares",{messagesPerSecond:S.messagesPerSecond,presenceHz:S.presenceHz,bytesPerSecond:S.roomBytesPerSecond});p(this,"clock");p(this,"schema");p(this,"frozenSettings",null);p(this,"secrets",new Map);p(this,"offlineReady");p(this,"complained",new Map);p(this,"acks",new Map);this.transport=t,this.clock=r,this.schema=s,this.match=e.match??{phase:"lobby",n:0,min:1},this.applyBudget(e.budget),this.id=e.room,this.kind=e.room==="solo"?"solo":e.room.startsWith("private:")?"private":e.room.startsWith("room:")?"named":"public",this.invite=e.invite??null,this.teams=e.teams??0,this.open=e.open??!0,this.ranked=e.ranked??!1,this.kept=e.kept??Qe(e.room),this.owner=e.owner??null,this.host=e.host;for(let o of e.players)this.players.set(o.id,{...o}),o.presence!==null&&o.presence!==void 0&&this.samples.set(o.id,[{at:e.now??this.clock(),d:o.presence}]);this.me=this.players.get(e.you)??{id:e.you,name:"You",presence:null,team:0},this.players.set(this.me.id,this.me),this.state={...e.state},this.confirmed=Lt(e.state);for(let[o,i]of Object.entries(e.private??{}))this.secrets.set(o,{...i});this.match.phase!=="lobby"&&(this.frozenSettings=this.chosenSettings())}get budget(){return this.shares}get settings(){return this.frozenSettings??this.chosenSettings()}setSetting(e,t){if(this.closed||!this.isHost||this.match.phase!=="lobby")return;let r=this.schema.find(o=>o.id===e);if(!r||!r.options.some(o=>o.value===t)||this.chosenSettings()[e]===t)return;let s=this.state[Y];this.setState(Y,{...s!==null&&typeof s=="object"?s:{},[e]:t}),this.clearReady(),this.emit("settings",this.settings)}chosenSettings(){let e=this.state[Y];return Object.fromEntries(this.schema.map(t=>[t.id,et(t,e)]))}get isHost(){return this.connected&&this.host===this.me.id}get online(){return[...this.players.values()].filter(e=>e.connected!==!1)}get participants(){let e=this.match.participants;return this.match.phase==="lobby"||!e?[]:e.map(t=>this.players.get(t)).filter(t=>!!t)}get spectators(){let e=this.match.participants;return this.match.phase==="lobby"||!e?[]:this.online.filter(t=>!e.includes(t.id))}get leftOut(){let e=this.match.left;return this.match.phase==="lobby"||!e?.length?[]:this.spectators.filter(t=>e.includes(t.id))}get private(){return this.secrets.get(this.me.id)??{}}privateOf(e){return e===this.me.id||this.isHost?this.secrets.get(e)??{}:{}}setPrivate(e,t){this.closed||(this.setSecret(this.me.id,e,t??null),this.outbox.event(()=>q(t),()=>this.transport.private(e,t??null)))}setPrivateFor(e,t,r){if(!this.closed){if(e===this.me.id)return this.setPrivate(t,r);this.outbox.event(()=>q(r),()=>this.transport.private(t,r??null,String(e)))}}presenceAt(e,t={}){if(e===this.me.id)return this.me.presence;let r=this.samples.get(e);return!r||r.length===0?this.players.get(e)?.presence??null:At(r,this.clock()-(t.delay??100),t)}keep(e,t,r){let s=this.samples.get(e)??[],o=s.length;for(;o>0&&s[o-1].at>t;)o--;for(s.splice(o,0,{at:t,d:r});s.length>$t||s.length>2&&s[0].at<t-Ct;)s.shift();this.samples.set(e,s)}isParticipant(e=this.me.id){return this.match.phase!=="lobby"&&!!this.match.participants?.includes(e)}get spectating(){return this.match.phase!=="lobby"&&!this.isParticipant()}get running(){return this.match.phase==="playing"&&!this.match.paused}matchNow(){let e=this.match;if(e.phase!=="playing"||e.startedAt===void 0)return 0;let t=this.clock(),r=(e.pausedMs??0)+(e.paused?Math.max(0,t-e.paused.since):0);return Math.max(0,t-e.startedAt-r)}get canStart(){return this.isHost&&this.kind!=="public"&&this.match.phase==="lobby"&&this.online.length>=this.match.min&&this.allReady}get allReady(){return this.notReady.length===0}get notReady(){return this.online.filter(e=>e.id!==this.host&&!e.ready)}setReady(e=!0){this.closed||!!this.me.ready===e||(e?this.me.ready=!0:delete this.me.ready,this.connected||(this.offlineReady=e),this.outbox.urgent(I,()=>this.transport.ready(e)))}startMatch(e={}){if(!this.reachable("startMatch"))return;let t=Number(e.countdown),r={...Number.isFinite(t)?{countdown:Math.round(t*1e3)}:{},...e.open===!0?{open:!0}:{}};this.outbox.urgent(I,()=>this.transport.start(r))}endMatch(){this.reachable("endMatch")&&this.outbox.urgent(I,()=>this.transport.end())}pauseMatch(e=!0){this.reachable("pauseMatch")&&this.outbox.urgent(I,()=>this.transport.pause(e))}admit(e){let t=(Array.isArray(e)?e:[e]).map(String);t.length&&this.reachable("admit")&&this.outbox.urgent(I,()=>this.transport.admit(t))}reachable(e){let[t,r]=this.closed?["closed","this room is closed (you left it, were removed, or moved to another one)"]:this.connected?["",""]:["disconnected","the connection to the room is down and the platform is reconnecting: call it again after room.on('reconnect')"];return t?(this.complain(e,t,r),!1):!0}dropHostWrites(){for(let e of[...this.written.keys()]){if(!J(e))continue;this.written.delete(e);let t=this.confirmed[e]??null;JSON.stringify(this.state[e]??null)!==JSON.stringify(t)&&(t===null?delete this.state[e]:this.state[e]=t,this.emit("state",e,t,""))}}complain(e,t,r){let s=this.clock(),o=`${e}:${t}`;if(s-(this.complained.get(o)??-1/0)<Zn)return;this.complained.set(o,s);let i=`${e}() did nothing: ${r}.`;console.warn(`[onceworlds] ${i} (${t})`),this.emit("error",{code:t,message:i})}transferHost(e){this.closed||this.outbox.urgent(I,()=>this.transport.transfer(String(e)))}hideLobby(e=!0){this.closed||this.transport.hideLobby?.(!!e)}clearReady(){if(!(this.closed||!this.isHost)){for(let e of this.players.values())delete e.ready;this.outbox.urgent(I,()=>this.transport.unready())}}send(e,t={}){this.closed||this.outbox.event(()=>q(e),()=>this.transport.send(e,t.to))}setPresence(e){if(!this.closed){if(this.me.presence=e,this.presenceTimer){this.pendingPresence={value:e};return}this.transport.presence(e),this.outbox.spend(q(e)),this.presenceTimer=setTimeout(()=>this.flushPresence(),1e3/this.shares.presenceHz)}}setState(e,t){this.writeState(e,t)}writeState(e,t){if(this.closed)return 0;if(J(e)&&this.connected&&this.host!==this.me.id)return this.complain("setState","not_host",`only the host writes ${e}`),0;t==null?delete this.state[e]:this.state[e]=t;let r=++this.writes;return this.written.set(e,{w:r,at:this.clock()}),this.outbox.state(e,()=>q(t)+e.length,()=>this.transport.state(e,t??null,r)),r}_writeAcked(e,t){if(this.closed||!this.connected)return Promise.resolve(!1);let r=this.writeState(e,t);return r?this.kind==="solo"?Promise.resolve(!0):new Promise(s=>{let o={w:r,done:l=>{clearTimeout(i),s(l)}},i=setTimeout(()=>this.settleAcks(e,l=>l===o,!1),Qn);this.acks.set(e,[...this.acks.get(e)??[],o])}):Promise.resolve(!1)}_resetData(){return this.closed||!this.connected||!this.transport.dataReset?!1:(this.outbox.urgent(I,()=>this.transport.dataReset()),!0)}settleAcks(e,t,r){let s=this.acks.get(e);if(!s)return;let o=s.filter(i=>!t(i));o.length>0?this.acks.set(e,o):this.acks.delete(e);for(let i of s)t(i)&&i.done(r)}failAcks(){for(let e of[...this.acks.keys()])this.settleAcks(e,()=>!0,!1)}setTeam(e,t){this.closed||this.outbox.urgent(I,()=>this.transport.team(e,t))}setOpen(e){this.closed||this.outbox.urgent(I,()=>this.transport.open(e))}reportResult(e){this.closed||this.outbox.urgent(()=>q(e),()=>this.transport.result(e))}kick(e){this.closed||this.outbox.urgent(I,()=>this.transport.kick(String(e)))}voteKick(e){this.closed||this.outbox.urgent(I,()=>this.transport.voteKick(String(e)))}on(e,t){let r=this.listeners.get(e);return r||this.listeners.set(e,r=new Set),r.add(t),()=>r.delete(t)}leave(){this.closed||(this.transport.leave(),this.close("left"))}_receive(e){switch(e.t){case"welcome":return this.resync(e);case"away":{let t=this.players.get(e.id);return!t||t===this.me?void 0:(t.connected=!1,this.emit("away",t))}case"back":{let t=this.players.get(e.id);return!t||t===this.me?void 0:(delete t.connected,this.emit("back",t,e.fresh===!0))}case"ready":{let t=this.players.get(e.id);return!t||!!t.ready==(e.ready===!0)?void 0:(e.ready===!0?t.ready=!0:delete t.ready,this.emit("ready",t))}case"match":return this.applyMatch(e.match);case"idle":{let t=this.players.get(e.id);return!t||t===this.me||!!t.idle==(e.idle===!0)?void 0:(e.idle===!0?t.idle=!0:delete t.idle,this.emit("idle",t))}case"private":{let t=JSON.stringify(this.secrets.get(e.id)?.[e.k]??null);this.setSecret(e.id,e.k,e.v??null),t!==JSON.stringify(e.v??null)&&this.emit("private",e.k,e.v??null,e.id);return}case"privates":return this.applySecrets(e.all??{});case"unready":{for(let t of this.players.values())t.ready&&(delete t.ready,this.emit("ready",t));return}case"join":{let t={...e.player};return this.players.set(t.id,t),this.emit("join",t)}case"leave":{let t=this.players.get(e.id);return!t||t===this.me?void 0:(this.players.delete(e.id),this.samples.delete(e.id),this.emit("leave",t,e.kicked===!0))}case"votekick":{let t=this.players.get(e.id);t&&this.emit("votekick",t,e.votes,e.needed);return}case"host":if(this.host=e.id,e.id!==this.me.id)for(let t of[...this.secrets.keys()])t!==this.me.id&&this.secrets.delete(t);return e.id!==this.me.id&&(this.dropHostWrites(),this.failAcks()),this.emit("host",e.id);case"msg":return this.emit("message",e.d,this.players.get(e.from)??{id:e.from,name:"Unknown",presence:null,team:0},typeof e.at=="number"?e.at:this.clock(),typeof e.mt=="number"?e.mt:void 0);case"team":{let t=this.players.get(e.id);return t?(t.team=e.team,this.emit("team",t)):void 0}case"name":{let t=e.id===this.me.id?this.me:this.players.get(e.id);return!t||typeof e.name!="string"||t.name===e.name?void 0:(t.name=e.name,this.emit("rename",t))}case"open":return this.open=e.open,this.emit("open",e.open);case"rated":for(let t of e.changes){let r=this.players.get(t.id);r&&(r.rating=t.rating)}return this.emit("rated",e.changes,e.disputed,e.capped===!0);case"presence":{let t=this.players.get(e.id);return!t||t===this.me?void 0:(t.presence=e.d,this.keep(e.id,typeof e.at=="number"?e.at:this.clock(),e.d),this.emit("presence",t))}case"state":{e.from===this.me.id&&typeof e.w=="number"&&this.settleAcks(e.k,s=>s.w<=e.w,!0),J(e.k)&&(e.v===null?delete this.confirmed[e.k]:this.confirmed[e.k]=e.v);let t=this.written.get(e.k);if(t)if(e.from===this.me.id)if(typeof e.w!="number")this.written.delete(e.k);else{if(e.w<t.w)return;e.w===t.w&&this.written.delete(e.k)}else{if(this.clock()-t.at<Yn)return;this.written.delete(e.k)}let r=JSON.stringify(this.state[e.k]??null);e.v===null?delete this.state[e.k]:this.state[e.k]=e.v,(e.from!==this.me.id||r!==JSON.stringify(e.v??null))&&this.emit("state",e.k,e.v,e.from),e.k===Y&&this.schema.length>0&&this.frozenSettings===null&&r!==JSON.stringify(e.v??null)&&e.from!==this.me.id&&this.emit("settings",this.settings);return}case"chat":return this.emit("chat",e.entry);case"error":return typeof e.k=="string"&&typeof e.w=="number"&&this.settleAcks(e.k,t=>t.w===e.w,!1),e.code==="cooldown"&&this.me.ready&&(delete this.me.ready,this.emit("ready",this.me)),console.warn(`[onceworlds] ${e.message} (${e.code})`),this.emit("error",{code:e.code,message:e.message})}}_closed(e){this.close(e)}_disconnected(){this.closed||!this.connected||(this.connected=!1,this.outbox.clear(),this.failAcks(),this.emit("disconnect"))}close(e){this.closed||(this.closed=!0,this.outbox.clear(),this.failAcks(),this.presenceTimer&&clearTimeout(this.presenceTimer),this.emit("close",e))}flushPresence(){if(this.presenceTimer=null,!this.pendingPresence||this.closed)return;let{value:e}=this.pendingPresence;this.pendingPresence=null,this.transport.presence(e),this.outbox.spend(q(e)),this.presenceTimer=setTimeout(()=>this.flushPresence(),1e3/this.shares.presenceHz)}applyBudget(e){if(!e)return;let t=(r,s)=>typeof r=="number"&&Number.isFinite(r)&&r>0&&r<=s;t(e.presenceHz,S.presenceHz)&&(this.shares={...this.shares,presenceHz:e.presenceHz}),t(e.messagesPerSecond,S.messagesPerSecond)&&t(e.bytesPerSecond,S.roomBytesPerSecond)&&(this.shares={...this.shares,messagesPerSecond:e.messagesPerSecond,bytesPerSecond:e.bytesPerSecond},this.outbox.setBudget({messagesPerSecond:e.messagesPerSecond,bytesPerSecond:e.bytesPerSecond}))}setSecret(e,t,r){let s={...this.secrets.get(e)??{}};r===null?delete s[t]:s[t]=r,Object.keys(s).length>0?this.secrets.set(e,s):this.secrets.delete(e)}applySecrets(e){let t=[];for(let[r,s]of Object.entries(e))for(let[o,i]of Object.entries(s))JSON.stringify(this.secrets.get(r)?.[o]??null)!==JSON.stringify(i)&&t.push([r,o,i]);for(let[r,s]of this.secrets)for(let o of Object.keys(s))o in(e[r]??{})||t.push([r,o,null]);this.secrets=new Map(Object.entries(e).map(([r,s])=>[r,{...s}]));for(let[r,s,o]of t)this.emit("private",s,o,r)}applyMatch(e){let t=this.match;if(!(!e||JSON.stringify(t)===JSON.stringify(e))){if(this.match=e,e.phase!=="lobby"&&this.frozenSettings===null)this.frozenSettings=this.chosenSettings();else if(e.phase==="lobby"&&this.frozenSettings!==null){let r=JSON.stringify(this.frozenSettings);this.frozenSettings=null,r!==JSON.stringify(this.chosenSettings())&&queueMicrotask(()=>this.emit("settings",this.settings))}this.emit("match",e,t),t.phase!=="starting"&&e.phase==="starting"&&this.emit("starting",e),t.phase!=="playing"&&e.phase==="playing"&&this.emit("matchstart",e),t.phase!=="lobby"&&e.phase==="lobby"&&this.emit("matchend",e,t),t.phase==="playing"&&e.phase==="playing"&&(!t.paused&&e.paused?this.emit("matchpause",e):t.paused&&!e.paused&&this.emit("matchresume",e))}}resync(e){let t=this.connected,r=this.host!==e.host;this.connected=!0,this.host=e.host,this.written.clear(),this.confirmed=Lt(e.state),this.applyBudget(e.budget);let s=new Set;for(let i of e.players){if(s.add(i.id),i.id===this.me.id){this.offlineReady===void 0&&!!this.me.ready!=!!i.ready&&(i.ready?this.me.ready=!0:delete this.me.ready,this.emit("ready",this.me));continue}let l=this.players.get(i.id);if(l)l.presence=i.presence,i.presence!==null&&i.presence!==void 0&&this.keep(i.id,e.now??this.clock(),i.presence),l.team=i.team,l.name!==i.name&&(l.name=i.name,this.emit("rename",l)),!!l.ready!=!!i.ready&&(i.ready?l.ready=!0:delete l.ready,this.emit("ready",l)),!!l.idle!=!!i.idle&&(i.idle?l.idle=!0:delete l.idle,this.emit("idle",l)),l.connected===!1!=(i.connected===!1)&&(i.connected===!1?l.connected=!1:delete l.connected,i.connected===!1?this.emit("away",l):this.emit("back",l,!1));else{let c={...i};this.players.set(i.id,c),this.emit("join",c)}}for(let[i,l]of this.players)s.has(i)||l===this.me||(this.players.delete(i),this.emit("leave",l));let o=new Set([...Object.keys(this.state),...Object.keys(e.state)]);for(let i of o){let l=e.state[i]??null;JSON.stringify(this.state[i]??null)!==JSON.stringify(l)&&(l===null?delete this.state[i]:this.state[i]=l,this.emit("state",i,l,""))}r&&this.emit("host",e.host),this.teams=e.teams??this.teams,this.kept=e.kept??this.kept,e.open!==void 0&&e.open!==this.open&&(this.open=e.open,this.emit("open",e.open)),this.applyMatch(e.match??{phase:"lobby",n:0,min:1}),this.applySecrets(e.private??{}),this.me.presence!==null&&this.transport.presence(this.me.presence),this.offlineReady!==void 0&&!!e.players.find(i=>i.id===this.me.id)?.ready!==this.offlineReady&&this.transport.ready(this.offlineReady),this.offlineReady=void 0,t||this.emit("reconnect")}emit(e,...t){for(let r of this.listeners.get(e)??[])try{r(...t)}catch(s){console.error(`[onceworlds] error in room "${e}" listener`,s)}}};function _t(n){let e=null,t=s=>n()._receive({t:"match",match:s}),r=()=>{let o=n().match;if(o.phase!=="starting")return;let{startsAt:i,...l}=o;t({...l,phase:"playing",startedAt:Date.now(),pausedMs:0})};return{send(){},presence(){},state(){},team(){},open(){},result(){},kick(){},voteKick(){},ready(){},unready(){},transfer(){},start(s){let o=n();if(o.match.phase!=="lobby")return;let i=Math.min(S.matchCountdownMaxMs,Math.max(0,s.countdown??S.matchCountdownMs));t({phase:"starting",n:o.match.n+1,min:o.match.min,id:`solo${o.match.n+1}`,seed:Math.floor(Math.random()*2**32),participants:[o.me.id],startsAt:Date.now()+i}),i===0?r():e=setTimeout(r,i)},end(){let s=n();e&&clearTimeout(e),e=null,s.match.phase!=="lobby"&&t({phase:"lobby",n:s.match.n,min:s.match.min})},pause(s){let o=n().match;if(o.phase!=="playing")return;let i=Date.now();if(s&&!o.paused)t({...o,paused:{since:i,reason:"host"}});else if(!s&&o.paused){let{paused:l,...c}=o;t({...c,pausedMs:(o.pausedMs??0)+Math.max(0,i-l.since)})}},admit(){},private(){},leave(){e&&clearTimeout(e),e=null}}}var Dt=["pointerdown","pointermove","keydown","wheel","touchstart","touchmove","devicemotion","visibilitychange"],Xn=5e3;function Ot(n,e=S.idleAfterMs){let t=Date.now(),r=!1,s=()=>{t=Date.now(),r&&(r=!1,n(!1))},o=()=>{try{for(let l of navigator.getGamepads?.()??[])if(l&&(l.buttons.some(c=>c.pressed)||l.axes.some(c=>Math.abs(c)>.25)))return!0}catch{}return!1};for(let l of Dt)window.addEventListener(l,s,{capture:!0,passive:!0});let i=setInterval(()=>{if(o())return s();!r&&Date.now()-t>e&&(r=!0,n(!0))},Xn);return{get idle(){return r},stop(){clearInterval(i);for(let l of Dt)window.removeEventListener(l,s,{capture:!0})}}}var Tt=["pointerdown","keydown","touchstart","gamepadconnected"];function It(n,e){let t=r=>{if(!(!r.isTrusted||!n())){for(let s of Tt)window.removeEventListener(s,t,{capture:!0});e()}};for(let r of Tt)window.addEventListener(r,t,{capture:!0,passive:!0})}var Nt=["low","medium","high"],er={low:.6,medium:.8,high:1},tr=24,nr=18.5,rr=26,_e=6e3,Bt=2e4,or=5*6e4,De=class{constructor(e=2){p(this,"level",2);p(this,"slow",0);p(this,"smoothSince",0);p(this,"holdUntil",0);p(this,"probeAfter",Bt);p(this,"steppedUpAt",-1/0);this.level=e}window(e,t,r){return t>tr?(this.smoothSince=0,++this.slow>=2&&e>=this.holdUntil&&this.level>0&&(e-this.steppedUpAt<_e+Bt/2&&(this.probeAfter=Math.min(or,this.probeAfter*2)),this.level--,this.slow=0,this.holdUntil=e+_e)):t<=nr&&r<=rr?(this.slow=0,this.smoothSince||(this.smoothSince=e),this.level<Nt.length-1&&e>=this.holdUntil&&e-this.smoothSince>=this.probeAfter&&(this.level++,this.steppedUpAt=e,this.smoothSince=0,this.holdUntil=e+_e)):(this.slow=0,this.smoothSince=0),this.level}};function Gt(n){let e="auto",t=typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches,r=!1,s=new De(sr()?1:2),o=new Set,i=!1,l=!1,c=0,d=[],m=0,h=0,f=M=>{if(i){if(c&&!document.hidden){let P=M-c;P<250&&d.push(P)}if(c=document.hidden?0:M,m||(m=M),M-m>=1e3){if(d.length>=10){let P=[...d].sort((j,A)=>j-A),L=d.reduce((j,A)=>j+A,0)/d.length,U=P[Math.min(P.length-1,Math.floor(P.length*.95))],N=E();e==="auto"&&s.window(M,L,U),r&&M-h>=500&&(h=M,n.stats({fps:Math.round(1e3/L),frameMs:Math.round(L*10)/10,worstMs:Math.round(P[P.length-1]*10)/10})),E()!==N&&_()}d=[],m=M}w()}},w=()=>{l||!i||(l=!0,requestAnimationFrame(M=>{l=!1,f(M)}))},y=()=>{i||typeof requestAnimationFrame!="function"||(i=!0,c=0,m=0,w())},k=()=>{!r&&e!=="auto"&&i&&(i=!1)},E=()=>e==="auto"?Nt[s.level]:e,_=()=>{for(let M of o)try{M(T)}catch(P){console.error('[onceworlds] error in settings "change" listener',P)}},T={get choice(){return e},get quality(){return e==="auto"&&y(),E()},get scale(){return er[T.quality]},get reducedMotion(){return t},pixelRatio(M=2){let P=typeof devicePixelRatio=="number"&&devicePixelRatio>0?devicePixelRatio:1;return Math.max(.5,Math.min(P,M)*T.scale)},on(M,P){return M!=="change"?()=>{}:(o.add(P),e==="auto"&&y(),()=>o.delete(P))}};return{settings:T,apply(M){let P=`${E()}|${t}`;e=M.quality,t=M.reducedMotion,r=M.showStats,r||e==="auto"&&o.size>0?y():k(),`${E()}|${t}`!==P&&_()}}}function sr(){return typeof matchMedia=="function"&&matchMedia("(pointer: coarse)").matches}var X={maxSide:1280,quality:.85,maxBytes:15e5,answerMs:2500,waitMs:3e3,perSecond:3};var ir=4,ar=250,lr=1e3;function cr(){return typeof window>"u"||typeof document>"u"?null:{document,requestAnimationFrame:n=>window.requestAnimationFrame(n),setTimeout:(n,e)=>window.setTimeout(n,e),clearTimeout:n=>window.clearTimeout(n),background:n=>window.getComputedStyle(n).backgroundColor,hidden:()=>document.visibilityState==="hidden"}}function ur(n){if(!n||typeof n!="object")return null;let e=n;if(typeof e.id!="number"||!Number.isSafeInteger(e.id)||e.id<0)return null;let t=typeof e.maxSide=="number"&&Number.isFinite(e.maxSide)?Math.min(X.maxSide,Math.max(64,Math.round(e.maxSide))):X.maxSide,r=typeof e.quality=="number"&&Number.isFinite(e.quality)?Math.min(.95,Math.max(.5,e.quality)):X.quality;return{id:e.id,maxSide:t,quality:r}}function dr(n,e,t){let r=Math.min(1,t/Math.max(n,e,1)),s=o=>Math.max(1,Math.min(t,Math.round(o*r)));return{width:s(n),height:s(e)}}function mr(n){for(let e=0;e+2<n.length;e+=4)if(n[e]!==0||n[e+1]!==0||n[e+2]!==0)return!1;return!0}var pr=/^(?:transparent|rgba\(.*,\s*0(?:\.0*)?\))$/;function fr(n,e){try{for(let t=n;t;t=t.parentElement){let r=e.background?.(t)?.trim();if(r&&!pr.test(r))return r}}catch{}return"#000"}function Oe(n,e,t,r,s){try{let o=r.document.createElement("canvas");o.width=e.width,o.height=e.height;let i=o.getContext("2d");if(!i)return{miss:"unsupported"};if(i.drawImage(n,0,0,e.width,e.height),mr(i.getImageData(0,0,e.width,e.height).data))return{miss:"blank"};i.globalCompositeOperation="destination-over",i.fillStyle=s(),i.fillRect(0,0,e.width,e.height);for(let l of[t.quality,.6]){let c=o.toDataURL("image/jpeg",l);if(!c.startsWith("data:image/jpeg;base64,"))return{miss:"unsupported"};if((c.length-23)*.75<=X.maxBytes)return{image:c}}return{miss:"failed"}}catch(o){return{miss:o?.name==="SecurityError"?"tainted":"failed"}}}function jt(n,e){let t=!1,r=()=>{t||(t=!0,e())};n.requestAnimationFrame(r),n.setTimeout(r,ar)}function gr(n,e,t){return new Promise(r=>{let s,o;try{if(typeof n.captureStream!="function")return r(null);s=n.captureStream(),o=e.document.createElement("video"),o.muted=!0,o.playsInline=!0,o.srcObject=s}catch{return r(null)}let i=!1,l=m=>{if(!i){i=!0,e.clearTimeout(c);try{o.srcObject=null;for(let h of s.getTracks())h.stop()}catch{}r(m)}},c=e.setTimeout(()=>l(null),lr),d=()=>{!i&&o.videoWidth>0&&o.videoHeight>0&&l(t(o))};try{o.addEventListener("loadeddata",d),o.addEventListener("playing",d),o.play()?.catch(()=>{})}catch{l(null)}})}function Ht(n,e=cr()){let t=!1,r=o=>{try{n(o)}catch{}};function s(o){let i=o.id;if(!e)return r({id:i,t:"none",reason:"unsupported"});if(t)return r({id:i,t:"none",reason:"busy"});let l=e,c=ie(l.document.querySelectorAll("canvas"));if(!c)return r({id:i,t:"none",reason:"no-canvas"});t=!0;let d=k=>{t=!1,r("image"in k?{id:i,t:"done",image:k.image}:{id:i,t:"none",reason:k.miss})},m=dr(c.width,c.height,o.maxSide),h=null,f=()=>h??(h=fr(c,l));if(l.hidden?.()){let k=Oe(c,m,o,l,f);return d("miss"in k&&k.miss==="blank"?{miss:"hidden"}:k)}let w=0,y=()=>{try{let k=Oe(c,m,o,l,f);if(!("miss"in k)||k.miss!=="blank")return d(k);if(++w<ir)return jt(l,y);gr(c,l,E=>Oe(E,m,o,l,f)).then(E=>d(E??{miss:"blank"}),()=>d({miss:"blank"}))}catch{d({miss:"failed"})}};jt(l,y)}return{receive(o){let i=null;try{i=ur(o),i&&s(i)}catch{t=!1,i&&r({id:i.id,t:"none",reason:"failed"})}}}}var qt=(n,e)=>Object.prototype.hasOwnProperty.call(n,e);function Te(n){try{return n(),!0}catch{return!1}}function hr(){let n=new Map,e={getItem:t=>n.has(String(t))?n.get(String(t)):null,setItem:(t,r)=>{n.set(String(t),String(r))},removeItem:t=>{n.delete(String(t))},clear:()=>n.clear(),key:t=>[...n.keys()][Number(t)]??null};return new Proxy(e,{get(t,r){if(r==="length")return n.size;if(r===Symbol.toStringTag)return"Storage";if(typeof r=="string")return qt(e,r)?t[r]:n.get(r)},set(t,r,s){return typeof r=="string"&&n.set(r,String(s)),!0},has:(t,r)=>typeof r=="string"&&(qt(e,r)||n.has(r)),deleteProperty(t,r){return typeof r=="string"&&n.delete(r),!0},ownKeys:()=>[...n.keys()],getOwnPropertyDescriptor:(t,r)=>typeof r=="string"&&n.has(r)?{value:n.get(r),writable:!0,enumerable:!0,configurable:!0}:void 0})}function yr(n=Date.now){let e=new Map;return{read:()=>[...e].map(([t,r])=>`${t}=${r}`).join("; "),write(t){let[r,...s]=String(t).split(";"),o=r.indexOf("="),i=(o<0?"":r.slice(0,o)).trim(),l=(o<0?r:r.slice(o+1)).trim();if(!i&&!l)return;let c=!1;for(let d of s){let[m,...h]=d.split("="),f=h.join("=").trim();m.trim().toLowerCase()==="max-age"&&Number(f)<=0&&(c=!0),m.trim().toLowerCase()==="expires"&&Date.parse(f)<=n()&&(c=!0)}c?e.delete(i):e.set(i,l)}}}function ee(n,e,t){try{Object.defineProperty(n,e,{configurable:!0,...t})}catch{}}function br(){if(typeof HTMLImageElement!="function")return;let n=Object.getOwnPropertyDescriptor(HTMLImageElement.prototype,"src");if(!n?.get||!n.set)return;let{get:e,set:t}=n;ee(HTMLImageElement.prototype,"src",{enumerable:n.enumerable,get(){return e.call(this)},set(r){try{this.crossOrigin===null&&new URL(String(r),document.baseURI).origin===location.origin&&(this.crossOrigin="anonymous")}catch{}t.call(this,r)}})}function wr(){let n=window.Worker;if(typeof n!="function")return;let e=function(t,r){try{return new n(t,r)}catch(s){if(!(s instanceof DOMException&&s.name==="SecurityError")||r?.type==="module")throw s;let o;try{o=new URL(String(t),document.baseURI)}catch{throw s}if(o.origin!==location.origin)throw s;let l=`const base = ${JSON.stringify(o.href)};
3
+ const resolve = (input) => new URL(String(input), base).href;
4
+ const importScripts_ = self.importScripts.bind(self);
5
+ self.importScripts = (...urls) => importScripts_(...urls.map(resolve));
6
+ const fetch_ = self.fetch.bind(self);
7
+ self.fetch = (input, init) => fetch_(typeof input === 'string' || input instanceof URL ? resolve(input) : input, init);
8
+ if (typeof XMLHttpRequest === 'function') {
9
+ const open_ = XMLHttpRequest.prototype.open;
10
+ XMLHttpRequest.prototype.open = function (method, url, ...rest) { return open_.call(this, method, resolve(url), ...rest); };
11
+ }
12
+ importScripts(base);`;return new n(URL.createObjectURL(new Blob([l],{type:"text/javascript"})),r)}};e.prototype=n.prototype,ee(window,"Worker",{value:e,writable:!0})}function zt(){try{for(let n of["localStorage","sessionStorage"])Te(()=>window[n].length)||ee(window,n,{value:hr()});if(!Te(()=>document.cookie)){let n=yr();ee(document,"cookie",{get:()=>n.read(),set:e=>n.write(e)})}if(window.origin==="null"&&(wr(),br()),window.origin==="null"||!Te(()=>history.replaceState(history.state,"",location.href)))for(let n of["pushState","replaceState"]){let e=history[n];ee(history,n,{value:function(...t){try{return e.apply(this,t)}catch(r){if(!(r instanceof DOMException&&r.name==="SecurityError"))throw r}}})}}catch{}}var kr=["menu","lobby","stick","buttons"];function Ft(n){if(!Array.isArray(n)||n.length>16)return null;let e=[];for(let t of n){if(!t||typeof t!="object")continue;let{kind:r,x:s,y:o,w:i,h:l}=t;kr.includes(r)&&(!ue(s)||!ue(o)||!ue(i)||!ue(l)||i<0||l<0||e.push({kind:r,x:s,y:o,w:i,h:l}))}return e}var ue=n=>typeof n=="number"&&Number.isFinite(n),Ie={entries:10,entryMs:1e3,totalMs:2e3};function Kt(n){let e=typeof n=="number"?[n]:Array.isArray(n)?n.slice(0,Ie.entries):null;if(!e||!e.every(s=>typeof s=="number"&&Number.isFinite(s)&&s>=0))return null;let t=[],r=Ie.totalMs;for(let s of e){let o=Math.min(Math.round(s),Ie.entryMs,r);if(t.push(o),r-=o,r<=0)break}return t.some((s,o)=>o%2===0&&s>0)?t:[]}var vr=/^#(?:[0-9a-f]{3}){1,2}$/i,te={panel:"#111216",text:"#f7f7f8",accent:"#d33e00"},Ne=4.5,Be=3,de=["#4ade80","#15803d"];function Vt(n){let e=[];if(n==null)return{look:null,notes:e};if(typeof n!="object")return{look:null,notes:["a look is { accent, panel, text } or null"]};let t=n,r=m=>{let h=t[m];return h==null?null:typeof h=="string"&&vr.test(h)?Wt(h):(e.push(`${m} is not #rgb or #rrggbb`),null)},s=r("panel"),o=r("text"),i=r("accent");if(s||o){let m=z(o??te.text,s??te.panel);m<Ne&&(e.push(`text on panel is ${m.toFixed(1)}:1, under ${Ne}:1: the platform's are used`),s=o=null)}let l=s??te.panel,c=o??te.text;if(i){let m=z(i,l);m<Be&&(e.push(`accent on panel is ${m.toFixed(1)}:1, under ${Be}:1: the platform's is used`),i=null)}if(!i&&s&&z(te.accent,s)<Be&&(i=c),!s&&!o&&!i)return{look:null,notes:e};let d=i?Sr(i):null;return{look:{panel:s,text:o,muted:s||o?xr(c,l):null,accent:i,accentHover:i?Jt(i,d==="#ffffff"?"#000000":"#ffffff",.14):null,onAccent:d,ok:s?z(de[0],s)>=z(de[1],s)?de[0]:de[1]:null},notes:e}}function Wt(n){let e=n.slice(1).toLowerCase();return`#${e.length===3?[...e].map(t=>t+t).join(""):e}`}function Ge(n){let e=Wt(n);return[parseInt(e.slice(1,3),16),parseInt(e.slice(3,5),16),parseInt(e.slice(5,7),16)]}function Ut(n){let[e,t,r]=Ge(n).map(s=>{let o=s/255;return o<=.04045?o/12.92:((o+.055)/1.055)**2.4});return .2126*e+.7152*t+.0722*r}function z(n,e){let[t,r]=[Ut(n),Ut(e)].sort((s,o)=>o-s);return(t+.05)/(r+.05)}function Sr(n){return z(n,"#000000")>z(n,"#ffffff")?"#000000":"#ffffff"}function Jt(n,e,t){let[r,s]=[Ge(n),Ge(e)];return`#${r.map((o,i)=>Math.round(o+(s[i]-o)*t).toString(16).padStart(2,"0")).join("")}`}function xr(n,e){for(let t=.3;t>.001;t-=.05){let r=Jt(n,e,t);if(z(r,e)>=Ne)return r}return n}var me=class{constructor(){p(this,"areas",null);p(this,"key","")}receive(e){let t=Ft(e);if(!t)return!1;let r=JSON.stringify(t);return this.areas&&r===this.key?!1:(this.key=r,this.areas=Object.freeze(t.map(s=>Object.freeze(s))),!0)}};function Yt(n){let e={look:null,notes:["a look is { accent, panel, text } or null"]};if(n==null)return{look:null,notes:[]};if(typeof n!="object")return e;let t={};try{for(let r of["accent","panel","text"]){let s=n[r];s!=null&&(t[r]=typeof s=="string"?s.slice(0,16):"")}}catch{return e}return{look:t,notes:Vt(t).notes}}function Qt(n,e,t){let r=typeof n.vibrate=="function"?n.vibrate.bind(n):null,s=o=>{try{if(!e())return r?r(o):!1;if(!r)return!1;let i=Kt(Array.isArray(o)?Array.from(o):o);return i?(t(i),!0):!1}catch{return!1}};try{Object.defineProperty(n,"vibrate",{value:s,configurable:!0,writable:!0})}catch{}}var Mr=["RTCPeerConnection","webkitRTCPeerConnection","mozRTCPeerConnection"];function Zt(n){if(n)for(let e of Mr)try{Object.defineProperty(n,e,{value:void 0,writable:!1,enumerable:!1,configurable:!1})}catch{}}function Xt(n,e){if(Zt(n),!!e)for(let t of["contentWindow","contentDocument"])try{let r=Object.getOwnPropertyDescriptor(e.prototype,t),s=r?.get;if(!r||!s)continue;Object.defineProperty(e.prototype,t,{...r,get(){let o=s.call(this);return Zt(t==="contentWindow"?o:o?.defaultView),o}})}catch{}}var en="0.1.0";function on(){let n=globalThis;return n.onceworlds?.__onceworlds||(n.onceworlds=Rr()),n.onceworlds}function Rr(){let n=lt(document.currentScript);zt(),Xt(window,typeof HTMLIFrameElement>"u"?void 0:HTMLIFrameElement);let e=at(),t=Gt({stats:a=>x("stats",a)}),r=window.parent!==window,s=r&&gt(location.search)?wt(console,location.origin):null,o="connecting",i=!r&&bt(location.search),l=null,c=null,d=1,m=new Map,h=new Map,f=null,w=[],y,k=null,E=0,_=new Set,T=new me,M=new Set,P=new Set,L=r?mt(a=>x("clip",a),void 0,()=>f?{phase:f.match.phase,paused:!!f.match.paused,flow:ut(f.state)}:null):null,U=s?Ht(a=>x("snapshot",a)):null,N=new le(a=>{o!=="standalone"&&R("ui.controls",a).catch(()=>{})},a=>x("input",{touch:a})),j,A=new Promise(a=>j=a),je=xt(),He=Mt(()=>f,je),sn={read:a=>R("data.game.get",{key:a}),op:a=>R("data.game.op",a)},an=Et(()=>G().then(a=>a.player),B),ln=Rt(async()=>(await A,o==="platform"?sn:an),je),be=new Set,we=[],qe=a=>{let u=`${a.message}|${a.source}|${a.line}`;be.has(u)||be.size>=S.errorReportsPerPage||(be.add(u),o==="platform"?x("error",a):o==="connecting"&&we.push(a))};if(window.addEventListener("error",a=>{if(!(a instanceof ErrorEvent))return;let u=String(a.message||"Error");if(qe({message:u,source:tn(a.filename),line:a.lineno||0,column:a.colno||0,stack:a.error instanceof Error?String(a.error.stack??""):""}),s){let g=a.error instanceof Error?`Uncaught ${ae(a.error)}`:/^Uncaught\b/.test(u)?u:`Uncaught ${u}`;s.error(g,{source:tn(a.filename),line:a.lineno||0,column:a.colno||0})}}),window.addEventListener("unhandledrejection",a=>{let u=a.reason;s?.error(`Uncaught (in promise) ${u instanceof Error?ae(u):V(u)}`),qe({message:`Unhandled promise rejection: ${u instanceof Error?u.message:String(u)}`,source:"",line:0,column:0,stack:u instanceof Error?String(u.stack??""):""})}),r){window.addEventListener("message",u=>{if(!(u.source!==window.parent||u.data?.type!==nt||!u.ports[0])&&o!=="standalone"){if(c?.close(),c=u.ports[0],c.onmessage=g=>cn(g.data),o=ht(u.data),i=o==="platform"&&yt(u.data),j(),o==="platform")for(let g of we.splice(0))x("error",g);else we.length=0;s?.connect(g=>x("console",g)),y||(x("alive",{}),y=setInterval(()=>x("alive",{}),2e3)),o==="platform"&&G().then(g=>{e.apply(g.audio),g.settings&&t.apply(g.settings)}).catch(()=>{})}});let a={type:tt,version:en,...n?{build:n}:{}};window.parent.postMessage(a,"*"),setTimeout(()=>{o==="connecting"&&(o="standalone",j())},5e3)}else o="standalone",j();if(window.addEventListener("keydown",a=>{a.key!=="/"||o!=="platform"||!f||Ar(a.target)||(a.preventDefault(),a.stopImmediatePropagation(),x("hotkey",{key:"/"}))},!0),r){try{document.documentElement.style.touchAction="pan-x pan-y"}catch{}for(let a of["gesturestart","gesturechange","gestureend"])document.addEventListener(a,u=>u.preventDefault(),{passive:!1})}if(r){let a=u=>{u.pointerType==="mouse"||o!=="platform"||(window.removeEventListener("pointerup",a,!0),R("ui.tapped",void 0).catch(()=>{}))};window.addEventListener("pointerup",a,!0)}if(r&&It(()=>o==="platform",()=>x("input.first",{})),r&&Qt(navigator,()=>o==="platform",a=>x("vibrate",{pattern:a})),r){let a=Element.prototype.requestFullscreen;Element.prototype.requestFullscreen=function(u){return o!=="platform"?a.call(this,u):(R("ui.fullscreen",void 0).catch(()=>{}),Promise.resolve())}}function cn(a){if(a.kind==="res"){let g=m.get(a.id);if(!g)return;m.delete(a.id),a.ok?g.resolve(a.result):g.reject(new Error(a.error));return}if(a.kind!=="event")return;let u=a.name;if(u==="room")f?._receive(a.data);else if(u==="room.connection")a.data?.connected===!1&&f?._disconnected();else if(u==="room.closed"){let g=f;f=null,g?._closed(a.data.reason)}else if(u==="room.moved"){let g=f;f=ze(a.data),g?._closed("moved");for(let v of _)try{v(f)}catch(D){console.error('[onceworlds] error in rooms "moved" listener',D)}}else if(u==="audio")e.apply(a.data),re("audio",a.data);else if(u==="settings")t.apply(a.data);else if(u==="pause"||u==="resume")re(u);else if(u==="controls")N.receive(a.data);else if(u==="input")N.touch=a.data?.touch===!0;else if(u==="reserved")T.receive(a.data)&&re("reserved",T.areas);else if(u==="clip")L?.receive(a.data);else if(u==="snapshot")U?.receive(a.data);else if(u==="debug")for(let g of P)try{g(a.data)}catch(v){console.error("[onceworlds] error in the debugger link",v)}else if(u==="player"){let g=a.data;G().then(v=>{g?.id!==v.player.id||typeof g.name!="string"||(v.player.name=g.name,re("player",v.player))}).catch(()=>{})}}async function R(a,u){await A;let g=c;if(!g)throw new Error("Not connected to Onceworlds");return new Promise((v,D)=>{let b=d++;m.set(b,{resolve:v,reject:D}),g.postMessage({kind:"req",id:b,method:a,params:u})})}function x(a,u){c?.postMessage({kind:"event",name:a,data:u})}function re(a,...u){for(let g of h.get(a)??[])try{g(...u)}catch(v){console.error(`[onceworlds] error in "${a}" listener`,v)}}function ze(a,u=w){let g={send:(b,$)=>x("room.send",{d:b,to:$}),presence:b=>x("room.presence",{d:b}),state:(b,$,C)=>x("room.state",{k:b,v:$,w:C}),hideLobby:b=>x("room.hideLobby",{hidden:b}),team:(b,$)=>x("room.team",{id:b,team:$}),open:b=>x("room.open",{open:b}),result:b=>x("room.result",{result:b}),kick:b=>x("room.kick",{id:b}),voteKick:b=>x("room.votekick",{id:b}),ready:b=>x("room.ready",{ready:b}),unready:()=>x("room.unready",{}),transfer:b=>x("room.transfer",{id:b}),start:b=>x("room.start",b),end:()=>x("room.end",{}),pause:b=>x("room.pause",{paused:b}),admit:b=>x("room.admit",{ids:b}),private:(b,$,C)=>x("room.private",{k:b,v:$,...C?{id:C}:{}}),dataReset:()=>x("room.datareset",{}),leave:()=>{f===v&&(f=null),R("room.leave",void 0).catch(()=>{})}};w=u;let v=new Z(a,g,()=>Date.now()+E,u);Ue(v);let D=Ot(b=>x("room.idle",{idle:b}));return v.on("reconnect",()=>D.idle&&x("room.idle",{idle:!0})),v.on("close",()=>D.stop()),v}function Ue(a){a.on("state",(u,g,v)=>{f===a&&ke(u)&&He._changed(u.slice(H.length),g,v)})}function un(a,u){let g={};for(let[C,W]of Object.entries(ge.all()))g[H+C]=W;let v={room:"solo",you:a.id,host:a.id,players:[{...a,presence:null,team:u.teams?1:0}],state:g,chat:[],teams:u.teams??0,open:!0,now:Date.now(),ranked:!1,kept:!0,owner:a.id},b={..._t(()=>$),state(C,W){ke(C)&&ge.set(C.slice(H.length),W)},dataReset(){for(let C of Object.keys(ge.all()))ge.set(C,null),$._receive({t:"state",k:H+C,v:null,from:""})}},$=new Z(v,b,()=>Date.now()+E,Re(u.settings));return Ue($),$}function G(){return k??(k=A.then(()=>o==="platform"?R("session.get",void 0):$r()).then(a=>(E=Number(a.timeOffset)||0,a))),k}G().catch(()=>{});let Fe={async get(a){return await A,o==="platform"?await R("save.get",{key:a}):pe.get(a)},async set(a,u){await A,o==="platform"?await R("save.set",{key:a,value:u}):pe.set(a,u)},async delete(a){await A,o==="platform"?await R("save.delete",{key:a}):pe.delete(a)},async list(){return await A,o==="platform"?R("save.list",void 0):pe.list()}},Ke={__onceworlds:!0,_debug:s?{send:a=>{c&&x("debug",a)},on:a=>(P.add(a),()=>P.delete(a))}:null,version:en,get mode(){return o},ready:()=>A,player:{get:()=>G().then(a=>a.player),async avatarUrl(a,u="full"){let g=await G().catch(()=>null);if(!g?.platformOrigin)return null;let v=typeof a=="string"&&a?a:g.player.id;return`${g.platformOrigin}/avatar/${encodeURIComponent(v)}${u==="head"?"/head":""}.svg`},async avatar(a){if(await A,o!=="platform")return null;let u=typeof a=="string"&&a?a:(await G()).player.id;return it.test(u)?We(await R("player.avatar",{id:u}).catch(()=>null)):null},async rename(){return await A,o!=="platform"?null:await R("player.rename",void 0).catch(()=>null)?(await G()).player:null}},game:{info:()=>G().then(a=>a.game)},save:Fe,data:{player:Fe,server:He,game:ln},rooms:{async join(a={}){await A;let u=a.party===!0&&f!==null&&o==="platform";if(u||(f?.leave(),f=null),o!=="platform"){let{player:D}=await G();return f=un(D,a),f}let g=await R("room.join",{name:a.name,maxPlayers:a.maxPlayers,mode:a.mode,teams:a.teams,private:a.private,ranked:a.ranked,party:a.party,minPlayers:a.minPlayers,minPlayersPrivate:a.minPlayersPrivate,settings:a.settings,countdown:a.countdown,lobby:a.lobby,...a.ownCountdown===!0?{ownCountdown:!0}:{}}),v=f;return f=ze(g,Re(a.settings)),u&&v?._closed("moved"),f},get current(){return f},on(a,u){return a!=="moved"?()=>{}:(_.add(u),()=>_.delete(u))}},ratings:{async get(a){return await A,o==="platform"?R("ratings.get",{mode:String(a)}):null},async top(a,u={}){return await A,o==="platform"?R("ratings.top",{mode:String(a),limit:u.limit}):[]}},ui:{setMenuPosition(a){R("ui.menuPosition",{position:a}).catch(()=>{})},get reserved(){return T.areas},setLook(a){let{look:u,notes:g}=Yt(a);for(let v of g)M.has(v)||(M.add(v),console.warn(`[onceworlds] ui.setLook: ${v}`));o!=="standalone"&&R("ui.look",u).catch(()=>{})},requestFullscreen(){o==="platform"?R("ui.fullscreen",void 0).catch(()=>{}):document.documentElement.requestFullscreen?.().catch(()=>{})},showInvite(){o==="platform"&&R("ui.invite",void 0).catch(()=>{})},setOrientation(a){a!=="any"&&a!=="landscape"&&a!=="portrait"||o!=="standalone"&&R("ui.orientation",{orientation:a}).catch(()=>{})}},controls:{set(a){N.set(a)},get stick(){return N.stick},pressed(a){return N.pressed(String(a))},presses(a){return N.presses(String(a))},get touch(){return N.touch}},now:()=>Date.now()+E,leaderboards:{async submit(a,u,g={}){if(await A,o!=="platform")return he.submit(String(a),Number(u),g.lowerIsBetter===!0);try{return await R("leaderboards.submit",{board:String(a),score:Number(u),lowerIsBetter:g.lowerIsBetter===!0})}catch(v){return console.warn(`[onceworlds] score for "${a}" was not saved: ${v instanceof Error?v.message:v}`),null}},async top(a,u={}){return await A,o!=="platform"?he.top(String(a)):R("leaderboards.top",{board:String(a),limit:u.limit,lowerIsBetter:u.lowerIsBetter===!0})}},settings:t.settings,audio:{get volume(){return e.volume},get muted(){return e.muted}},badges:{async award(a){if(await A,o!=="platform")return ye.add(String(a));try{return(await R("badges.award",{key:String(a)})).awarded}catch(u){return console.warn(`[onceworlds] badge "${a}" was not awarded: ${u instanceof Error?u.message:u}`),!1}},async list(){return await A,o==="platform"?R("badges.list",void 0):ye.list()},async has(a){return(await Ke.badges.list()).some(u=>u.key===a&&u.earned)}},demo:{get active(){return i},end(){return l??(l=(async()=>(await A,i?o!=="platform"?(console.info("[onceworlds] demo.end(): the end of the demo. On Onceworlds the platform shows its end-of-demo card here."),!0):R("demo.end",void 0).then(a=>a!==!1,()=>!0):!1))().finally(()=>l=null)),l}},env:Er(),async fetch(a,u={}){if(await A,o!=="platform")throw new Error("onceworlds.fetch only works on Onceworlds, where your secrets are stored. Run the game with `onceworlds dev`.");let g=a instanceof Request?a:null,v=new URL(g?g.url:String(a),location.href).href,D=(u.method??g?.method??"GET").toUpperCase(),b={};new Headers(u.headers??g?.headers).forEach((dn,mn)=>{b[mn]=dn});let $=u.body??null;$===null&&g&&D!=="GET"&&D!=="HEAD"&&($=await g.arrayBuffer()),$ instanceof URLSearchParams&&(b["content-type"]??(b["content-type"]="application/x-www-form-urlencoded;charset=UTF-8"),$=$.toString());let C=await R("net.fetch",{url:v,method:D,headers:b,body:await Pr($)}),W=[101,204,205,304].includes(C.status);return new Response(W?null:C.body,{status:C.status,statusText:C.statusText,headers:C.headers})},on(a,u){let g=h.get(a);return g||h.set(a,g=new Set),g.add(u),()=>g.delete(u)}};return Ke}function Er(){let n=globalThis.__ONCEWORLDS_ENV__,e={};if(n&&typeof n=="object")for(let[t,r]of Object.entries(n))typeof r=="string"&&(e[t]=r);return Object.freeze(e)}async function Pr(n){if(n==null)return null;if(typeof n=="string"||n instanceof ArrayBuffer)return n;if(ArrayBuffer.isView(n))return new Uint8Array(n.buffer,n.byteOffset,n.byteLength).slice().buffer;if(n instanceof Blob)return n.arrayBuffer();throw new TypeError("onceworlds.fetch bodies must be a string (e.g. JSON.stringify(...)), bytes or a Blob.")}function tn(n){if(!n)return"";try{let e=new URL(n);return e.origin===location.origin?e.pathname.slice(1)||"index.html":e.href}catch{return n}}function Ar(n){return n instanceof HTMLElement?n.isContentEditable||["INPUT","TEXTAREA","SELECT"].includes(n.tagName):!1}function $r(){let n=B.get("onceworlds:player-id");return n||(n=`local-${Math.random().toString(36).slice(2,10)}`,B.set("onceworlds:player-id",n)),{player:{id:n,name:"Player"},game:{slug:location.hostname.split(".")[0]||"local",name:document.title||"Game",owner:"local"},audio:{volume:1,muted:!1},timeOffset:0}}var nn="onceworlds:scores",he={all(){try{let n=JSON.parse(B.get(nn)??"{}");return n&&typeof n=="object"?n:{}}catch{return{}}},submit(n,e,t){let r=he.all(),s=r[n],o=s===void 0?e:t?Math.min(s,e):Math.max(s,e);return r[n]=o,B.set(nn,JSON.stringify(r)),{best:o,rank:1}},top(n){let e=he.all()[n];if(e===void 0)return{entries:[],me:null};let t={rank:1,player:{id:"local",name:"You"},score:e};return{entries:[t],me:t}}},ne="onceworlds:save:",rn="onceworlds:badges",ye={earned(){try{let n=JSON.parse(B.get(rn)??"{}");return n&&typeof n=="object"?n:{}}catch{return{}}},add(n){let e=ye.earned();return e[n]?!1:(e[n]=Date.now(),B.set(rn,JSON.stringify(e)),!0)},list(){return Object.entries(ye.earned()).map(([n,e])=>({key:n,name:n,description:"",icon:null,earned:!0,earnedAt:e}))}},pe={get(n){let e=B.get(ne+n);if(e===null)return null;try{return JSON.parse(e)}catch{return null}},set(n,e){B.set(ne+n,JSON.stringify(e??null))},delete(n){B.remove(ne+n)},list(){let n=[];try{for(let e=0;e<localStorage.length;e++){let t=localStorage.key(e);t?.startsWith(ne)&&n.push(t.slice(ne.length))}}catch{}return n.sort()}},fe="onceworlds:server:",ge={all(){let n={};try{for(let e=0;e<localStorage.length;e++){let t=localStorage.key(e);if(t?.startsWith(fe))try{n[t.slice(fe.length)]=JSON.parse(localStorage.getItem(t)??"null")}catch{}}}catch{}return n},set(n,e){e==null?B.remove(fe+n):B.set(fe+n,JSON.stringify(e))}},B={get(n){try{return localStorage.getItem(n)}catch{return null}},set(n,e){try{localStorage.setItem(n,e)}catch{}},remove(n){try{localStorage.removeItem(n)}catch{}}};on();})();
@@ -0,0 +1,193 @@
1
+ // ../sdk/src/helpers/random.ts
2
+ function hashString(text) {
3
+ let h1 = 3735928559;
4
+ let h2 = 1103547991;
5
+ for (let i = 0; i < text.length; i++) {
6
+ const c = text.charCodeAt(i);
7
+ h1 = Math.imul(h1 ^ c, 2654435761);
8
+ h2 = Math.imul(h2 ^ c, 1597334677);
9
+ }
10
+ h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
11
+ h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
12
+ return (h2 ^ h1) >>> 0;
13
+ }
14
+ function createRandom(seed) {
15
+ const s = typeof seed === "number" && Number.isFinite(seed) ? Math.floor(seed) >>> 0 : hashString(String(seed));
16
+ let a = 2654435769;
17
+ let b = 608135816;
18
+ let c = 3084996962;
19
+ let d = s;
20
+ const next = () => {
21
+ a >>>= 0;
22
+ b >>>= 0;
23
+ c >>>= 0;
24
+ d >>>= 0;
25
+ let t = a + b | 0;
26
+ a = b ^ b >>> 9;
27
+ b = c + (c << 3) | 0;
28
+ c = c << 21 | c >>> 11;
29
+ d = d + 1 | 0;
30
+ t = t + d | 0;
31
+ c = c + t | 0;
32
+ return (t >>> 0) / 4294967296;
33
+ };
34
+ for (let i = 0; i < 12; i++) next();
35
+ const int = (n) => Number.isFinite(n) && n > 0 ? Math.floor(next() * Math.floor(n)) : 0;
36
+ return {
37
+ next,
38
+ int,
39
+ range: (min, max) => min + next() * (max - min),
40
+ chance: (p) => next() < p,
41
+ pick: (items) => Array.isArray(items) && items.length > 0 ? items[int(items.length)] : void 0,
42
+ shuffle(items) {
43
+ const out = Array.isArray(items) ? [...items] : [];
44
+ for (let i = out.length - 1; i > 0; i--) {
45
+ const j = int(i + 1);
46
+ [out[i], out[j]] = [out[j], out[i]];
47
+ }
48
+ return out;
49
+ }
50
+ };
51
+ }
52
+
53
+ // ../sdk/src/helpers/util.ts
54
+ var isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
55
+ var said = /* @__PURE__ */ new Map();
56
+ function warn(key, message, level = "warn", error) {
57
+ const now = Date.now();
58
+ if (now - (said.get(key) ?? -Infinity) < 5e3) return;
59
+ said.set(key, now);
60
+ if (said.size > 500) said.delete(said.keys().next().value);
61
+ try {
62
+ const text = `[onceworlds] ${message}`;
63
+ if (level === "error") console.error(text, error);
64
+ else if (level === "debug") console.debug(text);
65
+ else console.warn(text);
66
+ } catch {
67
+ }
68
+ }
69
+ function guard(where, fn, fallback) {
70
+ try {
71
+ return fn();
72
+ } catch (error) {
73
+ warn(`threw:${where}`, `${where} threw (the helper carries on)`, "error", error);
74
+ return fallback;
75
+ }
76
+ }
77
+
78
+ // ../sdk/src/helpers/bots.ts
79
+ var BOTS_KEY = "host:ow.bots";
80
+ var NAMES = ["Mox", "Juno", "Pip", "Rook", "Vega", "Tilly", "Bram", "Nix", "Sable", "Otto", "Wren", "Kit", "Lumo", "Dash", "Fern", "Zed"];
81
+ var isMatch = (target) => typeof target._useBots === "function";
82
+ function actionsOf(result) {
83
+ const list = Array.isArray(result) ? result : result ? [result] : [];
84
+ const out = [];
85
+ for (const item of list.slice(0, 8)) {
86
+ if (!isObject(item)) continue;
87
+ const name = item.call ?? item.rpc ?? item.claim;
88
+ if (typeof name === "string") out.push({ name, args: item.args });
89
+ }
90
+ return out;
91
+ }
92
+ function createBots(target, options) {
93
+ const match = target && isMatch(target) ? target : null;
94
+ const room = match ? match.room : target;
95
+ let fill = Math.max(0, Math.min(30, Math.floor(options?.fill ?? 4)));
96
+ const every = Math.max(50, options?.every ?? 700);
97
+ const names = options?.names?.length ? options.names.map((n) => String(n).slice(0, 24)) : NAMES;
98
+ const skillRange = options?.skill ?? [0.3, 0.7];
99
+ if (!options || typeof options.think !== "function") warn("bots-think", "createBots(match, { think(view) {...} }) needs a think function", "error");
100
+ if (!options?.host) warn("bots-host", "createBots: without { host } a bot's actions ({ call: 'move' }) have nowhere to go: pass the game's createHost(room)");
101
+ if (match) match._useBots(fill, names, skillRange);
102
+ const nextAt = /* @__PURE__ */ new Map();
103
+ const streams = /* @__PURE__ */ new Map();
104
+ let lastTurn = "";
105
+ let disposed = false;
106
+ const roster = () => {
107
+ const raw = room.state[BOTS_KEY];
108
+ if (!Array.isArray(raw)) return [];
109
+ const humans = room.online.length;
110
+ return raw.filter((b) => isObject(b) && typeof b.id === "string" && b.id.startsWith("bot:") && b.id.length <= 32 && typeof b.name === "string" && b.name.length <= 32 && typeof b.skill === "number" && b.skill >= 0 && b.skill <= 1).slice(0, 30).map((b, i) => ({ id: b.id, name: b.name, bot: true, me: false, index: humans + i, team: 0, away: false, idle: false, left: false, skill: b.skill }));
111
+ };
112
+ function keepRoster() {
113
+ if (match || !room.isHost || disposed) return;
114
+ const want = Math.max(0, Math.min(30 - room.online.length, fill - room.online.length));
115
+ const now = roster();
116
+ if (now.length === want && Array.isArray(room.state[BOTS_KEY])) return;
117
+ const rng = createRandom(`${room.id}:ow.bots`);
118
+ const order = rng.shuffle(names);
119
+ const next = Array.from({ length: want }, (_, i) => {
120
+ const kept = now[i];
121
+ if (kept) return { id: kept.id, name: kept.name, skill: kept.skill };
122
+ const skill = typeof skillRange === "number" ? skillRange : skillRange[0] + rng.next() * (skillRange[1] - skillRange[0]);
123
+ return { id: `bot:${i + 1}`, name: String(order[i % order.length]), skill: Math.round(Math.min(1, Math.max(0, skill)) * 100) / 100 };
124
+ });
125
+ room.setState(BOTS_KEY, next);
126
+ }
127
+ const list = () => match ? match.seats.filter((s) => s.bot) : roster();
128
+ function think() {
129
+ if (disposed) return;
130
+ if (!match) keepRoster();
131
+ const acting = match ? match.isHost && match.phase === "round" && !match.paused : room.isHost;
132
+ if (!acting) {
133
+ nextAt.clear();
134
+ return;
135
+ }
136
+ const now = Date.now();
137
+ const turn = match?.turn ?? null;
138
+ const turnKey = turn ? `${match.roundId}.${turn.n}` : "";
139
+ if (turnKey !== lastTurn) {
140
+ lastTurn = turnKey;
141
+ if (turn?.seat?.bot) nextAt.set(turn.id, now + every * (0.8 + Math.random() * 0.6));
142
+ }
143
+ for (const bot of list()) {
144
+ const due = nextAt.get(bot.id);
145
+ if (due === void 0) {
146
+ nextAt.set(bot.id, now + every * Math.random());
147
+ continue;
148
+ }
149
+ if (now < due) continue;
150
+ nextAt.set(bot.id, now + every * (0.8 + Math.random() * 0.4) * (1.4 - 0.8 * bot.skill));
151
+ const key = match ? match.roundId : "";
152
+ let stream = streams.get(bot.id);
153
+ if (!stream || stream.key !== key) streams.set(bot.id, stream = { key, random: createRandom(`${room.match.seed ?? 0}:bot:${bot.id}:${key}`) });
154
+ const view = {
155
+ bot,
156
+ skill: bot.skill,
157
+ match,
158
+ get data() {
159
+ return match ? match.data : null;
160
+ },
161
+ state: room.state,
162
+ myTurn: !!turn && turn.id === bot.id,
163
+ random: stream.random
164
+ };
165
+ const result = guard(`bot think (${bot.id})`, () => options.think(view), void 0);
166
+ for (const action of actionsOf(result)) options.host?.callAs({ id: bot.id, name: bot.name }, action.name, action.args);
167
+ }
168
+ }
169
+ const timer = setInterval(think, Math.max(50, Math.min(250, Math.floor(every / 4))));
170
+ const offs = [room.on("close", () => api.dispose())];
171
+ if (!match) for (const event of ["join", "leave", "host", "reconnect"]) offs.push(room.on(event, () => keepRoster()));
172
+ const api = {
173
+ get list() {
174
+ return list();
175
+ },
176
+ setFill(n) {
177
+ fill = Math.max(0, Math.min(30, Math.floor(Number(n) || 0)));
178
+ if (match) match._useBots(fill, names, skillRange);
179
+ else keepRoster();
180
+ },
181
+ dispose() {
182
+ if (disposed) return;
183
+ disposed = true;
184
+ clearInterval(timer);
185
+ for (const off of offs) off();
186
+ }
187
+ };
188
+ return api;
189
+ }
190
+ export {
191
+ BOTS_KEY,
192
+ createBots
193
+ };