@onceworlds/cli 0.9.5 → 0.10.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 Vt=Object.defineProperty;var Ft=(n,e,t)=>e in n?Vt(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var u=(n,e,t)=>Ft(n,typeof e!="symbol"?e+"":e,t);var qt=["#ffe0c4","#f3c59c","#d9a174","#b57a4f","#8a5836","#5c3a24","#5fd4b9","#8bd46e","#5ec8f2","#a98bff","#ff8fc0","#b9c2cf"],Ne=["#e53935","#fb8c00","#fdd835","#7cb342","#2e7d32","#00897b","#00acc1","#1e88e5","#283593","#8e24aa","#ec407a","#f5f5f5","#9e9e9e","#424242","#1b1b1b","#6d4c41"],Wt=["Happy","Grin","Shades","Wink","Surprised","Determined","Joyful","Shy"],Jt=["None","Sprout","Cap","Beanie","Crown","Headphones","Horns","Antenna","Bow","Halo","Party hat","Cat ears","Short hair","Tuft","Bob","Spikes","Bun","Curls"];var Yt=["Plain","Band","Spots","Stripes","Star"];var Xt={skin:qt.length,shirt:Ne.length,pants:Ne.length,face:Wt.length,hat:Jt.length,top:Yt.length};function Be(n){if(!n||typeof n!="object")return null;let e=n,t={};for(let[r,o]of Object.entries(Xt)){let s=e[r],i=typeof s=="number"?s:typeof s=="string"&&/^[0-9]{1,3}$/.test(s)?Number(s):NaN;if(!Number.isInteger(i)||i<0||i>=o)return null;t[r]=i}return t}var b={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 Zt="host:",N="data:";function V(n){return n.startsWith(Zt)||n.startsWith(N)}var Ge=/^(?!__proto__$)[A-Za-z0-9_.:-]{1,59}$/;function fe(n){return n.startsWith(N)}function ge(n){return N+n}function je(n){return n.startsWith("private:")||n.startsWith("room:")}function he(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 ye=/^[A-Za-z][A-Za-z0-9_.-]{0,31}$/;var Qt={counter:["add"],list:["push"],record:["best"],map:["claim","release"],value:["set"]},en={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 tn(n){return Qt[n].map(e=>`ow.data.game.${en[e]}`).join(" or ")}function be(n,e){let r=Math.floor(e/864e5);if(n==="daily")return{start:r*864e5,next:(r+1)*864e5};let o=r-(r+3)%7;return{start:o*864e5,next:(o+7)*864e5}}function nn(n,e){switch(n.type){case"counter":return{type:"counter",value:n.min,...n.reset?{resetsAt:be(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 nn(n,t);if(e.type==="counter"&&n.type==="counter"){if(!n.reset)return{type:"counter",value:e.value};let s=be(n.reset,t);return{type:"counter",value:(e.period??0)>=s.start?e.value:n.min,resetsAt:s.next}}let{period:r,...o}=e;return o}function ze(n,e,t,r,o){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 s={id:r.id,name:r.name},i=rn(n,e,o);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)),d=n.reset?be(n.reset,o):null;return{next:{type:"counter",value:l,...d?{resetsAt:d.next,period:d.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:s,at:o},...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:s,at:o},result:{type:"record",value:t.n,by:s,at:o,record:!0}}}case"map":{if(t.op!=="claim"&&t.op!=="release"||n.type!=="map")break;let l={...i.fields},d=Object.hasOwn(l,t.field)?l[t.field]:void 0;return t.op==="release"?!d||d.by.id!==r.id?{next:i,result:{type:"map",ok:!1,...d?{holder:d.by}:{}}}:(delete l[t.field],{next:{type:"map",fields:l},result:{type:"map",ok:!0}}):d?{next:i,result:{type:"map",ok:d.by.id===r.id,holder:d.by}}:Object.values(l).filter(f=>f.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:s,at:o},{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:o},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 ${tn(n.type)}.`}}var Ie=n=>n.replace(/[\u0000-\u001f\u007f]/g," ").replace(/\s+/g," ").trim();var on=/^[a-z0-9][a-z0-9-]{0,19}$/;function He(n){if(!n||typeof n!="object")return null;let e=n,t=[];for(let o of Array.isArray(e.buttons)?e.buttons:[]){if(t.length>=b.controlButtons)break;let{id:s,label:i}=o??{};if(typeof s!="string"||!on.test(s)||t.some(d=>d.id===s))continue;let l=typeof i=="string"?i.replace(/[\u0000-\u001f\u007f]/g,"").replace(/\s+/g," ").trim().slice(0,b.controlLabelLength).trim():"";t.push({id:s,label:l||s})}let r=e.stick===!0;return r||t.length>0?{stick:r,zone:e.zone==="corner"?"corner":"wide",buttons:t}:null}var F="host:ow.settings",sn=/^[a-z][a-zA-Z0-9]{0,15}$/;function we(n){if(!Array.isArray(n))return[];let e=[];for(let t of n){if(e.length>=6)break;let{id:r,label:o,options:s,default:i}=t??{};if(typeof r!="string"||!sn.test(r)||e.some(f=>f.id===r)||!Array.isArray(s))continue;let l=[];for(let f of s){let p=typeof f=="object"&&f!==null?f.value:f;if(typeof p!="string"&&typeof p!="number"||typeof p=="number"&&!Number.isFinite(p)||l.length>=8||l.some(D=>D.value===p))continue;let S=typeof f=="object"&&f!==null&&typeof f.label=="string"?f.label:String(p);l.push({value:p,label:Ie(S).slice(0,20)||String(p)})}if(l.length<2)continue;let d=typeof o=="string"?Ie(o).slice(0,24):"";e.push({id:r,label:d||r,options:l,default:l.some(f=>f.value===i)?i:l[0].value})}return e}function Ue(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 Ke="onceworlds:hello",Ve="onceworlds:connect",Fe=/^[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 qe=["log","info","warn","error"],We="onceworlds-console";var Je=/^[A-Za-z0-9-]{1,64}$/;function Ye(){let n=1,e=!1,t=()=>e?0:n,r=new Map;if(typeof AudioNode<"u"&&typeof AudioDestinationNode<"u"){let f=AudioNode.prototype.connect,p=AudioNode.prototype.disconnect,S=v=>typeof OfflineAudioContext>"u"||!(v instanceof OfflineAudioContext),D=v=>{let h=r.get(v);return h||(h=v.createGain(),h.gain.value=t(),f.call(h,v.destination),r.set(v,h)),h};AudioNode.prototype.connect=function(v,...h){return v instanceof AudioDestinationNode&&S(v.context)&&r.get(v.context)!==this?(f.call(this,D(v.context),...h),v):f.call(this,v,...h)},AudioNode.prototype.disconnect=function(...v){let h=v[0];if(h instanceof AudioDestinationNode){let R=r.get(h.context);R&&R!==this&&(v[0]=R)}return p.apply(this,v)}}let o=new WeakMap,s=new Set,i=typeof HTMLMediaElement<"u"?Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype,"volume"):void 0,l=f=>i?.set?.call(f,ke((o.get(f)??1)*t())),d=f=>{o.has(f)||!i?.get||(o.set(f,i.get.call(f)),s.add(new WeakRef(f)))};if(i?.get&&i.set){Object.defineProperty(HTMLMediaElement.prototype,"volume",{configurable:!0,enumerable:i.enumerable,get(){return o.has(this)?o.get(this):i.get.call(this)},set(p){d(this),o.set(this,ke(Number(p))),l(this)}});let f=HTMLMediaElement.prototype.play;HTMLMediaElement.prototype.play=function(){return d(this),l(this),f.call(this)}}return{get volume(){return n},get muted(){return e},apply(f){n=ke(f.volume),e=f.muted;for(let[p,S]of r)S.gain.setTargetAtTime(t(),p.currentTime,.02);for(let p of s){let S=p.deref();S?l(S):s.delete(p)}}}}function ke(n){return Number.isFinite(n)?Math.min(1,Math.max(0,n)):1}function Xe(n){try{let e=n?.getAttribute("data-build");return e&&Fe.test(e)?e:null}catch{return null}}var an=200,Ze=2,j=20,Qe=200;function et(n){try{return new URLSearchParams(n).get(We)==="1"}catch{return!1}}function tt(n){return typeof n=="object"&&n!==null&&n.solo===!0?"standalone":"platform"}function nt(n,e,t=Date.now,r=setTimeout){let o=null,s=[],i=-1/0,l=0,d=0,f=!1,p=!1,S=h=>{o?o(h):s.length<an&&s.push(h)},D=()=>{let h=t();return h-i>=1e3&&(i=h,l=0),l<b.consoleLinesPerSecond?(l++,!0):(d++,f||(f=!0,r(()=>{f=!1;let R=d;d=0,R>0&&D()&&S({level:"warn",text:`${R} more ${R===1?"line":"lines"} left out`,at:t()})},Math.max(0,1e3-(h-i)))),!1)},v=(h,R,$)=>{if(!D())return;let G=rt(e?R.split(`${e}/`).join(""):R);S({level:h,text:G,at:t(),...$?{source:$.source.slice(0,300),line:$.line,column:$.column}:{}})};for(let h of qe){let R=n[h];typeof R=="function"&&(n[h]=function(...$){if(R.apply(n,$),!p){p=!0;try{v(h,ln($))}catch{}finally{p=!1}}})}return{error(h,R){if(!p){p=!0;try{v("error",h,R)}catch{}finally{p=!1}}},connect(h){o=h;for(let R of s.splice(0))h(R)}}}function ln(n){let e="",t=n;if(typeof n[0]=="string"){let r=1;e=n[0].replace(/%[sdifoOc%]/g,o=>{if(o==="%%")return"%";if(r>=n.length)return o;let s=n[r++];return o==="%c"?"":o==="%d"||o==="%i"?String(typeof s=="number"?Math.trunc(s):parseInt(q(s),10)):o==="%f"?String(typeof s=="number"?s:parseFloat(q(s))):o==="%s"?q(s):z(s)}),t=n.slice(r)}for(let r of t)e+=e?` ${q(r)}`:q(r);return rt(e)}function q(n){return typeof n=="string"?n:z(n)}function z(n,e=0){try{switch(typeof n){case"string":return JSON.stringify(n.length>Qe?`${n.slice(0,Qe)}\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 te(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>=Ze?`Array(${n.length})`:`[${n.slice(0,j).map(i=>z(i,e+1)).join(", ")}${n.length>j?`, \u2026${n.length-j} more`:""}]`;let t=typeof n.constructor=="function"&&n.constructor!==Object?`${n.constructor.name} `:"";if(e>=Ze)return`${t}{\u2026}`;let r=Object.keys(n),o=r.slice(0,j).map(s=>`${/^[A-Za-z_$][\w$]*$/.test(s)?s:JSON.stringify(s)}: ${z(n[s],e+1)}`);return`${t}{${o.join(", ")}${r.length>j?`, \u2026${r.length-j} more`:""}}`}catch{return Object.prototype.toString.call(n)}}function te(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 rt(n){return n.length>b.consoleLineLength?`${n.slice(0,b.consoleLineLength-1)}\u2026`:n}var cn={wasd:{up:"w",down:"s",left:"a",right:"d"},arrows:{up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight"}},un=.45,dn=.3,ve={" ":["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]},ne=class{constructor(e,t){u(this,"touch");u(this,"stick",{x:0,y:0});u(this,"held",new Set);u(this,"downs",new Map);u(this,"stickMode");u(this,"buttonKeys",new Map);u(this,"down",new Map);u(this,"show");u(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:[],o=e?He({stick:this.stickMode!==void 0,zone:t.zone,buttons:r}):null;this.buttonKeys=new Map;for(let s of o?.buttons??[]){let i=r.find(l=>l?.id===s.id)?.key;typeof i=="string"&&i&&this.buttonKeys.set(s.id,i)}this.show(o),o?this.update():this.release()}receive(e){let t=o=>typeof o=="number"&&Number.isFinite(o)?Math.max(-1,Math.min(1,o)):0;this.stick.x=t(e?.x),this.stick.y=t(e?.y);let r=new Set(Array.isArray(e?.buttons)?e.buttons.filter(o=>typeof o=="string"):[]);for(let o of r)this.held.has(o)||this.downs.set(o,(this.downs.get(o)??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=cn[this.stickMode],r=(o,s)=>{s>(this.down.has(o)?dn:un)&&e.set(o,ot(o))};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,ot(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 ot(n){let e=n==="Space"?" ":n;return Object.prototype.hasOwnProperty.call(ve,e)?{key:e,code:ve[e][0],keyCode:ve[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 pn(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 it(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 at(n,e){let t=new Set,r=async(o,s)=>{let i=`onceworlds.data.server.${s===null?"delete":"set"}('${String(o).slice(0,40)}')`,l=n();if(typeof o!="string"||!Ge.test(o))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 d;try{d=JSON.stringify(s??null)}catch{d=void 0}return d===void 0?(e(`${i} did nothing: the value must be plain JSON data (numbers, text, lists, objects).`),!1):he(d)>b.stateValueBytes-128?(e(`${i} did nothing: the value is ${Math.ceil(he(d)/1024)} KB, and a key holds 16 KB. Split it into keys by area or chunk (a server keeps ${b.serverDataKeys} keys, ${b.serverDataBytes/1024} KB), or let the engine's Persist() save the world for you.`),!1):await l._writeAcked(ge(o),s??null)};return{get(o){let s=n();if(!s||typeof o!="string")return null;let i=s.state[ge(o)];return i===void 0?null:i},all(){let o=n(),s={};if(!o)return s;for(let[i,l]of Object.entries(o.state))i.startsWith("data:")&&(s[i.slice(5)]=l);return s},set:(o,s)=>r(o,s??null),delete:o=>r(o,null),get kept(){return n()?.kept??!1},get canWrite(){let o=n();return!!(o&&!o.closed&&o.isHost)},async reset(){let o=n();return o?o.owner!==o.me.id&&o.kind!=="solo"?(e("onceworlds.data.server.reset() did nothing: only a private server's owner starts its world over (room.owner)."),!1):o._resetData():(e("onceworlds.data.server.reset() did nothing: you're not in a room."),!1)},on(o,s){return o!=="change"||typeof s!="function"?()=>{}:(t.add(s),()=>t.delete(s))},_changed(o,s,i){for(let l of t)try{l(o,s??null,i)}catch(d){console.error('[onceworlds] error in data.server "change" listener',d)}}}}function lt(n,e){let t=async(o,s,i,l)=>{if(typeof o.key!="string"||!ye.test(o.key))return e(`${s} did nothing: '${String(o.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(o))}catch(d){return e(`${s} did nothing: ${d instanceof Error?d.message:String(d)}`),l}},r=(o,s)=>`onceworlds.data.game.${o}('${String(s).slice(0,40)}')`;return{async get(o){if(typeof o!="string"||!ye.test(o))return e(`${r("get",o)}: '${String(o).slice(0,40)}' isn't a game data key (1-32 letters, digits, _ . or -).`),null;try{return pn(await(await n()).read(o))}catch(s){return e(`${r("get",o)} read nothing: ${s instanceof Error?s.message:String(s)}`),null}},add:(o,s)=>t({key:o,op:"add",n:Number(s)},r("add",o),i=>i.type==="counter"?i.value:null,null),push:(o,s)=>t({key:o,op:"push",item:s},r("push",o),i=>i.type==="list",!1),best:(o,s)=>t({key:o,op:"best",n:Number(s)},r("best",o),i=>i.type==="record"?{value:i.value,by:i.by,at:i.at,record:i.record}:null,null),claim:(o,s)=>t({key:o,op:"claim",field:String(s)},r("claim",o),i=>i.type==="map"&&i.ok,!1),release:(o,s)=>t({key:o,op:"release",field:String(s)},r("release",o),i=>i.type==="map"&&i.ok,!1),set:(o,s)=>t({key:o,op:"set",value:s},r("set",o),i=>i.type==="value",!1)}}function ct(n,e){let t=b.gameDataNumberMax,r=s=>{switch(s.op){case"add":return{type:"counter",min:0,max:t,add:[-t,t],guests:!0};case"push":return{type:"list",max:b.gameDataListMax,bytes:b.gameDataItemBytes,guests:!0};case"best":return{type:"record",order:"max",min:-t,max:t,guests:!0};case"claim":case"release":return{type:"map",fields:b.gameDataMapFields,perPlayer:b.gameDataMapPerPlayer,guests:!0};case"set":return{type:"value",bytes:b.gameDataValueBytes,guests:!0}}},o=s=>{try{let i=e.get(`onceworlds:game:${s}`);return i?JSON.parse(i):null}catch{return null}};return{async read(s){let i=o(s);if(!i)throw new Error(`nothing is stored under '${s}' on this page yet (on its own, game data lives in this browser).`);return i},async op(s){let i=await n(),l=o(s.key),d=r(s);if(l&&l.type!==d.type)throw new Error(`'${s.key}' holds a ${l.type} on this page: it was first used that way.`);let f=ze(d,l,JSON.parse(JSON.stringify(s??null)),{id:i.id,name:i.name,host:!0},Date.now());if("code"in f)throw new Error(f.message);return e.set(`onceworlds:game:${s.key}`,JSON.stringify(f.next)),f.result}}}function ut(n){return{messagesPerSecond:n.messagesPerSecond*.85,messageBurst:n.messagesPerSecond*2*.85,bytesPerSecond:n.bytesPerSecond*.85,byteBurst:n.bytesPerSecond*4*.85}}var mn=60,fn=100,gn=5e3,re=class{constructor(e={}){u(this,"queue",[]);u(this,"rates",ut({messagesPerSecond:b.messagesPerSecond,bytesPerSecond:b.roomBytesPerSecond}));u(this,"messages",this.rates.messageBurst);u(this,"bytes",this.rates.byteBurst);u(this,"budget",{messagesPerSecond:b.messagesPerSecond,bytesPerSecond:b.roomBytesPerSecond});u(this,"refilledAt");u(this,"timer",null);u(this,"warnedAt",-1/0);u(this,"dropped",0);u(this,"now");u(this,"setTimer");u(this,"clearTimer");u(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=ut(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 o=this.queue.length-1;o>=0;o--){let s=this.queue[o];if(s.kind!=="state")break;if(s.key===e)return s.size=t,s.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(mn,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/(b.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(d){console.error("[onceworlds] a message could not be sent",d)}}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,o=Math.max(0,t-this.bytes)/this.rates.bytesPerSecond,s=Math.min(250,Math.max(8,Math.ceil(Math.max(r,o)*1e3)));this.timer=this.setTimer(()=>{this.timer=null,this.drain(!1)},s)}squeeze(){let e=new Set;for(let o=this.queue.length-1;o>=0;o--){let s=this.queue[o];s.kind==="state"&&(e.has(s.key)?this.queue.splice(o,1):e.add(s.key))}let t=this.queue.filter(o=>o.kind==="event").length,r=this.waitingLimit(fn,20);for(let o=0;t>r&&o<this.queue.length;)this.queue[o].kind==="event"?(this.queue.splice(o,1),t--,this.dropped++):o++;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<gn||(this.warnedAt=t,this.warn(e))}};function B(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 xe=Math.PI*2;function Se(n,e,t,r={},o=""){if(typeof n=="number"&&typeof e=="number"){if(r.angles?.includes(o)){let s=((e-n)%xe+xe+Math.PI)%xe-Math.PI;return n+s*t}return n+(e-n)*t}if(Array.isArray(n)&&Array.isArray(e)&&n.length===e.length)return e.map((s,i)=>Se(n[i],s,t,r,o));if(n&&e&&typeof n=="object"&&typeof e=="object"&&!Array.isArray(n)&&!Array.isArray(e)){let s={};for(let i of Object.keys(e))s[i]=i in n?Se(n[i],e[i],t,r,i):e[i];return s}return t<.5?n:e}function hn(n,e,t){if(t===void 0||!n||!e||typeof n!="object"||typeof e!="object")return!1;for(let[r,o]of Object.entries(e)){let s=n[r];if(typeof o=="number"&&typeof s=="number"&&Math.abs(o-s)>t)return!0}return!1}function dt(n,e,t={}){if(n.length===0)return;let r=n[0],o=n[n.length-1];if(e<=r.at)return r.d;if(e>=o.at)return o.d;let s=n.length-2;for(;s>0&&n[s].at>e;)s--;let i=n[s],l=n[s+1];return hn(i.d,l.d,t.snap)?l.d:Se(i.d,l.d,(e-i.at)/Math.max(1,l.at-i.at),t)}var pt=8,mt=2e3;var yn=3e3,bn=15e3,wn=5e3;function ft(n){let e={};for(let t of Object.keys(n))V(t)&&(e[t]=n[t]);return e}var O=()=>48,W=class{constructor(e,t,r=Date.now,o=[]){u(this,"id");u(this,"kind");u(this,"invite");u(this,"teams");u(this,"open");u(this,"ranked");u(this,"kept");u(this,"me");u(this,"owner");u(this,"players",new Map);u(this,"state",{});u(this,"host");u(this,"closed",!1);u(this,"connected",!0);u(this,"match");u(this,"listeners",new Map);u(this,"transport");u(this,"outbox",new re);u(this,"samples",new Map);u(this,"presenceTimer",null);u(this,"pendingPresence",null);u(this,"writes",0);u(this,"written",new Map);u(this,"confirmed",{});u(this,"shares",{messagesPerSecond:b.messagesPerSecond,presenceHz:b.presenceHz,bytesPerSecond:b.roomBytesPerSecond});u(this,"clock");u(this,"schema");u(this,"frozenSettings",null);u(this,"secrets",new Map);u(this,"offlineReady");u(this,"complained",new Map);u(this,"acks",new Map);this.transport=t,this.clock=r,this.schema=o,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??je(e.room),this.owner=e.owner??null,this.host=e.host;for(let s of e.players)this.players.set(s.id,{...s}),s.presence!==null&&s.presence!==void 0&&this.samples.set(s.id,[{at:e.now??this.clock(),d:s.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=ft(e.state);for(let[s,i]of Object.entries(e.private??{}))this.secrets.set(s,{...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(s=>s.id===e);if(!r||!r.options.some(s=>s.value===t)||this.chosenSettings()[e]===t)return;let o=this.state[F];this.setState(F,{...o!==null&&typeof o=="object"?o:{},[e]:t}),this.clearReady(),this.emit("settings",this.settings)}chosenSettings(){let e=this.state[F];return Object.fromEntries(this.schema.map(t=>[t.id,Ue(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(()=>B(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(()=>B(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:dt(r,this.clock()-(t.delay??100),t)}keep(e,t,r){let o=this.samples.get(e)??[],s=o.length;for(;s>0&&o[s-1].at>t;)s--;for(o.splice(s,0,{at:t,d:r});o.length>pt||o.length>2&&o[0].at<t-mt;)o.shift();this.samples.set(e,o)}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(O,()=>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(O,()=>this.transport.start(r))}endMatch(){this.reachable("endMatch")&&this.outbox.urgent(O,()=>this.transport.end())}pauseMatch(e=!0){this.reachable("pauseMatch")&&this.outbox.urgent(O,()=>this.transport.pause(e))}admit(e){let t=(Array.isArray(e)?e:[e]).map(String);t.length&&this.reachable("admit")&&this.outbox.urgent(O,()=>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(!V(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 o=this.clock(),s=`${e}:${t}`;if(o-(this.complained.get(s)??-1/0)<wn)return;this.complained.set(s,o);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(O,()=>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(O,()=>this.transport.unready())}}send(e,t={}){this.closed||this.outbox.event(()=>B(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(B(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(V(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,()=>B(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(o=>{let s={w:r,done:l=>{clearTimeout(i),o(l)}},i=setTimeout(()=>this.settleAcks(e,l=>l===s,!1),bn);this.acks.set(e,[...this.acks.get(e)??[],s])}):Promise.resolve(!1)}_resetData(){return this.closed||!this.connected||!this.transport.dataReset?!1:(this.outbox.urgent(O,()=>this.transport.dataReset()),!0)}settleAcks(e,t,r){let o=this.acks.get(e);if(!o)return;let s=o.filter(i=>!t(i));s.length>0?this.acks.set(e,s):this.acks.delete(e);for(let i of o)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(O,()=>this.transport.team(e,t))}setOpen(e){this.closed||this.outbox.urgent(O,()=>this.transport.open(e))}reportResult(e){this.closed||this.outbox.urgent(()=>B(e),()=>this.transport.result(e))}kick(e){this.closed||this.outbox.urgent(O,()=>this.transport.kick(String(e)))}voteKick(e){this.closed||this.outbox.urgent(O,()=>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,o=>o.w<=e.w,!0),V(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===F&&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(B(e)),this.presenceTimer=setTimeout(()=>this.flushPresence(),1e3/this.shares.presenceHz)}applyBudget(e){if(!e)return;let t=(r,o)=>typeof r=="number"&&Number.isFinite(r)&&r>0&&r<=o;t(e.presenceHz,b.presenceHz)&&(this.shares={...this.shares,presenceHz:e.presenceHz}),t(e.messagesPerSecond,b.messagesPerSecond)&&t(e.bytesPerSecond,b.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 o={...this.secrets.get(e)??{}};r===null?delete o[t]:o[t]=r,Object.keys(o).length>0?this.secrets.set(e,o):this.secrets.delete(e)}applySecrets(e){let t=[];for(let[r,o]of Object.entries(e))for(let[s,i]of Object.entries(o))JSON.stringify(this.secrets.get(r)?.[s]??null)!==JSON.stringify(i)&&t.push([r,s,i]);for(let[r,o]of this.secrets)for(let s of Object.keys(o))s in(e[r]??{})||t.push([r,s,null]);this.secrets=new Map(Object.entries(e).map(([r,o])=>[r,{...o}]));for(let[r,o,s]of t)this.emit("private",o,s,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=ft(e.state),this.applyBudget(e.budget);let o=new Set;for(let i of e.players){if(o.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 d={...i};this.players.set(i.id,d),this.emit("join",d)}}for(let[i,l]of this.players)o.has(i)||l===this.me||(this.players.delete(i),this.emit("leave",l));let s=new Set([...Object.keys(this.state),...Object.keys(e.state)]);for(let i of s){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(o){console.error(`[onceworlds] error in room "${e}" listener`,o)}}};function gt(n){let e=null,t=o=>n()._receive({t:"match",match:o}),r=()=>{let s=n().match;if(s.phase!=="starting")return;let{startsAt:i,...l}=s;t({...l,phase:"playing",startedAt:Date.now(),pausedMs:0})};return{send(){},presence(){},state(){},team(){},open(){},result(){},kick(){},voteKick(){},ready(){},unready(){},transfer(){},start(o){let s=n();if(s.match.phase!=="lobby")return;let i=Math.min(b.matchCountdownMaxMs,Math.max(0,o.countdown??b.matchCountdownMs));t({phase:"starting",n:s.match.n+1,min:s.match.min,id:`solo${s.match.n+1}`,seed:Math.floor(Math.random()*2**32),participants:[s.me.id],startsAt:Date.now()+i}),i===0?r():e=setTimeout(r,i)},end(){let o=n();e&&clearTimeout(e),e=null,o.match.phase!=="lobby"&&t({phase:"lobby",n:o.match.n,min:o.match.min})},pause(o){let s=n().match;if(s.phase!=="playing")return;let i=Date.now();if(o&&!s.paused)t({...s,paused:{since:i,reason:"host"}});else if(!o&&s.paused){let{paused:l,...d}=s;t({...d,pausedMs:(s.pausedMs??0)+Math.max(0,i-l.since)})}},admit(){},private(){},leave(){e&&clearTimeout(e),e=null}}}var ht=["pointerdown","pointermove","keydown","wheel","touchstart","touchmove","devicemotion","visibilitychange"],kn=5e3;function yt(n,e=b.idleAfterMs){let t=Date.now(),r=!1,o=()=>{t=Date.now(),r&&(r=!1,n(!1))},s=()=>{try{for(let l of navigator.getGamepads?.()??[])if(l&&(l.buttons.some(d=>d.pressed)||l.axes.some(d=>Math.abs(d)>.25)))return!0}catch{}return!1};for(let l of ht)window.addEventListener(l,o,{capture:!0,passive:!0});let i=setInterval(()=>{if(s())return o();!r&&Date.now()-t>e&&(r=!0,n(!0))},kn);return{get idle(){return r},stop(){clearInterval(i);for(let l of ht)window.removeEventListener(l,o,{capture:!0})}}}var bt=["pointerdown","keydown","touchstart","gamepadconnected"];function wt(n,e){let t=r=>{if(!(!r.isTrusted||!n())){for(let o of bt)window.removeEventListener(o,t,{capture:!0});e()}};for(let r of bt)window.addEventListener(r,t,{capture:!0,passive:!0})}var vt=["low","medium","high"],vn={low:.6,medium:.8,high:1},xn=24,Sn=18.5,Rn=26,Re=6e3,kt=2e4,En=5*6e4,Ee=class{constructor(e=2){u(this,"level",2);u(this,"slow",0);u(this,"smoothSince",0);u(this,"holdUntil",0);u(this,"probeAfter",kt);u(this,"steppedUpAt",-1/0);this.level=e}window(e,t,r){return t>xn?(this.smoothSince=0,++this.slow>=2&&e>=this.holdUntil&&this.level>0&&(e-this.steppedUpAt<Re+kt/2&&(this.probeAfter=Math.min(En,this.probeAfter*2)),this.level--,this.slow=0,this.holdUntil=e+Re)):t<=Sn&&r<=Rn?(this.slow=0,this.smoothSince||(this.smoothSince=e),this.level<vt.length-1&&e>=this.holdUntil&&e-this.smoothSince>=this.probeAfter&&(this.level++,this.steppedUpAt=e,this.smoothSince=0,this.holdUntil=e+Re)):(this.slow=0,this.smoothSince=0),this.level}};function xt(n){let e="auto",t=typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches,r=!1,o=new Ee(Mn()?1:2),s=new Set,i=!1,l=!1,d=0,f=[],p=0,S=0,D=k=>{if(i){if(d&&!document.hidden){let E=k-d;E<250&&f.push(E)}if(d=document.hidden?0:k,p||(p=k),k-p>=1e3){if(f.length>=10){let E=[...f].sort((H,U)=>H-U),M=f.reduce((H,U)=>H+U,0)/f.length,Z=E[Math.min(E.length-1,Math.floor(E.length*.95))],Q=$();e==="auto"&&o.window(k,M,Z),r&&k-S>=500&&(S=k,n.stats({fps:Math.round(1e3/M),frameMs:Math.round(M*10)/10,worstMs:Math.round(E[E.length-1]*10)/10})),$()!==Q&&G()}f=[],p=k}v()}},v=()=>{l||!i||(l=!0,requestAnimationFrame(k=>{l=!1,D(k)}))},h=()=>{i||typeof requestAnimationFrame!="function"||(i=!0,d=0,p=0,v())},R=()=>{!r&&e!=="auto"&&i&&(i=!1)},$=()=>e==="auto"?vt[o.level]:e,G=()=>{for(let k of s)try{k(T)}catch(E){console.error('[onceworlds] error in settings "change" listener',E)}},T={get choice(){return e},get quality(){return e==="auto"&&h(),$()},get scale(){return vn[T.quality]},get reducedMotion(){return t},pixelRatio(k=2){let E=typeof devicePixelRatio=="number"&&devicePixelRatio>0?devicePixelRatio:1;return Math.max(.5,Math.min(E,k)*T.scale)},on(k,E){return k!=="change"?()=>{}:(s.add(E),e==="auto"&&h(),()=>s.delete(E))}};return{settings:T,apply(k){let E=`${$()}|${t}`;e=k.quality,t=k.reducedMotion,r=k.showStats,r||e==="auto"&&s.size>0?h():R(),`${$()}|${t}`!==E&&G()}}}function Mn(){return typeof matchMedia=="function"&&matchMedia("(pointer: coarse)").matches}var St=(n,e)=>Object.prototype.hasOwnProperty.call(n,e);function Me(n){try{return n(),!0}catch{return!1}}function Pn(){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 St(e,r)?t[r]:n.get(r)},set(t,r,o){return typeof r=="string"&&n.set(r,String(o)),!0},has:(t,r)=>typeof r=="string"&&(St(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 An(n=Date.now){let e=new Map;return{read:()=>[...e].map(([t,r])=>`${t}=${r}`).join("; "),write(t){let[r,...o]=String(t).split(";"),s=r.indexOf("="),i=(s<0?"":r.slice(0,s)).trim(),l=(s<0?r:r.slice(s+1)).trim();if(!i&&!l)return;let d=!1;for(let f of o){let[p,...S]=f.split("="),D=S.join("=").trim();p.trim().toLowerCase()==="max-age"&&Number(D)<=0&&(d=!0),p.trim().toLowerCase()==="expires"&&Date.parse(D)<=n()&&(d=!0)}d?e.delete(i):e.set(i,l)}}}function J(n,e,t){try{Object.defineProperty(n,e,{configurable:!0,...t})}catch{}}function $n(){if(typeof HTMLImageElement!="function")return;let n=Object.getOwnPropertyDescriptor(HTMLImageElement.prototype,"src");if(!n?.get||!n.set)return;let{get:e,set:t}=n;J(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 Dn(){let n=window.Worker;if(typeof n!="function")return;let e=function(t,r){try{return new n(t,r)}catch(o){if(!(o instanceof DOMException&&o.name==="SecurityError")||r?.type==="module")throw o;let s;try{s=new URL(String(t),document.baseURI)}catch{throw o}if(s.origin!==location.origin)throw o;let l=`const base = ${JSON.stringify(s.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,J(window,"Worker",{value:e,writable:!0})}function Rt(){try{for(let n of["localStorage","sessionStorage"])Me(()=>window[n].length)||J(window,n,{value:Pn()});if(!Me(()=>document.cookie)){let n=An();J(document,"cookie",{get:()=>n.read(),set:e=>n.write(e)})}if(window.origin==="null"&&(Dn(),$n()),window.origin==="null"||!Me(()=>history.replaceState(history.state,"",location.href)))for(let n of["pushState","replaceState"]){let e=history[n];J(history,n,{value:function(...t){try{return e.apply(this,t)}catch(r){if(!(r instanceof DOMException&&r.name==="SecurityError"))throw r}}})}}catch{}}var _n=["menu","lobby","stick","buttons"];function Mt(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:o,y:s,w:i,h:l}=t;_n.includes(r)&&(!oe(o)||!oe(s)||!oe(i)||!oe(l)||i<0||l<0||e.push({kind:r,x:o,y:s,w:i,h:l}))}return e}var oe=n=>typeof n=="number"&&Number.isFinite(n),Pe={entries:10,entryMs:1e3,totalMs:2e3};function Pt(n){let e=typeof n=="number"?[n]:Array.isArray(n)?n.slice(0,Pe.entries):null;if(!e||!e.every(o=>typeof o=="number"&&Number.isFinite(o)&&o>=0))return null;let t=[],r=Pe.totalMs;for(let o of e){let s=Math.min(Math.round(o),Pe.entryMs,r);if(t.push(s),r-=s,r<=0)break}return t.some((o,s)=>s%2===0&&o>0)?t:[]}var On=/^#(?:[0-9a-f]{3}){1,2}$/i,Y={panel:"#111216",text:"#f7f7f8",accent:"#d33e00"},$e=4.5,Ae=3,se=["#4ade80","#15803d"];function At(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=p=>{let S=t[p];return S==null?null:typeof S=="string"&&On.test(S)?$t(S):(e.push(`${p} is not #rgb or #rrggbb`),null)},o=r("panel"),s=r("text"),i=r("accent");if(o||s){let p=I(s??Y.text,o??Y.panel);p<$e&&(e.push(`text on panel is ${p.toFixed(1)}:1, under ${$e}:1: the platform's are used`),o=s=null)}let l=o??Y.panel,d=s??Y.text;if(i){let p=I(i,l);p<Ae&&(e.push(`accent on panel is ${p.toFixed(1)}:1, under ${Ae}:1: the platform's is used`),i=null)}if(!i&&o&&I(Y.accent,o)<Ae&&(i=d),!o&&!s&&!i)return{look:null,notes:e};let f=i?Ln(i):null;return{look:{panel:o,text:s,muted:o||s?Cn(d,l):null,accent:i,accentHover:i?Dt(i,f==="#ffffff"?"#000000":"#ffffff",.14):null,onAccent:f,ok:o?I(se[0],o)>=I(se[1],o)?se[0]:se[1]:null},notes:e}}function $t(n){let e=n.slice(1).toLowerCase();return`#${e.length===3?[...e].map(t=>t+t).join(""):e}`}function De(n){let e=$t(n);return[parseInt(e.slice(1,3),16),parseInt(e.slice(3,5),16),parseInt(e.slice(5,7),16)]}function Et(n){let[e,t,r]=De(n).map(o=>{let s=o/255;return s<=.04045?s/12.92:((s+.055)/1.055)**2.4});return .2126*e+.7152*t+.0722*r}function I(n,e){let[t,r]=[Et(n),Et(e)].sort((o,s)=>s-o);return(t+.05)/(r+.05)}function Ln(n){return I(n,"#000000")>I(n,"#ffffff")?"#000000":"#ffffff"}function Dt(n,e,t){let[r,o]=[De(n),De(e)];return`#${r.map((s,i)=>Math.round(s+(o[i]-s)*t).toString(16).padStart(2,"0")).join("")}`}function Cn(n,e){for(let t=.3;t>.001;t-=.05){let r=Dt(n,e,t);if(I(r,e)>=$e)return r}return n}var ie=class{constructor(){u(this,"areas",null);u(this,"key","")}receive(e){let t=Mt(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(o=>Object.freeze(o))),!0)}};function _t(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 o=n[r];o!=null&&(t[r]=typeof o=="string"?o.slice(0,16):"")}}catch{return e}return{look:t,notes:At(t).notes}}function Ot(n,e,t){let r=typeof n.vibrate=="function"?n.vibrate.bind(n):null,o=s=>{try{if(!e())return r?r(s):!1;if(!r)return!1;let i=Pt(Array.isArray(s)?Array.from(s):s);return i?(t(i),!0):!1}catch{return!1}};try{Object.defineProperty(n,"vibrate",{value:o,configurable:!0,writable:!0})}catch{}}var Tn=["RTCPeerConnection","webkitRTCPeerConnection","mozRTCPeerConnection"];function Lt(n){if(n)for(let e of Tn)try{Object.defineProperty(n,e,{value:void 0,writable:!1,enumerable:!1,configurable:!1})}catch{}}function Ct(n,e){if(Lt(n),!!e)for(let t of["contentWindow","contentDocument"])try{let r=Object.getOwnPropertyDescriptor(e.prototype,t),o=r?.get;if(!r||!o)continue;Object.defineProperty(e.prototype,t,{...r,get(){let s=o.call(this);return Lt(t==="contentWindow"?s:s?.defaultView),s}})}catch{}}var Tt="0.1.0";function Gt(){let n=globalThis;return n.onceworlds?.__onceworlds||(n.onceworlds=Nn()),n.onceworlds}function Nn(){let n=Xe(document.currentScript);Rt(),Ct(window,typeof HTMLIFrameElement>"u"?void 0:HTMLIFrameElement);let e=Ye(),t=xt({stats:a=>w("stats",a)}),r=window.parent!==window,o=r&&et(location.search)?nt(console,location.origin):null,s="connecting",i=null,l=1,d=new Map,f=new Map,p=null,S=[],D,v=null,h=0,R=new Set,$=new ie,G=new Set,T=new Set,k=new ne(a=>{s!=="standalone"&&x("ui.controls",a).catch(()=>{})},a=>w("input",{touch:a})),E,M=new Promise(a=>E=a),Z=it(),Q=at(()=>p,Z),H={read:a=>x("data.game.get",{key:a}),op:a=>x("data.game.op",a)},U=ct(()=>C().then(a=>a.player),L),jt=lt(async()=>(await M,s==="platform"?H:U),Z),pe=new Set,me=[],_e=a=>{let c=`${a.message}|${a.source}|${a.line}`;pe.has(c)||pe.size>=b.errorReportsPerPage||(pe.add(c),s==="platform"?w("error",a):s==="connecting"&&me.push(a))};if(window.addEventListener("error",a=>{if(!(a instanceof ErrorEvent))return;let c=String(a.message||"Error");if(_e({message:c,source:Nt(a.filename),line:a.lineno||0,column:a.colno||0,stack:a.error instanceof Error?String(a.error.stack??""):""}),o){let m=a.error instanceof Error?`Uncaught ${te(a.error)}`:/^Uncaught\b/.test(c)?c:`Uncaught ${c}`;o.error(m,{source:Nt(a.filename),line:a.lineno||0,column:a.colno||0})}}),window.addEventListener("unhandledrejection",a=>{let c=a.reason;o?.error(`Uncaught (in promise) ${c instanceof Error?te(c):z(c)}`),_e({message:`Unhandled promise rejection: ${c instanceof Error?c.message:String(c)}`,source:"",line:0,column:0,stack:c instanceof Error?String(c.stack??""):""})}),r){window.addEventListener("message",c=>{if(!(c.source!==window.parent||c.data?.type!==Ve||!c.ports[0])&&s!=="standalone"){if(i?.close(),i=c.ports[0],i.onmessage=m=>zt(m.data),s=tt(c.data),E(),s==="platform")for(let m of me.splice(0))w("error",m);else me.length=0;o?.connect(m=>w("console",m)),D||(w("alive",{}),D=setInterval(()=>w("alive",{}),2e3)),s==="platform"&&C().then(m=>{e.apply(m.audio),m.settings&&t.apply(m.settings)}).catch(()=>{})}});let a={type:Ke,version:Tt,...n?{build:n}:{}};window.parent.postMessage(a,"*"),setTimeout(()=>{s==="connecting"&&(s="standalone",E())},5e3)}else s="standalone",E();if(window.addEventListener("keydown",a=>{a.key!=="/"||s!=="platform"||!p||Gn(a.target)||(a.preventDefault(),a.stopImmediatePropagation(),w("hotkey",{key:"/"}))},!0),r){try{document.documentElement.style.touchAction="pan-x pan-y"}catch{}for(let a of["gesturestart","gesturechange","gestureend"])document.addEventListener(a,c=>c.preventDefault(),{passive:!1})}if(r){let a=c=>{c.pointerType==="mouse"||s!=="platform"||(window.removeEventListener("pointerup",a,!0),x("ui.tapped",void 0).catch(()=>{}))};window.addEventListener("pointerup",a,!0)}if(r&&wt(()=>s==="platform",()=>w("input.first",{})),r&&Ot(navigator,()=>s==="platform",a=>w("vibrate",{pattern:a})),r){let a=Element.prototype.requestFullscreen;Element.prototype.requestFullscreen=function(c){return s!=="platform"?a.call(this,c):(x("ui.fullscreen",void 0).catch(()=>{}),Promise.resolve())}}function zt(a){if(a.kind==="res"){let m=d.get(a.id);if(!m)return;d.delete(a.id),a.ok?m.resolve(a.result):m.reject(new Error(a.error));return}if(a.kind!=="event")return;let c=a.name;if(c==="room")p?._receive(a.data);else if(c==="room.connection")a.data?.connected===!1&&p?._disconnected();else if(c==="room.closed"){let m=p;p=null,m?._closed(a.data.reason)}else if(c==="room.moved"){let m=p;p=Oe(a.data),m?._closed("moved");for(let y of R)try{y(p)}catch(_){console.error('[onceworlds] error in rooms "moved" listener',_)}}else if(c==="audio")e.apply(a.data),ee("audio",a.data);else if(c==="settings")t.apply(a.data);else if(c==="pause"||c==="resume")ee(c);else if(c==="controls")k.receive(a.data);else if(c==="input")k.touch=a.data?.touch===!0;else if(c==="reserved")$.receive(a.data)&&ee("reserved",$.areas);else if(c==="debug")for(let m of T)try{m(a.data)}catch(y){console.error("[onceworlds] error in the debugger link",y)}else if(c==="player"){let m=a.data;C().then(y=>{m?.id!==y.player.id||typeof m.name!="string"||(y.player.name=m.name,ee("player",y.player))}).catch(()=>{})}}async function x(a,c){await M;let m=i;if(!m)throw new Error("Not connected to Onceworlds");return new Promise((y,_)=>{let g=l++;d.set(g,{resolve:y,reject:_}),m.postMessage({kind:"req",id:g,method:a,params:c})})}function w(a,c){i?.postMessage({kind:"event",name:a,data:c})}function ee(a,...c){for(let m of f.get(a)??[])try{m(...c)}catch(y){console.error(`[onceworlds] error in "${a}" listener`,y)}}function Oe(a,c=S){let m={send:(g,P)=>w("room.send",{d:g,to:P}),presence:g=>w("room.presence",{d:g}),state:(g,P,A)=>w("room.state",{k:g,v:P,w:A}),hideLobby:g=>w("room.hideLobby",{hidden:g}),team:(g,P)=>w("room.team",{id:g,team:P}),open:g=>w("room.open",{open:g}),result:g=>w("room.result",{result:g}),kick:g=>w("room.kick",{id:g}),voteKick:g=>w("room.votekick",{id:g}),ready:g=>w("room.ready",{ready:g}),unready:()=>w("room.unready",{}),transfer:g=>w("room.transfer",{id:g}),start:g=>w("room.start",g),end:()=>w("room.end",{}),pause:g=>w("room.pause",{paused:g}),admit:g=>w("room.admit",{ids:g}),private:(g,P,A)=>w("room.private",{k:g,v:P,...A?{id:A}:{}}),dataReset:()=>w("room.datareset",{}),leave:()=>{p===y&&(p=null),x("room.leave",void 0).catch(()=>{})}};S=c;let y=new W(a,m,()=>Date.now()+h,c);Le(y);let _=yt(g=>w("room.idle",{idle:g}));return y.on("reconnect",()=>_.idle&&w("room.idle",{idle:!0})),y.on("close",()=>_.stop()),y}function Le(a){a.on("state",(c,m,y)=>{p===a&&fe(c)&&Q._changed(c.slice(N.length),m,y)})}function Ht(a,c){let m={};for(let[A,K]of Object.entries(ce.all()))m[N+A]=K;let y={room:"solo",you:a.id,host:a.id,players:[{...a,presence:null,team:c.teams?1:0}],state:m,chat:[],teams:c.teams??0,open:!0,now:Date.now(),ranked:!1,kept:!0,owner:a.id},g={...gt(()=>P),state(A,K){fe(A)&&ce.set(A.slice(N.length),K)},dataReset(){for(let A of Object.keys(ce.all()))ce.set(A,null),P._receive({t:"state",k:N+A,v:null,from:""})}},P=new W(y,g,()=>Date.now()+h,we(c.settings));return Le(P),P}function C(){return v??(v=M.then(()=>s==="platform"?x("session.get",void 0):jn()).then(a=>(h=Number(a.timeOffset)||0,a))),v}C().catch(()=>{});let Ce={async get(a){return await M,s==="platform"?await x("save.get",{key:a}):ae.get(a)},async set(a,c){await M,s==="platform"?await x("save.set",{key:a,value:c}):ae.set(a,c)},async delete(a){await M,s==="platform"?await x("save.delete",{key:a}):ae.delete(a)},async list(){return await M,s==="platform"?x("save.list",void 0):ae.list()}},Te={__onceworlds:!0,_debug:o?{send:a=>{i&&w("debug",a)},on:a=>(T.add(a),()=>T.delete(a))}:null,version:Tt,get mode(){return s},ready:()=>M,player:{get:()=>C().then(a=>a.player),async avatarUrl(a,c="full"){let m=await C().catch(()=>null);if(!m?.platformOrigin)return null;let y=typeof a=="string"&&a?a:m.player.id;return`${m.platformOrigin}/avatar/${encodeURIComponent(y)}${c==="head"?"/head":""}.svg`},async avatar(a){if(await M,s!=="platform")return null;let c=typeof a=="string"&&a?a:(await C()).player.id;return Je.test(c)?Be(await x("player.avatar",{id:c}).catch(()=>null)):null},async rename(){return await M,s!=="platform"?null:await x("player.rename",void 0).catch(()=>null)?(await C()).player:null}},game:{info:()=>C().then(a=>a.game)},save:Ce,data:{player:Ce,server:Q,game:jt},rooms:{async join(a={}){await M;let c=a.party===!0&&p!==null&&s==="platform";if(c||(p?.leave(),p=null),s!=="platform"){let{player:_}=await C();return p=Ht(_,a),p}let m=await x("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}:{}}),y=p;return p=Oe(m,we(a.settings)),c&&y?._closed("moved"),p},get current(){return p},on(a,c){return a!=="moved"?()=>{}:(R.add(c),()=>R.delete(c))}},ratings:{async get(a){return await M,s==="platform"?x("ratings.get",{mode:String(a)}):null},async top(a,c={}){return await M,s==="platform"?x("ratings.top",{mode:String(a),limit:c.limit}):[]}},ui:{setMenuPosition(a){x("ui.menuPosition",{position:a}).catch(()=>{})},get reserved(){return $.areas},setLook(a){let{look:c,notes:m}=_t(a);for(let y of m)G.has(y)||(G.add(y),console.warn(`[onceworlds] ui.setLook: ${y}`));s!=="standalone"&&x("ui.look",c).catch(()=>{})},requestFullscreen(){s==="platform"?x("ui.fullscreen",void 0).catch(()=>{}):document.documentElement.requestFullscreen?.().catch(()=>{})},showInvite(){s==="platform"&&x("ui.invite",void 0).catch(()=>{})},setOrientation(a){a!=="any"&&a!=="landscape"&&a!=="portrait"||s!=="standalone"&&x("ui.orientation",{orientation:a}).catch(()=>{})}},controls:{set(a){k.set(a)},get stick(){return k.stick},pressed(a){return k.pressed(String(a))},presses(a){return k.presses(String(a))},get touch(){return k.touch}},now:()=>Date.now()+h,leaderboards:{async submit(a,c,m={}){if(await M,s!=="platform")return ue.submit(String(a),Number(c),m.lowerIsBetter===!0);try{return await x("leaderboards.submit",{board:String(a),score:Number(c),lowerIsBetter:m.lowerIsBetter===!0})}catch(y){return console.warn(`[onceworlds] score for "${a}" was not saved: ${y instanceof Error?y.message:y}`),null}},async top(a,c={}){return await M,s!=="platform"?ue.top(String(a)):x("leaderboards.top",{board:String(a),limit:c.limit,lowerIsBetter:c.lowerIsBetter===!0})}},settings:t.settings,audio:{get volume(){return e.volume},get muted(){return e.muted}},badges:{async award(a){if(await M,s!=="platform")return de.add(String(a));try{return(await x("badges.award",{key:String(a)})).awarded}catch(c){return console.warn(`[onceworlds] badge "${a}" was not awarded: ${c instanceof Error?c.message:c}`),!1}},async list(){return await M,s==="platform"?x("badges.list",void 0):de.list()},async has(a){return(await Te.badges.list()).some(c=>c.key===a&&c.earned)}},env:Bn(),async fetch(a,c={}){if(await M,s!=="platform")throw new Error("onceworlds.fetch only works on Onceworlds, where your secrets are stored. Run the game with `onceworlds dev`.");let m=a instanceof Request?a:null,y=new URL(m?m.url:String(a),location.href).href,_=(c.method??m?.method??"GET").toUpperCase(),g={};new Headers(c.headers??m?.headers).forEach((Ut,Kt)=>{g[Kt]=Ut});let P=c.body??null;P===null&&m&&_!=="GET"&&_!=="HEAD"&&(P=await m.arrayBuffer()),P instanceof URLSearchParams&&(g["content-type"]??(g["content-type"]="application/x-www-form-urlencoded;charset=UTF-8"),P=P.toString());let A=await x("net.fetch",{url:y,method:_,headers:g,body:await In(P)}),K=[101,204,205,304].includes(A.status);return new Response(K?null:A.body,{status:A.status,statusText:A.statusText,headers:A.headers})},on(a,c){let m=f.get(a);return m||f.set(a,m=new Set),m.add(c),()=>m.delete(c)}};return Te}function Bn(){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 In(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 Nt(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 Gn(n){return n instanceof HTMLElement?n.isContentEditable||["INPUT","TEXTAREA","SELECT"].includes(n.tagName):!1}function jn(){let n=L.get("onceworlds:player-id");return n||(n=`local-${Math.random().toString(36).slice(2,10)}`,L.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 Bt="onceworlds:scores",ue={all(){try{let n=JSON.parse(L.get(Bt)??"{}");return n&&typeof n=="object"?n:{}}catch{return{}}},submit(n,e,t){let r=ue.all(),o=r[n],s=o===void 0?e:t?Math.min(o,e):Math.max(o,e);return r[n]=s,L.set(Bt,JSON.stringify(r)),{best:s,rank:1}},top(n){let e=ue.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}}},X="onceworlds:save:",It="onceworlds:badges",de={earned(){try{let n=JSON.parse(L.get(It)??"{}");return n&&typeof n=="object"?n:{}}catch{return{}}},add(n){let e=de.earned();return e[n]?!1:(e[n]=Date.now(),L.set(It,JSON.stringify(e)),!0)},list(){return Object.entries(de.earned()).map(([n,e])=>({key:n,name:n,description:"",icon:null,earned:!0,earnedAt:e}))}},ae={get(n){let e=L.get(X+n);if(e===null)return null;try{return JSON.parse(e)}catch{return null}},set(n,e){L.set(X+n,JSON.stringify(e??null))},delete(n){L.remove(X+n)},list(){let n=[];try{for(let e=0;e<localStorage.length;e++){let t=localStorage.key(e);t?.startsWith(X)&&n.push(t.slice(X.length))}}catch{}return n.sort()}},le="onceworlds:server:",ce={all(){let n={};try{for(let e=0;e<localStorage.length;e++){let t=localStorage.key(e);if(t?.startsWith(le))try{n[t.slice(le.length)]=JSON.parse(localStorage.getItem(t)??"null")}catch{}}}catch{}return n},set(n,e){e==null?L.remove(le+n):L.set(le+n,JSON.stringify(e))}},L={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{}}};Gt();})();
@@ -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
+ };