ball2d 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -4
- package/dist/browser.js +22 -30
- package/dist/node.js +1 -1
- package/dist/types/player.d.ts +2 -0
- package/dist/types/room.d.ts +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@ Host a Ball2D football room on your own server and control it through a typed
|
|
|
4
4
|
JavaScript API. The host runs the simulation; players connect directly over
|
|
5
5
|
WebRTC. Ball2D provides authorization, room discovery and signaling.
|
|
6
6
|
|
|
7
|
-
**Release: 0.2.
|
|
8
|
-
Node.js hosting, account quotas and key revocation.
|
|
9
|
-
|
|
7
|
+
**Release: 0.2.1.** The matching production service supports API-key-authorized
|
|
8
|
+
Node.js hosting, account quotas and key revocation. The installed 0.2.1 package passed authenticated production acceptance with a
|
|
9
|
+
real browser player, including mute/unmute, quota rejection and key revocation.
|
|
10
10
|
|
|
11
11
|
Repository maintainers: [local setup](https://github.com/fillbyte/ball2d/blob/main/docs/DEVELOPMENT.md) · [release procedure](https://github.com/fillbyte/ball2d/blob/main/docs/RELEASING.md) · [changelog](https://github.com/fillbyte/ball2d/blob/main/CHANGELOG.md).
|
|
12
12
|
|
|
@@ -16,7 +16,7 @@ Use Node.js 24 or newer. The verified native runtime is Node.js 24.19.0 on macOS
|
|
|
16
16
|
arm64; other systems need independent acceptance. Native transport is experimental.
|
|
17
17
|
|
|
18
18
|
```sh
|
|
19
|
-
npm install ball2d@0.2.
|
|
19
|
+
npm install ball2d@0.2.1
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
Create an API key through your Ball2D account.
|
|
@@ -199,3 +199,12 @@ installed-package hosting, gameplay, replay and cleanup. This evidence does not
|
|
|
199
199
|
establish broad WAN/NAT reachability,
|
|
200
200
|
Linux compatibility, sustained capacity or an uptime guarantee. Direct WebRTC
|
|
201
201
|
requires peer reachability; no TURN relay is provided.
|
|
202
|
+
|
|
203
|
+
## Player mute
|
|
204
|
+
|
|
205
|
+
`await room.setPlayerMuted(id, true)` suppresses a player's room chat; pass `false`
|
|
206
|
+
to restore it. `player.muted` exposes the current state.
|
|
207
|
+
`onPlayerMuteChange(player, byPlayer)` reports the actor (null for SDK commands).
|
|
208
|
+
Muted messages do not reach `onPlayerChat`. Remote admins may mute other players
|
|
209
|
+
but cannot mute the room owner. Mute ends when a player leaves; use a ban to
|
|
210
|
+
prevent rejoining. Losing the room host closes the room without transferring it.
|
package/dist/browser.js
CHANGED
|
@@ -3706,6 +3706,7 @@ var Rt = Object.freeze({ ...Te }), zt = class e {
|
|
|
3706
3706
|
onRoomLink;
|
|
3707
3707
|
onPlayerJoin;
|
|
3708
3708
|
onPlayerTeamChange;
|
|
3709
|
+
onPlayerMuteChange;
|
|
3709
3710
|
onPlayerAdminChange;
|
|
3710
3711
|
onGameStart;
|
|
3711
3712
|
onGameStop;
|
|
@@ -3895,8 +3896,8 @@ var Rt = Object.freeze({ ...Te }), zt = class e {
|
|
|
3895
3896
|
}
|
|
3896
3897
|
if (r && n.type === "action") {
|
|
3897
3898
|
if (n.action === "chat" && typeof n.text == "string" && n.text.length <= 200) {
|
|
3898
|
-
if (!n.text.trim() || !this.traffic.allow(e.id, "chat") || (this.invoke("onPlayerActivity", this.onPlayerActivity, this.playerCopy(r)), this.closed || !this.players.includes(r))) return;
|
|
3899
|
-
this.invoke("onPlayerChat", this.onPlayerChat, this.playerCopy(r), n.text) !== !1 && this.network.broadcast({
|
|
3899
|
+
if (r.muted || !n.text.trim() || !this.traffic.allow(e.id, "chat") || (this.invoke("onPlayerActivity", this.onPlayerActivity, this.playerCopy(r)), this.closed || !this.players.includes(r))) return;
|
|
3900
|
+
this.invoke("onPlayerChat", this.onPlayerChat, this.playerCopy(r), n.text) !== !1 && !this.closed && this.players.includes(r) && !r.muted && this.network.broadcast({
|
|
3900
3901
|
type: "chat",
|
|
3901
3902
|
name: r.name,
|
|
3902
3903
|
text: n.text
|
|
@@ -3940,6 +3941,11 @@ var Rt = Object.freeze({ ...Te }), zt = class e {
|
|
|
3940
3941
|
return;
|
|
3941
3942
|
}
|
|
3942
3943
|
if (r.admin) {
|
|
3944
|
+
if (n.action === "mute" && typeof n.muted == "boolean") {
|
|
3945
|
+
let e = this.players.find((e) => e.slot === n.slot);
|
|
3946
|
+
e && e !== r && e.peerId !== this.network.hostId && this.changePlayerMuted(e.id, n.muted, this.playerCopy(r));
|
|
3947
|
+
return;
|
|
3948
|
+
}
|
|
3943
3949
|
if (n.action === "surface" && typeof n.enabled == "boolean" && ["lobby", "finished"].includes(this.engine.phase)) {
|
|
3944
3950
|
this.setSurfaceEnabled(n.enabled);
|
|
3945
3951
|
return;
|
|
@@ -4017,7 +4023,8 @@ var Rt = Object.freeze({ ...Te }), zt = class e {
|
|
|
4017
4023
|
slot: e.slot,
|
|
4018
4024
|
name: e.name,
|
|
4019
4025
|
team: e.team,
|
|
4020
|
-
admin: e.admin
|
|
4026
|
+
admin: e.admin,
|
|
4027
|
+
muted: !!e.muted
|
|
4021
4028
|
}));
|
|
4022
4029
|
}
|
|
4023
4030
|
sync() {
|
|
@@ -4046,6 +4053,7 @@ var Rt = Object.freeze({ ...Te }), zt = class e {
|
|
|
4046
4053
|
let t = this.engine.index(e.slot) * 18, n = !this.closed && this.engine.phase !== "lobby" && this.engine.data[t + 13] > 0, { slot: r, avatarOverride: i, ...a } = e;
|
|
4047
4054
|
return {
|
|
4048
4055
|
...a,
|
|
4056
|
+
muted: !!e.muted,
|
|
4049
4057
|
avatar: e.avatarOverride ?? e.avatar ?? null,
|
|
4050
4058
|
position: n ? {
|
|
4051
4059
|
x: this.engine.data[t],
|
|
@@ -4101,6 +4109,15 @@ var Rt = Object.freeze({ ...Te }), zt = class e {
|
|
|
4101
4109
|
let n = this.players.find((t) => t.id === e);
|
|
4102
4110
|
n && n.admin !== !!t && (n.admin = !!t, this.sync(), this.invoke("onPlayerAdminChange", this.onPlayerAdminChange, this.playerCopy(n), null));
|
|
4103
4111
|
}
|
|
4112
|
+
setPlayerMuted(e, t) {
|
|
4113
|
+
this.changePlayerMuted(e, t, null);
|
|
4114
|
+
}
|
|
4115
|
+
changePlayerMuted(e, t, n) {
|
|
4116
|
+
if (this.closed) throw Error("Room is closed");
|
|
4117
|
+
if (!Number.isInteger(e) || typeof t != "boolean") throw Error("Invalid player mute");
|
|
4118
|
+
let r = this.players.find((t) => t.id === e);
|
|
4119
|
+
r && r.peerId !== this.network.hostId && !!r.muted !== t && (r.muted = t, this.sync(), this.invoke("onPlayerMuteChange", this.onPlayerMuteChange, this.playerCopy(r), n));
|
|
4120
|
+
}
|
|
4104
4121
|
setTeamsLock(e) {
|
|
4105
4122
|
this.changeTeamsLock(e, null);
|
|
4106
4123
|
}
|
|
@@ -4451,33 +4468,7 @@ var Vt = class {
|
|
|
4451
4468
|
this.active?.reject(e);
|
|
4452
4469
|
for (let t of this.pending.splice(0)) t.reject(e);
|
|
4453
4470
|
}
|
|
4454
|
-
}, Ht =
|
|
4455
|
-
"sendChat",
|
|
4456
|
-
"sendAnnouncement",
|
|
4457
|
-
"setPlayerAdmin",
|
|
4458
|
-
"setPlayerTeam",
|
|
4459
|
-
"kickPlayer",
|
|
4460
|
-
"clearBan",
|
|
4461
|
-
"clearBans",
|
|
4462
|
-
"setScoreLimit",
|
|
4463
|
-
"setTimeLimit",
|
|
4464
|
-
"setCustomStadium",
|
|
4465
|
-
"setDefaultStadium",
|
|
4466
|
-
"setTeamsLock",
|
|
4467
|
-
"setTeamColors",
|
|
4468
|
-
"startGame",
|
|
4469
|
-
"stopGame",
|
|
4470
|
-
"pauseGame",
|
|
4471
|
-
"setPassword",
|
|
4472
|
-
"setRequireVerification",
|
|
4473
|
-
"setRequireRecaptcha",
|
|
4474
|
-
"reorderPlayers",
|
|
4475
|
-
"setKickRateLimit",
|
|
4476
|
-
"setSurfaceEnabled",
|
|
4477
|
-
"setPlayerAvatar",
|
|
4478
|
-
"setDiscProperties",
|
|
4479
|
-
"setPlayerDiscProperties"
|
|
4480
|
-
];
|
|
4471
|
+
}, Ht = /* @__PURE__ */ "sendChat.sendAnnouncement.setPlayerAdmin.setPlayerMuted.setPlayerTeam.kickPlayer.clearBan.clearBans.setScoreLimit.setTimeLimit.setCustomStadium.setDefaultStadium.setTeamsLock.setTeamColors.startGame.stopGame.pauseGame.setPassword.setRequireVerification.setRequireRecaptcha.reorderPlayers.setKickRateLimit.setSurfaceEnabled.setPlayerAvatar.setDiscProperties.setPlayerDiscProperties".split(".");
|
|
4481
4472
|
function Ut(e, t) {
|
|
4482
4473
|
let n = Object.create(null);
|
|
4483
4474
|
t && Object.defineProperty(n, "closed", {
|
|
@@ -4536,6 +4527,7 @@ function Ut(e, t) {
|
|
|
4536
4527
|
"onPlayerChat",
|
|
4537
4528
|
"onPlayerTeamChange",
|
|
4538
4529
|
"onPlayerAdminChange",
|
|
4530
|
+
"onPlayerMuteChange",
|
|
4539
4531
|
"onPlayerKicked",
|
|
4540
4532
|
"onPlayerActivity",
|
|
4541
4533
|
"onPlayerBallKick",
|
package/dist/node.js
CHANGED
|
@@ -11,7 +11,7 @@ import{createRequire as e}from"node:module";import{readFile as t}from"node:fs/pr
|
|
|
11
11
|
`+t+`}`}}return r.pop(),i=t,c}function f(e){if(e.length===0)return u(e,!0);let t=String.fromCodePoint(e.codePointAt(0));if(!bt.isIdStartChar(t))return u(e,!0);for(let n=t.length;n<e.length;n++)if(!bt.isIdContinueChar(String.fromCodePoint(e.codePointAt(n))))return u(e,!0);return e}function p(e){if(r.indexOf(e)>=0)throw TypeError(`Converting circular structure to JSON5`);r.push(e);let t=i;i+=s;let n=[];for(let t=0;t<e.length;t++){let r=l(String(t),e);n.push(r===void 0?`null`:r)}let a;if(n.length===0)a=`[]`;else if(s===``)a=`[`+n.join(`,`)+`]`;else{let e=`,
|
|
12
12
|
`+i,r=n.join(e);a=`[
|
|
13
13
|
`+i+r+`,
|
|
14
|
-
`+t+`]`}return r.pop(),i=t,a}}},tn={ball:1,red:2,blue:4,redKO:8,blueKO:16,wall:32,kick:64,score:128,c0:268435456,c1:536870912,c2:1073741824,c3:-2147483648,all:63},nn=e=>{if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`Expected an object`);return e},rn=(e,t,n=-4096,r=4096)=>{let i=e===void 0?t:e;if(typeof i!=`number`||!Number.isFinite(i)||i<n||i>r)throw Error(`Number must be between ${n} and ${r}`);return i},an=(e,t=[0,0])=>{if(e===void 0)return[...t];if(!Array.isArray(e)||e.length!==2)throw Error(`Expected [x, y]`);return[rn(e[0],0),rn(e[1],0)]},on=(e,t)=>{if(e===void 0)return[];if(!Array.isArray(e)||e.length>t)throw Error(`Array limit: ${t}`);return e};function sn(e,t){return e===void 0?t:typeof e==`number`?rn(e,t,-2147483648,4294967295)|0:on(e,16).reduce((e,t)=>{if(typeof t!=`string`||!Object.hasOwn(tn,t))throw Error(`Unknown collision flag`);return e|tn[t]},0)}function cn(e,t=`FFFFFF`){if(e===void 0)return t;if(e===`transparent`)return e;if(Array.isArray(e)&&e.length===3)return e.map(e=>Math.round(rn(e,0,0,255)).toString(16).padStart(2,`0`)).join(``);if(typeof e==`string`&&/^[0-9a-f]{6}$/i.test(e))return e;throw Error(`Invalid color`)}var ln=Object.fromEntries(Object.entries({root:`version physicsMode name width height maxViewWidth cameraFollow spawnDistance canBeStored kickOffReset bg traits vertexes segments goals discs planes joints redSpawnPoints blueSpawnPoints playerPhysics ballPhysics`,bg:`type width height kickOffRadius cornerRadius goalLine color`,vertexes:`trait x y bCoef cMask cGroup`,segments:`trait v0 v1 bCoef cMask cGroup curve curveF bias color vis`,discs:`trait pos speed gravity radius invMass damping bCoef cGroup cMask color`,planes:`trait normal dist bCoef cMask cGroup`,goals:`trait p0 p1 team`,joints:`trait d0 d1 length strength color`,playerPhysics:`trait pos speed gravity radius invMass damping bCoef cGroup cMask color acceleration kickingAcceleration kickingDamping kickStrength kickback`}).map(([e,t])=>[e,new Set(t.split(` `))])),un=new Set([`vertexes`,`segments`,`discs`,`planes`,`goals`,`joints`,`playerPhysics`].flatMap(e=>[...ln[e]]));function dn(e){let t=[],n=(e,t)=>{let n=t.length>80?t.slice(0,80)+`…`:t;return e+(/^[A-Za-z_$][\w$]*$/.test(n)?`.`+n:`[`+JSON.stringify(n)+`]`)},r=(e,r,i)=>{if(e&&typeof e==`object`&&!Array.isArray(e))for(let a of Object.keys(e))r.has(a)||(t.length<64?t.push(`Unsupported stadium field: `+n(i,a)):t.length===64&&t.push(`Additional unsupported stadium fields omitted.`))};r(e,ln.root,`$`),r(e.bg,ln.bg,`$.bg`);for(let t of[`vertexes`,`segments`,`discs`,`planes`,`goals`,`joints`]){let n=e[t];Array.isArray(n)&&n.forEach((e,n)=>r(e,ln[t],`$.`+t+`[`+n+`]`))}if(r(e.ballPhysics,ln.discs,`$.ballPhysics`),r(e.playerPhysics,ln.playerPhysics,`$.playerPhysics`),e.traits&&typeof e.traits==`object`&&!Array.isArray(e.traits))for(let[t,i]of Object.entries(e.traits))r(i,un,n(`$.traits`,t));return t}function fn(e,t,n,r,i){let a=e===`hbs`?1:Math.ceil(2*Math.SQRT2*100/Math.min(10,i));if((t+32)*(n+t+32+r)*a>2e6)throw Error(`Stadium collision complexity exceeds the room budget`)}function pn(e){if(new TextEncoder().encode(e).length>262144)throw Error(`Stadium exceeds 256 KB`);let t=nn(en.parse(e));if(t.physicsMode!==void 0&&t.physicsMode!==`hbs`&&t.physicsMode!==`substeps`)throw Error(`Invalid physics mode`);let n=t.physicsMode===`substeps`?`substeps`:`hbs`;if(t.version!==void 0&&t.version!==1)throw Error(`Unsupported stadium version`);let r=t.traits===void 0?{}:nn(t.traits),i=e=>{let t=nn(e);if(t.trait===void 0)return t;if(typeof t.trait!=`string`||!Object.hasOwn(r,t.trait))throw Error(`Unknown trait`);return{...nn(r[t.trait]),...t}},a=(e,t=!1)=>({pos:an(e.pos),speed:an(e.speed),gravity:an(e.gravity),radius:rn(e.radius,10,.5,100),invMass:rn(e.invMass,1,0,8192),damping:rn(e.damping,.99,0,8192),bCoef:rn(e.bCoef,.5,-1,8192),cGroup:sn(e.cGroup,t?193:63),cMask:sn(e.cMask,63),color:cn(e.color)}),o=on(t.discs,63).map(e=>a(i(e)));if(t.ballPhysics!==`disc0`){let e=a(t.ballPhysics===void 0?{}:i(t.ballPhysics),!0);e.cGroup|=192,o.unshift(e)}else if(!o.length)throw Error(`disc0 needs a disc`);let s=on(t.vertexes,1024).map(e=>i(e)),c=[],l=[],u=dn(t);for(let e of s)c.push({a:[rn(e.x,0),rn(e.y,0)],b:[rn(e.x,0),rn(e.y,0)],bCoef:rn(e.bCoef,1,-1,8192),cGroup:sn(e.cGroup,32),cMask:sn(e.cMask,63),bias:0,color:`transparent`,vis:!1});let d=[...c];for(let e of on(t.segments,1024)){let t=i(e),n=rn(t.v0,-1,0,s.length-1),r=rn(t.v1,-1,0,s.length-1);if(!Number.isInteger(n)||!Number.isInteger(r))throw Error(`Vertex indices must be integers`);let a=[rn(s[n].x,0),rn(s[n].y,0)],o=[rn(s[r].x,0),rn(s[r].y,0)],u={bCoef:rn(t.bCoef,1,-1,8192),cGroup:sn(t.cGroup,32),cMask:sn(t.cMask,63),bias:rn(t.bias,0,-100,100),color:cn(t.color,`000000`),vis:t.vis!==!1},f=t.curveF===void 0?rn(t.curve,0,-359,359):2*Math.atan2(1,rn(t.curveF,0,-1e8,1e8))*180/Math.PI;if(Math.abs(f)<1e-4){let e={a,b:o,...u};c.push(e),(a[0]!==o[0]||a[1]!==o[1])&&d.push(e);continue}let p=f*Math.PI/180,m=o[0]-a[0],h=o[1]-a[1];if(Math.hypot(m,h)<.001)throw Error(`Arc endpoints overlap`);let g=1/(2*Math.tan(p/2)),_=[(a[0]+o[0])/2-h*g,(a[1]+o[1])/2+m*g],v=Math.hypot(a[0]-_[0],a[1]-_[1]),y=Math.atan2(a[1]-_[1],a[0]-_[0]),b=Math.ceil(Math.abs(p)/Math.max(1e-8,2*Math.acos(Math.max(-1,1-.15/v))));if(c.length+b>4096)throw Error(`Compiled geometry exceeds 4096 segments`);let x={a,b:o,...u,center:_,radius:v,start:y,sweep:p,major:t.curveF===void 0?Math.abs(f)>180:Number(t.curveF)<=0};l.push(x),d.push(x);let S=a;for(let e=1;e<=b;e++){let t=e===b?o:[_[0]+v*Math.cos(y+p*e/b),_[1]+v*Math.sin(y+p*e/b)];c.push({a:S,b:t,...u,renderOnly:!0}),S=t}}if(c.length>4096)throw Error(`Compiled geometry exceeds 4096 segments`);let f=t.playerPhysics===void 0?{}:i(t.playerPhysics),p={...a({...f,radius:f.radius??15,invMass:f.invMass??.5,damping:f.damping??.96,cGroup:f.cGroup??0}),acceleration:rn(f.acceleration,.1,-8192,8192),kickingAcceleration:rn(f.kickingAcceleration,.07,-8192,8192),kickingDamping:rn(f.kickingDamping,.96,0,8192),kickStrength:rn(f.kickStrength,5,-8192,8192),kickback:rn(f.kickback,0,-8192,8192)};fn(n,o.length,c.length,on(t.planes,64).length+on(t.joints,128).length,Math.min(p.radius,...o.map(e=>e.radius)));let m=t.bg===void 0?{}:nn(t.bg);return{version:1,physicsMode:n,name:typeof t.name==`string`?t.name.slice(0,64):`Untitled stadium`,canBeStored:t.canBeStored!==!1,width:rn(t.width,520,100,2048),height:rn(t.height,300,80,2048),maxViewWidth:rn(t.maxViewWidth,0,0,4096),cameraFollow:t.cameraFollow===`player`?`player`:`ball`,bg:{type:m.type===`grass`?`grass`:m.type===`hockey`?`hockey`:`none`,cornerRadius:rn(m.cornerRadius,0,0,500),goalLine:rn(m.goalLine,0,0,2048),width:rn(m.width,0,0,2048),height:rn(m.height,0,0,2048),color:cn(m.color,`718C5A`),kickOffRadius:rn(m.kickOffRadius,0,0,500)},discs:o,segments:c,arcs:l,colliders:d,player:p,spawnDistance:rn(t.spawnDistance,200,0,1500),kickOffReset:t.kickOffReset===`full`?`full`:`partial`,redSpawnPoints:on(t.redSpawnPoints,32).map(e=>an(e)),blueSpawnPoints:on(t.blueSpawnPoints,32).map(e=>an(e)),warnings:u,planes:on(t.planes,64).map(e=>{let t=i(e),n=an(t.normal);if(Math.hypot(...n)<1e-6)throw Error(`Plane normal is zero`);return{normal:n,dist:rn(t.dist,0),bCoef:rn(t.bCoef,1,-1,8192),cGroup:sn(t.cGroup,32),cMask:sn(t.cMask,63)}}),goals:on(t.goals,16).map(e=>{let t=i(e);if(t.team!==`red`&&t.team!==`blue`)throw Error(`Invalid goal team`);let n=an(t.p0),r=an(t.p1);if(Math.hypot(r[0]-n[0],r[1]-n[1])<1)throw Error(`Goal has zero length`);return{p0:n,p1:r,team:t.team===`red`?1:2}}),joints:on(t.joints,128).map(e=>{let t=i(e),n=rn(t.d0,-1,0,o.length-1),r=rn(t.d1,-1,0,o.length-1);if(!Number.isInteger(n)||!Number.isInteger(r)||n===r)throw Error(`Invalid joint indices`);let a=Math.hypot(o[r].pos[0]-o[n].pos[0],o[r].pos[1]-o[n].pos[1]),s=t.length==null?[a,a]:typeof t.length==`number`?[t.length,t.length]:an(t.length);return{d0:n,d1:r,min:rn(s[0],0,0),max:rn(s[1],0,0),strength:t.strength===void 0||t.strength===`rigid`?`rigid`:rn(t.strength,0,-8192,8192),color:cn(t.color,`000000`)}})}}function mn(e=`Emerald Arena`,t=440,n=220){let r=[[-t,-n],[t,-n],[-t,n],[t,n],[-t,-70],[-t,70],[t,-70],[t,70],[-t-30,-70],[-t-30,70],[t+30,-70],[t+30,70],[0,-n-40],[0,-65],[0,65],[0,n+40]];return JSON.stringify({version:1,physicsMode:`substeps`,name:e,width:t+75,height:n+65,spawnDistance:t*.4,bg:{type:`grass`,width:t,height:n,kickOffRadius:65,color:`285B35`},vertexes:r.map(([e,t],n)=>({x:e,y:t,...n>=12?{cGroup:[`redKO`,`blueKO`],cMask:[`red`,`blue`]}:{}})),segments:[...[[0,1],[2,3],[0,4],[5,2],[1,6],[7,3],[4,8],[8,9],[9,5],[6,10],[10,11],[11,7]].map(([e,t],n)=>({v0:e,v1:t,cMask:[`ball`],color:n<6?`72A99C`:`3D7267`,bCoef:n<6?.8:.15})),{v0:12,v1:13,vis:!1,cGroup:[`redKO`,`blueKO`],cMask:[`red`,`blue`]},{v0:14,v1:15,vis:!1,cGroup:[`redKO`,`blueKO`],cMask:[`red`,`blue`]},{v0:14,v1:13,curve:-180,vis:!1,cGroup:[`redKO`],cMask:[`red`,`blue`]},{v0:14,v1:13,curve:180,vis:!1,cGroup:[`blueKO`],cMask:[`red`,`blue`]}],planes:[{normal:[0,1],dist:-n-40},{normal:[0,-1],dist:-n-40},{normal:[1,0],dist:-t-50},{normal:[-1,0],dist:-t-50}],goals:[{p0:[-t,-70],p1:[-t,70],team:`red`},{p0:[t,-70],p1:[t,70],team:`blue`}],discs:[...[-t,t].flatMap(e=>[-70,70].map(t=>({pos:[e,t],radius:6,invMass:0,color:`DAEEE4`,bCoef:.5})))],ballPhysics:{radius:9,damping:.991,bCoef:.6},playerPhysics:{radius:15,acceleration:.11,damping:.96,kickStrength:5.5}},null,2)}var hn=`ball2d-core/1/${vt}`,gn=class e{core;terrain;stadium;source=``;colors=[];tick=0;elapsed=0;ballKicks=[];red=0;blue=0;phase=`lobby`;paused=!1;resumeTicks=0;countdown=0;kickoff=1;kickoffActive=!0;scoreLimit=5;timeLimit=300;lastGoal=0;kickRate=2;setKickRateLimit(e,t,n){this.kickRate=_n(e,t,n),this.core.kick_limits(this.kickRate&255,this.kickRate>>>8&255,this.kickRate>>>16)}constructor(e){this.core=e.exports,this.terrain=new et(this.core)}configureSurface(e){if(this.phase!==`lobby`&&this.phase!==`finished`)throw Error(`Stop the match before configuring its surface`);e===null?this.terrain.disable():this.terrain.configure(e)}setSurfaceWeather(e){this.terrain.setWeather(e)}sampleSurface(e,t){return this.terrain.sample(e,t)}get surfaceEnabled(){return this.terrain.enabled}static async create(t,n){let r=t??await(await fetch(`/core.wasm?v=edb227eac070ad86a151`,{signal:n})).arrayBuffer();if(Array.from(new Uint8Array(await crypto.subtle.digest(`SHA-256`,r))).map(e=>e.toString(16).padStart(2,`0`)).join(``)!==`1229b1b4ba3892d6073fb85b3b6231282c2d81ee270808cb0acda874d49cb87e`)throw Error(`Physics build changed. Refresh the page to load a matching version.`);return new e(await WebAssembly.instantiate(await WebAssembly.compile(r)))}get data(){return new Float64Array(this.core.memory.buffer,this.core.data_ptr(),this.core.count()*18)}load(e){this.stadium=pn(e),this.source=e,this.core.reset(),this.terrain.disable(),this.colors=[],this.core.physics_mode(+(this.stadium.physicsMode===`substeps`)),this.tick=0,this.elapsed=0,this.red=this.blue=0,this.phase=`lobby`,this.paused=!1,this.resumeTicks=0,this.countdown=0,this.kickoffActive=!0;for(let e of this.stadium.discs)this.add(e);for(let e=0;e<32;e++)this.add(this.stadium.player,e+1);for(let e of this.stadium.colliders)if(`center`in e){let t=e;this.core.arc(...t.center,t.radius,...t.a,...t.b,t.sweep,+t.major,t.bCoef,t.cGroup,t.cMask,t.bias)}else{let t=e;this.core.wall(...t.a,...t.b,t.bCoef,t.cGroup,t.cMask,t.bias)}for(let e of this.stadium.planes)this.core.plane(...e.normal,e.dist,e.bCoef,e.cGroup,e.cMask);for(let e of this.stadium.joints)this.core.joint(e.d0,e.d1,e.min,e.max,e.strength===`rigid`?1/0:e.strength);for(let e of this.stadium.goals)this.core.goal(...e.p0,...e.p1,e.team);let t=this.stadium.player;this.core.configure(t.acceleration,t.kickStrength,t.kickingAcceleration,t.kickingDamping,t.kickback,this.kickRate&255),this.setKickRateLimit(this.kickRate&255,this.kickRate>>>8&255,this.kickRate>>>16)}add(e,t=0){let n=this.core.add_disc();if(n<0)throw Error(`Disc capacity exceeded`);this.colors.push(e.color===`transparent`?-1:parseInt(e.color,16)),[...e.pos,...e.speed,e.radius,e.invMass,e.damping,e.bCoef,...e.gravity,e.cGroup,e.cMask,t,0,0,0,e.pos[0],t?0:e.pos[1]].forEach((e,t)=>this.core.set_disc(n,t,e))}index(e){if(!Number.isInteger(e)||e<0||e>=32)throw Error(`Invalid slot`);return this.stadium.discs.length+e}joinPlayer(e){let t=this.index(e)*18;this.data[t+15]=0,this.data[t+17]=0,this.setTeam(e,0)}setTeam(e,t){if(![0,1,2].includes(t))throw Error(`Invalid team`);let n=this.index(e),r=this.data;r[n*18+13]=t,r[n*18+10]=this.stadium.player.cGroup|(t===1?2:t===2?4:0),r[n*18+14]=0,this.spawn(n,e,t,this.phase!==`lobby`)}input(e,t){let n=this.data,r=this.index(e)*18,i=t&31;i&16?n[r+14]&16||(n[r+15]=n[r+15]|1024):n[r+15]=n[r+15]&1023,n[r+14]=i}applyDiscProperties(e,t){let n=this.data;if(this.phase===`lobby`||!Number.isInteger(e)||e<0||e>=this.colors.length||n[e*18+12]>0&&n[e*18+13]===0)return!1;let r=_t(t),i=!1;for(let[t,a]of gt){let o=r[t];if(o===void 0)continue;let s=a===-1?this.colors[e]:n[e*18+a];Object.is(s,o)||(i=!0)}if(!i)return!1;if(r.radius!==void 0){let t=r.radius;for(let r=0;r<this.colors.length;r++)r!==e&&(t=Math.min(t,n[r*18+4]));fn(this.stadium.physicsMode,this.stadium.discs.length,this.stadium.segments.length,this.stadium.planes.length+this.stadium.joints.length,t)}for(let[t,i]of gt){let a=r[t];a!==void 0&&(i===-1?this.colors[e]=a:n[e*18+i]=a)}return!0}restoreDiscProperties(e,t){let n=e*18,r=this.data;this.colors[e]=t.color===`transparent`?-1:parseInt(t.color,16),r[n+4]=t.radius,r[n+5]=t.invMass,r[n+6]=t.damping,r[n+7]=t.bCoef,r[n+8]=t.gravity[0],r[n+9]=t.gravity[1],r[n+10]=t.cGroup,r[n+11]=t.cMask}spawn(e,t,n,r=!1){this.restoreDiscProperties(e,this.stadium.player),this.colors[e]=n===1?16087152:n===2?7516147:16777215,this.data[e*18+10]|=n===1?2:n===2?4:0;let i=n===1?this.stadium.redSpawnPoints:this.stadium.blueSpawnPoints,a=this.data,o=0;for(let e=0;e<t;e++)a[this.index(e)*18+13]===n&&o++;let s=n===1?-1:1,c=i.length?i[r?i.length-1:Math.min(o,i.length-1)]:r?[s*this.stadium.width,0]:[s*this.stadium.spawnDistance,o?Math.ceil(o/2)*55*(o%2?1:-1):0];a[e*18]=c[0],a[e*18+1]=c[1],a[e*18+2]=a[e*18+3]=a[e*18+14]=0,a[e*18+15]&=1023,a[e*18+11]=this.stadium.player.cMask&-25}resetPositions(e=!1){this.kickoffActive=!0;let t=this.data;for(let n=0;n<this.stadium.discs.length;n++){let r=this.stadium.discs[n];(e||n===0||this.stadium.kickOffReset===`full`)&&(this.restoreDiscProperties(n,r),t[n*18]=r.pos[0],t[n*18+1]=r.pos[1],t[n*18+2]=r.speed[0],t[n*18+3]=r.speed[1])}for(let e=0;e<32;e++){let n=this.index(e);this.spawn(n,e,t[n*18+13])}}start(){(this.phase===`lobby`||this.phase===`finished`)&&(this.red=this.blue=this.elapsed=0,this.phase=`playing`,this.paused=!1,this.resumeTicks=0,this.kickoff=1,this.countdown=0,this.resetPositions(!0))}stop(){this.phase=`lobby`,this.paused=!1,this.resumeTicks=0}setPaused(e){this.phase!==`lobby`&&(e=!!e,this.paused!==e&&(this.paused=e,this.resumeTicks=e?0:119))}finish(){this.phase=`finished`,this.countdown=300}step(){if(this.ballKicks.length=0,this.tick++,this.paused||this.phase===`lobby`)return;if(this.resumeTicks>0){this.resumeTicks--;return}let e=this.data;this.core.step();for(let e=this.core.ball_kick_events()>>>0,t=0;e;e>>>=1,t++)e&1&&this.ballKicks.push(t);if(this.phase===`finished`){--this.countdown<=0&&this.stop();return}if(this.phase===`goal`){--this.countdown<=0&&(this.scoreLimit>0&&Math.max(this.red,this.blue)>=this.scoreLimit||this.timeLimit>0&&this.elapsed>=this.timeLimit*60&&this.red!==this.blue?this.finish():(this.phase=`playing`,this.resetPositions()));return}for(let t=0;t<32;t++){let n=this.index(t)*18,r=this.stadium.player.cMask;e[n+11]=r&-25|(this.kickoffActive?r&(this.kickoff===1?8:16):0)}if(this.kickoffActive){e[2]*e[2]+e[3]*e[3]>0&&(this.kickoffActive=!1);return}this.elapsed++;let t=this.core.goal_event();if(t===1||t===2){t===1?this.red++:this.blue++,this.kickoff=t===1?2:1,this.phase=`goal`,this.countdown=150,this.lastGoal=this.tick;return}this.timeLimit>0&&this.elapsed>=this.timeLimit*60&&this.red!==this.blue&&this.finish()}snapshotSurface(){return this.terrain.snapshot()}snapshot(){let e=this.snapshotSurface();return{...e.length?{surface:e}:{},tick:this.tick,elapsed:this.elapsed,red:this.red,blue:this.blue,phase:this.phase,paused:this.paused,resumeTicks:this.resumeTicks,countdown:this.countdown,kickoff:this.kickoff,kickoffActive:this.kickoffActive,scoreLimit:this.scoreLimit,timeLimit:this.timeLimit,kickRate:this.kickRate,discs:Array.from(this.data),colors:[...this.colors]}}restore(e){if(!e||typeof e!=`object`||!Array.isArray(e.discs)||e.discs.length!==this.data.length||!e.discs.every((e,t)=>typeof e==`number`&&Number.isFinite(e)&&Math.abs(e)<=(t%18==10||t%18==11?2147483648:t%18==17?25500:8192)))throw Error(`Invalid state`);if(!Array.isArray(e.colors)||e.colors.length!==e.discs.length/18||e.colors.some(e=>!Number.isInteger(e)||e<-1||e>16777215))throw Error(`Invalid disc colors`);let t=(e,t,n=0)=>Number.isInteger(e)&&e>=n&&e<=t;if(!t(e.kickRate,6619135)||!t(e.tick,4294967295)||!t(e.elapsed,4294967295)||!t(e.red,65535)||!t(e.blue,65535)||!t(e.countdown,300)||!t(e.resumeTicks,119)||(e.paused||e.phase===`lobby`)&&e.resumeTicks!==0||!t(e.scoreLimit,99)||!t(e.timeLimit,5940)||![`lobby`,`playing`,`goal`,`finished`].includes(e.phase)||typeof e.paused!=`boolean`||typeof e.kickoffActive!=`boolean`||![1,2].includes(e.kickoff))throw Error(`Invalid match metadata`);for(let n=0;n<e.discs.length;n+=18)if(e.discs[n+4]<.5||e.discs[n+4]>100||e.discs[n+5]<0||e.discs[n+5]>8192||e.discs[n+6]<0||e.discs[n+6]>8192||e.discs[n+7]<-1||e.discs[n+7]>8192||!t(e.discs[n+10],2147483647,-2147483648)||!t(e.discs[n+11],2147483647,-2147483648)||!t(e.discs[n+13],2)||!t(e.discs[n+14],31)||!t(e.discs[n+15],2047)||e.discs[n+12]>0&&(!Number.isInteger(e.discs[n+17])||e.discs[n+17]<-255||e.discs[n+17]>25500))throw Error(`Invalid disc properties`);let n=10;for(let t=4;t<e.discs.length;t+=18)n=Math.min(n,e.discs[t]);fn(this.stadium.physicsMode,this.stadium.discs.length,this.stadium.segments.length,this.stadium.planes.length+this.stadium.joints.length,n),this.terrain.restore(e.surface===void 0?[]:e.surface),this.setKickRateLimit(e.kickRate&255,e.kickRate>>>8&255,e.kickRate>>>16),this.tick=e.tick,this.elapsed=e.elapsed,this.red=e.red,this.blue=e.blue,this.phase=e.phase,this.paused=e.paused,this.resumeTicks=e.resumeTicks,this.countdown=e.countdown,this.kickoff=e.kickoff,this.kickoffActive=e.kickoffActive,this.scoreLimit=e.scoreLimit,this.timeLimit=e.timeLimit,this.data.set(e.discs),this.colors=[...e.colors]}};function _n(e,t,n){if(![e,t,n].every(Number.isInteger))throw Error(`Invalid kick rate limit`);return Math.max(0,Math.min(255,e))|Math.max(0,Math.min(255,t))<<8|Math.max(0,Math.min(100,n))<<16}function vn(e){let t=new URL(e);if(![`http:`,`https:`].includes(t.protocol)||t.username||t.password||t.pathname!==`/`||t.search||t.hash)throw Error(`Expected an HTTP(S) service origin without credentials or a path`);return t.origin}function yn(){return{serviceOrigin:location.origin,signalingResume:!0,createWebSocket:e=>new WebSocket(e),createPeerConnection:e=>new RTCPeerConnection(e)}}var bn=[[`classic`,`Classic`],[`easy`,`Easy`],[`small`,`Small`],[`big`,`Big`],[`rounded`,`Rounded`],[`hockey`,`Hockey`],[`big_easy`,`Big Easy`],[`big_rounded`,`Big Rounded`],[`big_hockey`,`Big Hockey`],[`huge`,`Huge`]];function xn(e){let t=new Map;return async n=>{let r=bn.find(([e,t])=>e===n||t===n);if(!r)throw Error(`Unknown default stadium`);let i=t.get(r[0]);return i||(i=(async()=>{let t=await e(`/stadiums/${r[0]}.hbs`);if(!t.ok)throw Error(`Could not load stadium`);let n=await t.text();return pn(n),n})(),t.set(r[0],i),i.catch(()=>t.delete(r[0]))),i}}function Sn(){let e=yn(),t=(e,t)=>fetch(e,t);return{network:e,request:t,loadEngine:e=>gn.create(void 0,e),loadStadium:xn(n=>t(new URL(n,e.serviceOrigin)))}}var Cn={message:{burst:240,perSecond:160},action:{burst:12,perSecond:6},chat:{burst:4,perSecond:1}},wn=class{peers=new Map;allow(e,t,n=performance.now()){let r=this.peers.get(e);r||(r={},this.peers.set(e,r));let{burst:i,perSecond:a}=Cn[t],o=r[t]??{tokens:i,at:n};return o.tokens=Math.min(i,o.tokens+Math.max(0,n-o.at)*a/1e3),o.at=Math.max(o.at,n),r[t]=o,o.tokens<1?!1:(o.tokens--,!0)}delete(e){this.peers.delete(e)}clear(){this.peers.clear()}},Tn=33554432,En=new TextEncoder;new TextDecoder(`utf-8`,{fatal:!0});function Dn(e){let t=2166136261;for(let n of e)t=Math.imul(t^n,16777619);return t>>>0}function On(e){if(e.length>33554432)throw Error(`Replay exceeds 32 MB`);let t=Je(e,{level:6}),n=new Uint8Array(16+t.length),r=new DataView(n.buffer);return n.set([66,50,68,90,1,0,0,0]),r.setUint32(8,e.length,!0),r.setUint32(12,Dn(e),!0),n.set(t,16),n}function kn(e){if(typeof e==`string`){if(En.encode(e).length>33554432)throw Error(`Replay exceeds 32 MB`);return En.encode(e)}let t=e instanceof Uint8Array?e:new Uint8Array(e);if(t.length>33554432)throw Error(`Replay exceeds 32 MB`);if(t[0]!==66||t[1]!==50||t[2]!==68||t[3]!==90)return t;if(t.length<17||t[4]!==1||t[5]||t[6]||t[7])throw Error(`Invalid compressed replay header`);let n=new DataView(t.buffer,t.byteOffset,t.byteLength),r=n.getUint32(8,!0);if(!r||r>33554432)throw Error(`Invalid expanded replay size`);let i=new Uint8Array(r),a=0,o=!1,s=new Ye((e,t)=>{if(a+e.length>r)throw Error(`Expanded replay exceeds declared size`);i.set(e,a),a+=e.length,o=t});for(let e=16;e<t.length;e+=1024)s.push(t.subarray(e,e+1024),e+1024>=t.length);if(!o||a!==r||Dn(i)!==n.getUint32(12,!0))throw Error(`Compressed replay integrity failure`);return i}var An=[`input`,`team`,`start`,`stop`,`pause`,`scoreLimit`,`timeLimit`,`kickRate`,`join`,`disc`,`surface`],jn=new TextEncoder,Mn=new TextDecoder(`utf-8`,{fatal:!0});function Nn(e){return On(Pn(e))}function Pn(e){let{commands:t,...n}=e,r=t.some(e=>e.kind===`surface`)||e.initial.surface!==void 0||e.checkpoints.some(e=>e.state.surface!==void 0)?4:t.some(e=>e.kind===`disc`)?3:e.checkpoints.length?2:1,i=0,a=e.checkpoints.map(e=>{let t=e.state.discs;if(!Array.isArray(t)||t.length>1728||t.some(e=>!Number.isFinite(e)))throw Error(`Invalid checkpoint discs`);i+=t.length*8;let n=e.state.surface;if(n!==void 0){if(!Array.isArray(n)||n.length!==0&&n.length!==5389||n.some(e=>!Number.isInteger(e)||e<0||e>4294967295))throw Error(`Invalid checkpoint surface`);i+=n.length*4}return{...e,state:{...e.state,discs:t.length,...n===void 0?{}:{surface:n.length}}}});if(a.length>721)throw Error(`Too many replay checkpoints`);let o=jn.encode(JSON.stringify(r>=2?{...n,checkpoints:a}:n));if(t.length>5e5||o.length+16>33554432)throw Error(`Replay exceeds bounds`);let s=t.length*12+t.filter(e=>e.kind===`disc`).length*106,c=new Uint8Array(Math.min(Tn,s)),l=new DataView(c.buffer),u=e=>{if(d+e>c.length)throw Error(`Replay exceeds bounds`)},d=0,f=e.initial.tick,p=e=>{if(!Number.isInteger(e)||e<0||e>4294967295)throw Error(`Invalid replay integer`);do{u(1);let t=Math.floor(e/128);c[d++]=e%128|(t?128:0),e=t}while(e)};for(let e of t){let t=An.indexOf(r<3&&e.kind===`join`?`team`:e.kind);if(e.kind===`join`&&e.value!==0||e.kind===`team`&&e.value>2)throw Error(`Invalid replay team command`);if(t<0||!Number.isInteger(e.slot)||e.slot<0||e.slot>(e.kind===`disc`?95:31))throw Error(`Invalid replay command`);if(p(e.tick-f),u(1),c[d++]=r>=3?t:t<<5|e.slot,r>=3&&p(e.slot),p(r<3&&e.kind===`join`?3:e.value),e.kind===`disc`){let t=_t(e.properties),n=0;gt.forEach(([e],r)=>{t[e]!==void 0&&(n|=1<<r)}),p(n);for(let[e]of gt){let n=t[e];n!==void 0&&(u(8),l.setFloat64(d,n,!0),d+=8)}}f=e.tick}let m=16+o.length+i+d;if(m>33554432)throw Error(`Replay exceeds 32 MB`);let h=new Uint8Array(m),g=new DataView(h.buffer);h.set([66,50,68,80,r,0,0,0]),g.setUint32(8,o.length,!0),g.setUint32(12,t.length,!0),h.set(o,16);let _=16+o.length;for(let t of e.checkpoints){for(let e of t.state.discs)g.setFloat64(_,e,!0),_+=8;for(let e of t.state.surface??[])g.setUint32(_,e,!0),_+=4}return h.set(c.subarray(0,d),_),h}function Fn(e){let t=kn(e);if(t[0]!==66||t[1]!==50||t[2]!==68||t[3]!==80)return JSON.parse(Mn.decode(t));if(t.length<16||![1,2,3,4].includes(t[4])||t[5]||t[6]||t[7])throw Error(`Invalid packed replay header`);let n=new DataView(t.buffer,t.byteOffset,t.byteLength),r=n.getUint32(8,!0),i=n.getUint32(12,!0);if(r>t.length-16||i>5e5||i>(t.length-16-r)/3)throw Error(`Invalid packed replay bounds`);let a=JSON.parse(Mn.decode(t.subarray(16,16+r)));if(!a||!Number.isSafeInteger(a.initial?.tick)||a.initial.tick<0)throw Error(`Invalid replay initial tick`);a.commands=[];let o=16+r,s=a.initial.tick;if(t[4]>=2){if(!Array.isArray(a.checkpoints)||a.checkpoints.length>721)throw Error(`Invalid packed checkpoints`);let e=0;for(let n of a.checkpoints){let r=n?.state?.discs;if(typeof r!=`number`||!Number.isInteger(r)||r<0||r>1728)throw Error(`Invalid checkpoint disc count`);if(e+=r*8,t[4]>=4&&n.state.surface!==void 0){let t=n.state.surface;if(t!==0&&t!==5389)throw Error(`Invalid checkpoint surface count`);e+=t*4}}if(e>t.length-o-i*3)throw Error(`Truncated checkpoint discs`);for(let e of a.checkpoints){let r=e.state.discs,i=Array(r);for(let e=0;e<r;e++){let t=n.getFloat64(o,!0);if(!Number.isFinite(t))throw Error(`Nonfinite checkpoint disc`);i[e]=t,o+=8}if(e.state.discs=i,t[4]>=4&&e.state.surface!==void 0){let t=e.state.surface,r=Array(t);for(let e=0;e<t;e++)r[e]=n.getUint32(o,!0),o+=4;e.state.surface=r}}}let c=()=>{let e=0;for(let n=0;n<=28;n+=7){if(o>=t.length)throw Error(`Truncated replay command`);let r=t[o++];if(n===28&&r>15)throw Error(`Replay integer overflow`);if(e+=(r&127)*2**n,!(r&128)){if(n&&r===0)throw Error(`Noncanonical replay integer`);return e}}throw Error(`Invalid replay integer`)};for(let e=0;e<i;e++){if(s+=c(),!Number.isSafeInteger(s)||o>=t.length)throw Error(`Invalid replay tick`);let e=t[o++],r=An[t[4]>=3?e:e>>5];if(!r)throw Error(`Unknown replay command`);let i=t[4]>=3?c():e&31,l=c();if(r===`disc`){let e=c();if(e>8191)throw Error(`Invalid disc property mask`);let u={};gt.forEach(([r],i)=>{if(e&1<<i){if(o+8>t.length)throw Error(`Truncated disc properties`);u[r]=n.getFloat64(o,!0),o+=8}}),a.commands.push({tick:s,kind:r,slot:i,value:l,properties:_t(u)});continue}a.commands.push(t[4]<3&&r===`team`&&l===3?{tick:s,kind:`join`,slot:i,value:0}:{tick:s,kind:r,slot:i,value:l})}if(o!==t.length)throw Error(`Trailing replay command data`);return a}function In(e){let t=JSON.stringify(e),n=2166136261;for(let e=0;e<t.length;e++)n^=t.charCodeAt(e),n=Math.imul(n,16777619);return(n>>>0).toString(16).padStart(8,`0`)}function Ln(e,t){switch(t.kind){case`surface`:if(t.slot!==0||t.value!==0&&t.value!==1)throw Error(`Invalid surface command`);e.configureSurface(t.value?{seed:42,halfWidth:e.stadium.bg.width||e.stadium.width,halfHeight:e.stadium.bg.height||e.stadium.height,moisturePermille:1e3}:null),t.value&&e.setSurfaceWeather({rainMilliMmH:2e5,temperatureMilliC:2e4,humidityPermille:1e3,windMilliMS:0});break;case`disc`:e.applyDiscProperties(t.slot,t.properties);break;case`input`:e.input(t.slot,t.value);break;case`join`:e.joinPlayer(t.slot);break;case`team`:e.setTeam(t.slot,t.value);break;case`start`:e.start();break;case`stop`:e.stop();break;case`scoreLimit`:e.scoreLimit=t.value;break;case`timeLimit`:e.timeLimit=t.value;break;case`kickRate`:e.setKickRateLimit(t.value&255,t.value>>>8&255,t.value>>>16);break;case`pause`:e.setPaused(!!t.value)}}var Rn=class{replay;playerOrder=[];lastInputs=new Map;bytes=0;full=!1;canRecord(e){return!this.full&&e.tick-this.replay.initial.tick<216e3}constructor(e,t=[],n=[null,null]){let r=e.snapshot();this.playerOrder=t.map(e=>e.slot),this.replay={magic:`B2DR`,version:1,engine:hn,stadium:e.source,initial:r,commands:[],checkpoints:[],roster:t.map(e=>({...e,tick:r.tick})),styles:[{tick:r.tick,teams:ft(n)}],orders:[{tick:r.tick,slots:[...this.playerOrder]}],end:r.tick,finalHash:In(r)},this.bytes=new TextEncoder().encode(JSON.stringify(this.replay)).length;for(let t=0;t<32;t++)this.lastInputs.set(t,e.data[e.index(t)*18+14])}reserve(e){let t=new TextEncoder().encode(JSON.stringify(e)).length+1;return this.full||this.bytes+t>31457280?(this.full=!0,!1):(this.bytes+=t,!0)}player(e,t,n,r){let i={tick:e,slot:t,name:n,avatar:r};return this.replay.roster.length>=4096||!this.reserve(i)?(this.full=!0,!1):(this.replay.roster.push(i),n===null?this.order(e,this.playerOrder.filter(e=>e!==t)):this.playerOrder.includes(t)?!0:this.order(e,[...this.playerOrder,t]))}style(e,t){let n={tick:e,teams:ft(t)},r=this.replay.styles;return r.length>=4096||!this.reserve(n)?(this.full=!0,!1):(r.push(n),!0)}order(e,t){if(t.length===this.playerOrder.length&&t.every((e,t)=>e===this.playerOrder[t]))return!0;let n={tick:e,slots:[...t]},r=this.replay.orders;return r.length>=4096||!this.reserve(n)?(this.full=!0,!1):(this.playerOrder=[...t],r.push(n),!0)}command(e){return e.kind===`input`&&this.lastInputs.get(e.slot)===e.value?!0:this.replay.commands.length>=5e5||!this.reserve(e)?(this.full=!0,!1):(e.kind===`input`&&this.lastInputs.set(e.slot,e.value),(e.kind===`team`||e.kind===`join`)&&this.lastInputs.set(e.slot,0),e.kind===`start`&&this.lastInputs.clear(),this.replay.commands.push(e.kind===`disc`?{...e,properties:_t(e.properties)}:{...e}),!0)}step(e){for(let t=0;t<32;t++)this.lastInputs.set(t,e.data[e.index(t)*18+14]);if(e.tick%300==0){let t=e.snapshot(),n={tick:e.tick,state:t,hash:In(t)};this.reserve(n)&&this.replay.checkpoints.push(n)}this.replay.end=e.tick}pack(e){return this.replay.end=e.tick,this.replay.finalHash=In(e.snapshot()),Pn(this.replay)}finish(e){return this.replay.end=e.tick,this.replay.finalHash=In(e.snapshot()),new Blob([Nn(this.replay)],{type:`application/x-ball2d-replay`})}};async function zn(e){if(e.size>33554432)throw Error(`Replay exceeds 32 MB`);return Bn(await e.arrayBuffer())}function Bn(e){let t=Fn(e);if(t.magic!==`B2DR`||t.version!==1||t.engine!==hn)throw Error(`Unsupported replay engine/version`);if(!Array.isArray(t.commands)||t.commands.length>5e5||!Array.isArray(t.checkpoints)||t.checkpoints.length>721||!Number.isInteger(t.end)||t.end<t.initial.tick||t.end-t.initial.tick>216e3)throw Error(`Invalid replay bounds`);let n=t.initial.tick;for(let e of t.commands){if(!Number.isInteger(e.tick)||e.tick<n||e.tick>t.end||![`input`,`team`,`start`,`stop`,`pause`,`scoreLimit`,`timeLimit`,`kickRate`,`join`,`disc`,`surface`].includes(e.kind)||e.kind===`surface`&&e.slot!==0||!Number.isInteger(e.slot)||e.slot<0||e.slot>(e.kind===`disc`?95:31)||!Number.isInteger(e.value)||e.value<0||e.value>(e.kind===`disc`||e.kind===`join`?0:e.kind===`kickRate`?6619135:e.kind===`timeLimit`?5940:e.kind===`scoreLimit`?99:e.kind===`team`?2:e.kind===`pause`||e.kind===`surface`?1:31))throw Error(`Invalid replay command`);e.kind===`disc`&&(e.properties=_t(e.properties)),n=e.tick}if(!Array.isArray(t.roster)||t.roster.length>4096)throw Error(`Invalid replay roster`);n=t.initial.tick;for(let e of t.roster){if(!Number.isInteger(e.tick)||e.tick<n||e.tick>t.end||!Number.isInteger(e.slot)||e.slot<0||e.slot>31||e.name!==null&&(typeof e.name!=`string`||e.name.length>24)||e.avatar!==void 0&&!ht(e.avatar))throw Error(`Invalid roster event`);n=e.tick}if(t.styles!==void 0){if(!Array.isArray(t.styles)||t.styles.length>4096)throw Error(`Invalid replay styles`);let e=t.initial.tick;for(let n of t.styles){if(!n||!Number.isInteger(n.tick)||n.tick<e||n.tick>t.end||n.teams===void 0)throw Error(`Invalid replay style`);n.teams=ft(n.teams),e=n.tick}}if(t.orders!==void 0){if(!Array.isArray(t.orders)||t.orders.length>4096)throw Error(`Invalid replay orders`);let e=t.initial.tick;for(let n of t.orders){if(!n||!Number.isInteger(n.tick)||n.tick<e||n.tick>t.end||!Array.isArray(n.slots)||n.slots.length>32||n.slots.some(e=>!Number.isInteger(e)||e<0||e>31)||new Set(n.slots).size!==n.slots.length)throw Error(`Invalid replay order`);e=n.tick}}let r=t.initial.tick;for(let e of t.checkpoints){if(!Number.isInteger(e.tick)||e.tick<=r||e.tick>t.end||e.state.tick!==e.tick||typeof e.hash!=`string`)throw Error(`Invalid checkpoint`);r=e.tick}return t}var Vn=e=>Number.isSafeInteger(e)&&e>0&&e<=9e4,Hn=class{io;state=`admitted`;currentEpoch=0;membershipDeadline;recoveryDeadline=1/0;phaseDeadline=1/0;attemptId;retry=0;timer;timerVersion=0;transport;constructor(e,t){if(this.io=e,!Vn(t))throw RangeError(`Invalid membership duration`);this.membershipDeadline=e.now()+t,this.arm()}get epoch(){return this.currentEpoch}get status(){return this.state}disconnected(e){e!==this.currentEpoch||this.terminal()||this.checkExpiry()||(this.state===`admitted`?(this.recoveryDeadline=Math.min(this.io.now()+3e4,this.membershipDeadline),this.attemptId=this.io.newAttemptId(),this.retry=0,this.wait()):(this.state===`connecting`||this.state===`awaiting-ack`)&&this.wait())}acknowledge(e,t){if(e!==this.currentEpoch||this.state!==`awaiting-ack`||t!==void 0&&!Vn(t)||this.checkExpiry()||this.checkAttemptTimeout())return!1;t!==void 0&&(this.membershipDeadline=Math.min(this.membershipDeadline,this.io.now()+t));let n={attemptId:this.attemptId,epoch:e};return this.state=`admitted`,this.recoveryDeadline=1/0,this.phaseDeadline=1/0,this.attemptId=void 0,this.retry=0,this.arm(),this.io.onRecovered(n),!0}heartbeat(e,t){return e!==this.currentEpoch||this.state!==`admitted`||!Vn(t)||this.checkExpiry()?!1:(this.membershipDeadline=this.io.now()+t,this.arm(),!0)}cancel(){this.terminal()||(this.state=`cancelled`,this.clearTimer(),this.retire())}terminal(){return this.state===`expired`||this.state===`cancelled`}retire(){let e=this.transport;this.transport=void 0;try{e?.close()}catch{}}clearTimer(){this.timerVersion++,this.timer!==void 0&&this.io.clearTimer(this.timer),this.timer=void 0}checkExpiry(){if(this.terminal())return!0;let e=this.io.now(),t=e>=this.membershipDeadline;return!t&&e<this.recoveryDeadline?!1:(this.state=`expired`,this.clearTimer(),this.retire(),this.io.onExpired(t?`membership`:`recovery`),!0)}checkAttemptTimeout(){return(this.state===`connecting`||this.state===`awaiting-ack`)&&this.io.now()>=this.phaseDeadline&&(this.wait(),!0)}wait(){this.state=`waiting`,this.retire();let e=this.io.random(),t=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.5,n=Math.min(4e3,250*2**Math.min(this.retry++,4));this.phaseDeadline=this.io.now()+n*(.75+t*.25),this.arm()}arm(){if(this.clearTimer(),this.terminal())return;let e=this.timerVersion,t=Math.min(this.membershipDeadline,this.recoveryDeadline,this.phaseDeadline);this.timer=this.io.setTimer(()=>{if(!(e!==this.timerVersion||this.checkExpiry())){if(this.timer=void 0,this.io.now()<this.phaseDeadline){this.arm();return}this.state===`waiting`?this.attempt():this.state===`connecting`||this.state===`awaiting-ack`?this.wait():this.arm()}},Math.max(0,t-this.io.now()))}attempt(){if(this.checkExpiry())return;this.state=`connecting`;let e=++this.currentEpoch;this.phaseDeadline=this.io.now()+5e3,this.arm();let t;try{t=this.io.createAttempt({attemptId:this.attemptId,epoch:e},{opened:()=>{e!==this.currentEpoch||this.state!==`connecting`||this.checkExpiry()||this.checkAttemptTimeout()||(this.state=`awaiting-ack`)},closed:()=>this.disconnected(e)})}catch{e===this.currentEpoch&&this.disconnected(e);return}if(e===this.currentEpoch&&(this.state===`connecting`||this.state===`awaiting-ack`||this.state===`admitted`))this.transport=t;else try{t.close()}catch{}}};function Un(e,t){return typeof e==`object`&&!!e&&!Array.isArray(e)&&Object.keys(e).length===t.length&&t.every(t=>Object.hasOwn(e,t))}var Wn=e=>typeof e==`string`&&/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(e),Gn=e=>typeof e==`string`&&/^[0-9a-f]{64}$/.test(e),Kn=(e,t)=>Number.isSafeInteger(e)&&e>=t,qn=e=>Kn(e,1)&&e<=9e4,Jn=e=>e===`host`||e===`guest`;function Yn(e){return!Un(e,[`version`,`roomGeneration`,`secret`,`connectionEpoch`,`membershipValidForMs`])||e.version!==2||!Wn(e.roomGeneration)||!Gn(e.secret)||!Kn(e.connectionEpoch,1)||!qn(e.membershipValidForMs)?null:{version:2,roomGeneration:e.roomGeneration,secret:e.secret,connectionEpoch:e.connectionEpoch,membershipValidForMs:e.membershipValidForMs}}function Xn(e){if(!Un(e,[`type`,`version`,`roomGeneration`,`attemptId`,`id`,`hostId`,`role`,`connectionEpoch`,`membershipValidForMs`,`rosterRevision`,`members`,`requireVerification`,`locked`])||e.type!==`resumed`||e.version!==2||!Wn(e.roomGeneration)||!Wn(e.attemptId)||!Wn(e.id)||!Wn(e.hostId)||!Jn(e.role)||!Kn(e.connectionEpoch,1)||!qn(e.membershipValidForMs)||!Kn(e.rosterRevision,0)||typeof e.requireVerification!=`boolean`||typeof e.locked!=`boolean`||!Array.isArray(e.members)||e.members.length<1||e.members.length>33)return null;let t=Qn(e.members,e.hostId);return!t||!t.some(t=>t.id===e.id&&t.role===e.role&&t.attached&&t.connectionEpoch===e.connectionEpoch)?null:{type:`resumed`,version:2,roomGeneration:e.roomGeneration,attemptId:e.attemptId,id:e.id,hostId:e.hostId,role:e.role,connectionEpoch:e.connectionEpoch,membershipValidForMs:e.membershipValidForMs,rosterRevision:e.rosterRevision,members:t,requireVerification:e.requireVerification,locked:e.locked}}function Zn(e){if(!Un(e,[`type`,`id`,`hostId`,`role`,`resumeGrant`,`rosterRevision`,`members`,`requireVerification`,`locked`])||e.type!==`ready`)return null;let t=Yn(e.resumeGrant);if(!t)return null;let n=Xn({type:`resumed`,version:2,roomGeneration:t.roomGeneration,attemptId:t.roomGeneration,id:e.id,hostId:e.hostId,role:e.role,connectionEpoch:t.connectionEpoch,membershipValidForMs:t.membershipValidForMs,rosterRevision:e.rosterRevision,members:e.members,requireVerification:e.requireVerification,locked:e.locked});return n?{type:`ready`,id:n.id,hostId:n.hostId,role:n.role,resumeGrant:t,rosterRevision:n.rosterRevision,members:n.members,requireVerification:n.requireVerification,locked:n.locked}:null}function Qn(e,t){if(!Array.isArray(e)||e.length<1||e.length>33)return null;let n=[],r=new Set;for(let t of e){if(!Un(t,[`id`,`role`,`attached`,`connectionEpoch`])||!Wn(t.id)||!Jn(t.role)||typeof t.attached!=`boolean`||!Kn(t.connectionEpoch,1)||r.has(t.id))return null;r.add(t.id),n.push({id:t.id,role:t.role,attached:t.attached,connectionEpoch:t.connectionEpoch})}let i=n.filter(e=>e.role===`host`);return i.length===1&&i[0].id===t?n:null}function $n(e){if(!Un(e,[`type`,`roomGeneration`,`hostId`,`rosterRevision`,`members`])||e.type!==`roster`||!Wn(e.roomGeneration)||!Wn(e.hostId)||!Kn(e.rosterRevision,0))return null;let t=Qn(e.members,e.hostId);return t?{type:`roster`,roomGeneration:e.roomGeneration,hostId:e.hostId,rosterRevision:e.rosterRevision,members:t}:null}function er(e){let t=[...e],n=new Set(t.filter(e=>e.type===`transport`&&e.selectedCandidatePairId).map(e=>e.selectedCandidatePairId)),r=t.filter(e=>e.type===`candidate-pair`&&e.state===`succeeded`),i=n.size?r.filter(e=>n.has(e.id)):r.filter(e=>e.nominated===!0);if(i.length!==1)return null;let a=i[0].currentRoundTripTime;return typeof a==`number`&&Number.isFinite(a)&&a>=0?a*1e3:null}var tr=524288,nr=16384,rr=12;function ir(e,t){let n=JSON.stringify(e);if(n===void 0)throw Error(`Missing control message`);let r=new TextEncoder().encode(n);if(r.length>tr)throw Error(`Control message exceeds 512 KB`);if(r.length<=nr)return[n];let i=Math.ceil(r.length/nr),a=[];for(let e=0;e<i;e++){let n=r.subarray(e*nr,(e+1)*nr),o=new ArrayBuffer(rr+n.length),s=new DataView(o);s.setUint16(0,45635),s.setUint8(2,1),s.setUint32(4,t,!0),s.setUint16(8,e,!0),s.setUint16(10,i,!0),new Uint8Array(o,rr).set(n),a.push(o)}return a}var ar=class{partial;push(e,t=performance.now()){if(typeof e==`string`){if(this.partial||new TextEncoder().encode(e).length>nr)throw Error(`Invalid control message`);return JSON.parse(e)}if(e.byteLength<13||e.byteLength>16396)throw Error(`Control fragment length`);let n=new DataView(e);if(n.getUint16(0)!==45635||n.getUint8(2)!==1||n.getUint8(3)!==0)throw Error(`Control fragment version`);let r=n.getUint32(4,!0),i=n.getUint16(8,!0),a=n.getUint16(10,!0);if(a<2||a>32||i>=a)throw Error(`Control fragment bounds`);if(!this.partial){if(i!==0)throw Error(`Missing first fragment`);this.partial={id:r,count:a,next:0,bytes:0,parts:[],since:t}}let o=this.partial;if(o.id!==r||o.count!==a||o.next!==i||t-o.since>1e4)throw Error(`Control fragment sequence`);if(o.next++,o.bytes+=e.byteLength-rr,o.bytes>tr)throw Error(`Control size limit`);if(o.parts.push(new Uint8Array(e.slice(rr))),o.next!==a)return;let s=new Uint8Array(o.bytes),c=0;for(let e of o.parts)s.set(e,c),c+=e.length;return this.partial=void 0,JSON.parse(new TextDecoder(`utf-8`,{fatal:!0}).decode(s))}},or=class extends Error{},sr=1,cr=e=>typeof e==`string`&&/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/.test(e),lr=e=>Number.isSafeInteger(e)&&e>0,ur=e=>e?.match(/(?:^|\r?\n)a=ice-ufrag:([^\s]+)/)?.[1],dr=e=>e.usernameFragment??e.candidate?.match(/(?:^| )ufrag ([^ ]+)/)?.[1],fr=class{room;credentials;hooks;runtime;ws;peers=new Map;id=``;host=!1;hostId=``;closed=!1;timer;bytesSent=0;bytesReceived=0;pollingStats=!1;resumeGrant;recovery;resumeAttempt;socketSerial=0;requestSentAt=0;rosterRevision=-1;members=new Map;lockedState=null;get locked(){return this.lockedState}heartbeatSequence=0;heartbeatRequest;heartbeatTimer;heartbeatTimerVersion=0;heartbeatDeadline=0;cancelHeartbeat(){clearTimeout(this.heartbeatTimer),this.heartbeatTimer=void 0,this.heartbeatTimerVersion++,this.heartbeatRequest=void 0}armHeartbeat(e){clearTimeout(this.heartbeatTimer);let t=++this.heartbeatTimerVersion;this.heartbeatTimer=setTimeout(()=>{t===this.heartbeatTimerVersion&&(this.heartbeatTimer=void 0,this.sendHeartbeat())},e)}scheduleHeartbeat(e,t){this.cancelHeartbeat();let n=performance.now()+e;this.heartbeatDeadline=t?n:Math.min(this.heartbeatDeadline,n);let r=this.heartbeatDeadline-performance.now();r>0&&this.signalingReady&&this.armHeartbeat(Math.max(1,Math.floor(Math.min(3e4,r/3))))}sendHeartbeat(){let e=this.heartbeatDeadline-performance.now();if(!this.signalingReady||!this.resumeGrant||!this.recovery||e<=0)return;let t=this.heartbeatRequest??={id:++this.heartbeatSequence,sentAt:performance.now(),localEpoch:this.recovery.epoch,transmissions:0,retryDelay:Math.max(1,Math.floor(Math.min(5e3,e/3)))};if(!(t.transmissions>=3)){t.transmissions++;try{this.signal({type:`heartbeat`,requestId:t.id,connectionEpoch:this.resumeGrant.connectionEpoch})}catch{}this.heartbeatRequest===t&&this.signalingReady&&t.transmissions<3&&t.retryDelay<e&&this.armHeartbeat(t.retryDelay)}}get signalingReady(){return!this.closed&&!!this.id&&this.ws.readyState===sr&&this.signalingAdmitted}get signalingAdmitted(){return!this.recovery||this.recovery.status===`admitted`}verificationState=null;get requireVerification(){return this.verificationState}verificationSequence=0;verificationRequest;challenge;rejectVerification(e,t=!0){let n=this.verificationRequest;n&&(this.verificationRequest=void 0,clearTimeout(n.timer),t&&(this.verificationState=null),n.reject(Error(e)))}setRequireVerification(e){return typeof e==`boolean`?this.closed||!this.host||!this.signalingAdmitted||this.ws.readyState!==sr?Promise.reject(Error(`An active room-owner connection is required.`)):this.verificationRequest?Promise.reject(Error(`A verification update is already pending.`)):new Promise((t,n)=>{let r=++this.verificationSequence,i=setTimeout(()=>this.rejectVerification(`Verification update was not confirmed.`),1e4);this.verificationRequest={id:r,timer:i,resolve:t,reject:n};try{this.signal({type:`setVerification`,required:e,requestId:r})}catch{this.rejectVerification(`Verification update could not be sent.`)}}):Promise.reject(Error(`Expected a boolean.`))}passwordRequestId=0;passwordRequest;rejectPasswordUpdate(e){let t=this.passwordRequest;t&&(this.passwordRequest=void 0,clearTimeout(t.timer),t.reject(Error(e)))}setPassword(e){return e!==null&&(typeof e!=`string`||e.length>64)?Promise.reject(Error(`Password must contain at most 64 characters.`)):this.closed||!this.host||!this.signalingAdmitted||this.ws.readyState!==sr?Promise.reject(Error(`An active room-owner connection is required.`)):this.passwordRequest?Promise.reject(Error(`A password update is already pending.`)):new Promise((t,n)=>{let r=++this.passwordRequestId,i=setTimeout(()=>this.rejectPasswordUpdate(`Password update was not confirmed.`),1e4);this.passwordRequest={id:r,timer:i,resolve:t,reject:n};try{this.signal({type:`setPassword`,requestId:r,password:e??``})}catch{this.rejectPasswordUpdate(`Password update could not be sent.`)}})}banSequence=0;banRequest;rejectBan(e,t=!0){let n=this.banRequest;n&&(this.banRequest=void 0,clearTimeout(n.timer),n.reject(t?new or(e):Error(e)))}updateBan(e,t){return this.closed||!this.host||!this.signalingAdmitted||this.ws.readyState!==sr?Promise.reject(Error(`An active room-owner connection is required.`)):this.banRequest?Promise.reject(Error(`A ban operation is already pending.`)):new Promise((n,r)=>{let i=++this.banSequence,a=setTimeout(()=>this.rejectBan(`Ban operation was not confirmed.`),1e4);this.banRequest={id:i,resolve:n,reject:r,timer:a};try{this.signal({type:e,id:t,requestId:i})}catch{this.rejectBan(`Ban operation could not be sent.`)}})}get rtt(){let e=[...this.peers.values()].filter(e=>e.connected&&e.lostAt===void 0).map(e=>e.rtt).filter(e=>typeof e==`number`);return e.length?Math.max(...e):null}signalQueue=Promise.resolve();lastHeartbeat=0;controlId=0;controlAssemblers=new Map;constructor(e,t,n,r=yn()){this.room=e,this.credentials=t,this.hooks=n,this.runtime=r;let i=new URL(`/api/rooms/${encodeURIComponent(e)}/signal`,vn(r.serviceOrigin));i.protocol=i.protocol===`https:`?`wss:`:`ws:`,this.ws=r.createWebSocket(i),this.attachSocket(this.ws,()=>{this.requestSentAt=performance.now(),this.signal({type:`hello`,...t,...r.signalingResume?{signalingVersion:2}:{}})},0),this.timer=setInterval(()=>{!this.resumeGrant&&this.signalingAdmitted&&this.ws.readyState===sr&&performance.now()-this.lastHeartbeat>=3e4&&(this.signal({type:`heartbeat`}),this.lastHeartbeat=performance.now());for(let e of this.peers.values()){if(!e.connected&&performance.now()-e.created>2e4){n.status(`Direct connection failed. This network pair may require a relay; this game does not use TURN.`),this.remove(e.id);continue}e.lostAt!==void 0&&(performance.now()-e.lostAt>2e4?(n.status(`The direct connection could not be recovered. Rejoin the room.`),this.remove(e.id)):this.host&&performance.now()-e.lastRestart>5e3&&this.restartPeer(e.id))}},5e3)}attachSocket(e,t,n){let r=++this.socketSerial,i=()=>!this.closed&&this.ws===e&&this.socketSerial===r;e.onopen=()=>{i()&&t()},e.onmessage=e=>{i()&&(this.signalQueue=this.signalQueue.then(async()=>{i()&&await this.message(JSON.parse(e.data),r)}).catch(()=>{i()&&this.hooks.status(`Connection negotiation failed. Try another room or network.`)}))},e.onclose=e=>{if(i()){if(this.socketSerial++,this.challenge?.abort(),this.cancelHeartbeat(),this.rejectVerification(`Signaling disconnected before verification confirmation.`),this.rejectBan(`Signaling disconnected before ban confirmation.`),this.rejectPasswordUpdate(`Signaling disconnected before password confirmation.`),this.recovery&&this.resumeGrant&&![1e3,1008,1009].includes(e.code)){this.recovery.disconnected(n),this.hooks.status(`Signaling interrupted. Reconnecting…`);return}if(!this.id||this.recovery||[1001,1008,1009].includes(e.code)){this.close(),this.hooks.ended?.(e.reason||`Room connection ended.`);return}this.hooks.status(e.reason||`Signaling disconnected. Established matches can continue; new joins are unavailable.`)}},e.onerror=()=>{i()&&this.hooks.status(`Room service is unavailable.`)}}startRecovery(e){let t=Math.floor(e.membershipValidForMs-(performance.now()-this.requestSentAt));if(t<=0){this.close(),this.hooks.ended?.(`Room membership expired.`);return}this.resumeGrant=e,this.recovery=new Hn({now:()=>performance.now(),setTimer:(e,t)=>setTimeout(e,t),clearTimer:e=>clearTimeout(e),random:()=>Math.random(),newAttemptId:()=>crypto.randomUUID(),createAttempt:(e,t)=>{this.resumeAttempt=e;let n=new URL(`/api/rooms/${encodeURIComponent(this.room)}/signal`,vn(this.runtime.serviceOrigin));n.protocol=n.protocol===`https:`?`wss:`:`ws:`;let r=this.runtime.createWebSocket(n);return this.ws=r,this.attachSocket(r,()=>{t.opened(),this.recovery?.status===`awaiting-ack`&&(this.requestSentAt=performance.now(),r.send(JSON.stringify({type:`resume`,version:2,roomGeneration:this.resumeGrant.roomGeneration,peerId:this.id,secret:this.resumeGrant.secret,attemptId:e.attemptId,expectedEpoch:this.resumeGrant.connectionEpoch})))},e.epoch),{close:()=>{this.ws===r&&this.socketSerial++,r.onopen=null,r.onmessage=null,r.onclose=null,r.onerror=null,r.close()}}},onExpired:()=>{this.close(),this.hooks.ended?.(`Room signaling recovery expired.`)},onRecovered:()=>{}},t),this.scheduleHeartbeat(t,!0)}signal(e){!this.closed&&this.signalingAdmitted&&this.ws.readyState===sr&&this.ws.send(JSON.stringify(e))}async message(e,t=this.socketSerial){if(this.closed||t!==this.socketSerial)return;if(e.type===`resumed`){let n=Xn(e),r=this.resumeGrant,i=this.resumeAttempt;if(!n||!r||!i||!this.recovery||n.roomGeneration!==r.roomGeneration||n.attemptId!==i.attemptId||n.id!==this.id||n.hostId!==this.hostId||n.role===`host`!==this.host||n.connectionEpoch<=r.connectionEpoch||n.rosterRevision<this.rosterRevision||n.members.some(e=>e.connectionEpoch<(this.members.get(e.id)?.connectionEpoch??0)))return;let a=Math.floor(n.membershipValidForMs-(performance.now()-this.requestSentAt));if(a<=0||!this.recovery.acknowledge(i.epoch,a))return;this.resumeGrant={...r,connectionEpoch:n.connectionEpoch,membershipValidForMs:a},this.resumeAttempt=void 0,this.scheduleHeartbeat(a,!1),this.verificationState=n.requireVerification,this.lockedState=n.locked,this.reconcile(n.members,n.rosterRevision,t),this.hooks.status(`Room signaling restored.`);return}if(e.type===`heartbeat`&&this.resumeGrant&&this.recovery){let t=this.heartbeatRequest;if(!t||e.requestId!==t.id||e.connectionEpoch!==this.resumeGrant.connectionEpoch||!Number.isSafeInteger(e.membershipValidForMs)||e.membershipValidForMs<1||e.membershipValidForMs>9e4)return;let n=Math.floor(e.membershipValidForMs-(performance.now()-t.sentAt));n>0&&this.recovery.heartbeat(t.localEpoch,n)&&this.scheduleHeartbeat(n,!0);return}if(this.recovery&&!this.signalingAdmitted)return;if(e.type===`roster`&&this.resumeGrant){let n=$n(e);if(!n||n.roomGeneration!==this.resumeGrant.roomGeneration||n.hostId!==this.hostId||n.rosterRevision<=this.rosterRevision)return;let r=n.members.find(e=>e.id===this.id);if(!r||!r.attached||r.connectionEpoch!==this.resumeGrant.connectionEpoch||r.role===`host`!==this.host){this.close(),this.hooks.ended?.(`Room membership ended.`);return}if(n.members.some(e=>e.connectionEpoch<(this.members.get(e.id)?.connectionEpoch??0)))return;this.reconcile(n.members,n.rosterRevision,t);return}if(e.type===`verificationUpdated`&&this.verificationRequest&&this.verificationRequest.id===e.requestId){if(e.ok!==!0||typeof e.required!=`boolean`)this.rejectVerification(typeof e.error==`string`?e.error:`Verification update failed.`,e.ok!==!1);else{let t=this.verificationRequest;this.verificationRequest=void 0,clearTimeout(t.timer),this.verificationState=e.required,t.resolve(e.required)}return}if(e.type===`verificationRequired`){if(this.closed||this.id||this.credentials.hostToken||this.challenge||e.roomId!==this.room||typeof e.siteKey!=`string`||!/^[A-Za-z0-9_-]{1,100}$/.test(e.siteKey))return;if(!this.hooks.verify){this.close(),this.hooks.ended?.(`This client cannot complete the room verification challenge.`);return}let t=new AbortController;this.challenge=t;try{let n=await this.hooks.verify({siteKey:e.siteKey,roomId:this.room},t.signal);if(t.signal.aborted||this.closed||this.ws.readyState!==sr)return;if(typeof n!=`string`||n.length===0||n.length>2048)throw Error(`Invalid verification response.`);this.requestSentAt=performance.now(),this.signal({type:`hello`,...this.credentials,verificationToken:n,...this.runtime.signalingResume?{signalingVersion:2}:{}})}catch(e){this.closed||(this.close(),this.hooks.ended?.(e instanceof Error?e.message:`Room verification failed.`))}finally{this.challenge===t&&(this.challenge=void 0)}return}if(e.type===`passwordUpgradeRequired`&&this.host){this.hooks.status(`Update the room password or explicitly unlock it to allow new guests.`);return}if(e.type===`passwordUpdated`&&e.ok===!1&&this.passwordRequest?.id===e.requestId){this.rejectPasswordUpdate(typeof e.error==`string`?e.error:`Password update failed.`);return}if(e.type===`passwordUpdated`&&typeof e.locked==`boolean`&&this.passwordRequest&&this.passwordRequest.id===e.requestId){let t=this.passwordRequest;this.passwordRequest=void 0,clearTimeout(t.timer),t.resolve(e.locked);return}if(e.type===`banResult`&&this.banRequest&&this.banRequest.id===e.requestId){if(e.ok!==!0)this.rejectBan(typeof e.error==`string`?e.error:`Ban operation failed.`,!1);else{let e=this.banRequest;this.banRequest=void 0,clearTimeout(e.timer),e.resolve()}return}if(e.type===`ready`){if(this.id)return;if(this.runtime.signalingResume&&e.resumeGrant!==void 0){let t=Zn(e);if(!t){this.close(),this.hooks.ended?.(`Invalid room admission.`);return}if(this.id=t.id,this.host=t.role===`host`,this.hostId=t.hostId,this.verificationState=t.requireVerification,this.lockedState=t.locked,this.startRecovery(t.resumeGrant),this.closed)return;this.members=new Map(t.members.map(e=>[e.id,e])),this.rosterRevision=t.rosterRevision}else this.id=e.id,this.host=e.role===`host`,this.hostId=e.hostId,this.verificationState=typeof e.requireVerification==`boolean`?e.requireVerification:null;this.hooks.ready(this.id,this.host),this.resumeGrant&&this.reconcile([...this.members.values()],this.rosterRevision,t);return}if(e.type===`peer`||e.type===`leave`){if(this.resumeGrant){if(!cr(e.id)||!lr(e.connectionEpoch)||!Number.isSafeInteger(e.rosterRevision)||e.rosterRevision<=this.rosterRevision||e.id===this.id)return;let t=this.members.get(e.id);if(t&&e.connectionEpoch<t.connectionEpoch)return;this.rosterRevision=e.rosterRevision,e.type===`peer`?this.members.set(e.id,{id:e.id,role:e.id===this.hostId?`host`:`guest`,attached:!0,connectionEpoch:e.connectionEpoch}):this.members.delete(e.id)}if(e.type===`leave`){this.remove(e.id,!1);return}this.host&&!this.peers.has(e.id)&&await this.offerPeer(e.id,t);return}if(e.type!==`signal`||this.resumeGrant&&(!cr(e.negotiationId)||e.toConnectionEpoch!==this.resumeGrant.connectionEpoch||e.fromConnectionEpoch!==this.members.get(e.from)?.connectionEpoch||!this.members.get(e.from)?.attached))return;let n=this.peers.get(e.from);if(!n){if(this.host||e.from!==this.hostId||![`offer`,`candidate`].includes(e.signal.type))return;n=this.make(e.from)}if(this.resumeGrant){if(e.signal.type===`offer`){if(this.host||!ur(e.signal.sdp))return;n.negotiationId!==e.negotiationId&&(n.candidates=[]),this.beginNegotiation(n,e.negotiationId),n.remoteIceUfrag=ur(e.signal.sdp),n.localIceUfrag=void 0}else if(e.signal.type===`candidate`&&!n.negotiationId&&!this.host)this.beginNegotiation(n,e.negotiationId);else if(n.negotiationId!==e.negotiationId)return;if(n.negotiationLocalEpoch!==e.toConnectionEpoch||n.negotiationRemoteEpoch!==e.fromConnectionEpoch)return;if(e.signal.type===`answer`){if(!ur(e.signal.sdp))return;n.remoteIceUfrag=ur(e.signal.sdp)}}let r=n.negotiationId,i=()=>this.current(n)&&t===this.socketSerial&&this.signalingAdmitted&&n.negotiationId===r&&this.negotiationCurrent(n);if(e.signal.type===`offer`){if(this.host)throw Error(`Only the host can offer`);if(await n.pc.setRemoteDescription({type:`offer`,sdp:e.signal.sdp}),!i()||(await this.flushCandidates(n,i),!i()))return;let t=await n.pc.createAnswer();if(!i()||(n.localIceUfrag=ur(t.sdp),await n.pc.setLocalDescription(t),!i()))return;this.peerSignal(n,{type:`answer`,sdp:n.pc.localDescription.sdp})}else if(e.signal.type===`answer`){if(!this.host)throw Error(`Only guests can answer`);if(await n.pc.setRemoteDescription({type:`answer`,sdp:e.signal.sdp}),!i())return;await this.flushCandidates(n,i),this.noteHealthy(n)}else if(e.signal.type===`candidate`&&e.signal.candidate){if(this.resumeGrant&&(!dr(e.signal.candidate)||n.remoteIceUfrag&&dr(e.signal.candidate)!==n.remoteIceUfrag))return;if(!n.pc.remoteDescription)this.queueCandidate(n,e.signal.candidate);else try{await n.pc.addIceCandidate(e.signal.candidate)}catch{i()&&this.queueCandidate(n,e.signal.candidate)}}}reconcile(e,t,n){this.members=new Map(e.map(e=>[e.id,e])),this.rosterRevision=t;for(let e of[...this.peers.keys()])this.members.has(e)||this.remove(e,!1);if(this.host)for(let t of e)t.id!==this.id&&t.attached&&!this.peers.has(t.id)&&this.offerPeer(t.id,n).catch(()=>{!this.closed&&n===this.socketSerial&&this.hooks.status(`Connection negotiation failed.`)})}negotiationCurrent(e){return!this.resumeGrant||e.negotiationLocalEpoch===this.resumeGrant.connectionEpoch&&e.negotiationRemoteEpoch===this.members.get(e.id)?.connectionEpoch&&this.members.get(e.id)?.attached===!0}beginNegotiation(e,t){e.negotiationId=t,e.negotiationLocalEpoch=this.resumeGrant?.connectionEpoch,e.negotiationRemoteEpoch=this.members.get(e.id)?.connectionEpoch}peerSignal(e,t){let n=this.resumeGrant,r=this.members.get(e.id);(!n||r?.attached&&e.negotiationId&&this.signalingAdmitted&&e.negotiationLocalEpoch===n.connectionEpoch&&e.negotiationRemoteEpoch===r.connectionEpoch)&&this.signal({type:`signal`,to:e.id,signal:t,...n?{fromConnectionEpoch:n.connectionEpoch,toConnectionEpoch:r.connectionEpoch,negotiationId:e.negotiationId}:{}})}async offerPeer(e,t){let n=this.make(e);this.bind(n,n.pc.createDataChannel(`control`,{ordered:!0})),this.bind(n,n.pc.createDataChannel(`realtime`,{ordered:!1,maxRetransmits:0})),this.resumeGrant&&this.beginNegotiation(n,crypto.randomUUID());let r=n.negotiationId,i=()=>this.current(n)&&t===this.socketSerial&&this.signalingAdmitted&&n.negotiationId===r&&this.negotiationCurrent(n),a=await n.pc.createOffer();i()&&(n.localIceUfrag=ur(a.sdp),await n.pc.setLocalDescription(a),i()&&this.peerSignal(n,{type:`offer`,sdp:n.pc.localDescription.sdp}))}current(e){return!this.closed&&this.peers.get(e.id)===e}queueCandidate(e,t){if(this.current(e)){if(e.candidates.length>=128)throw Error(`Too many pending ICE candidates`);e.candidates.push(t)}}noteHealthy(e){if(!this.current(e)||e.pc.connectionState!==`connected`||![`connected`,`completed`].includes(e.pc.iceConnectionState))return;let t=e.lostAt!==void 0;e.lostAt=void 0,e.restarts=0,t&&this.hooks.status(`Direct connection restored.`)}async flushCandidates(e,t=()=>this.current(e)){let n=e.candidates.splice(0);for(let r of n){if(!t())return;if(!this.resumeGrant||e.remoteIceUfrag&&dr(r)===e.remoteIceUfrag)try{await e.pc.addIceCandidate(r)}catch{}}}async restartPeer(e){let t=this.peers.get(e);if(this.closed||!this.host||!t||t.restarting||t.restarts>=2||t.pc.signalingState!==`stable`||!this.signalingAdmitted||this.ws.readyState!==sr)return!1;let n=this.socketSerial;this.resumeGrant&&(this.beginNegotiation(t,crypto.randomUUID()),t.localIceUfrag=void 0,t.remoteIceUfrag=void 0,t.candidates=[]);let r=t.negotiationId,i=()=>this.current(t)&&n===this.socketSerial&&this.signalingAdmitted&&t.negotiationId===r&&this.negotiationCurrent(t);t.restarting=!0,t.lastRestart=performance.now(),t.lostAt??=t.lastRestart,t.restarts++;try{let e=await t.pc.createOffer({iceRestart:!0});return!i()||(t.localIceUfrag=ur(e.sdp),await t.pc.setLocalDescription(e),!i())?!1:(this.peerSignal(t,{type:`offer`,sdp:t.pc.localDescription.sdp}),!0)}catch{return!this.closed&&this.peers.get(e)===t&&this.hooks.status(`Direct connection recovery is still pending.`),!1}finally{t.restarting=!1}}make(e){let t=this.runtime.createPeerConnection({iceServers:[{urls:`stun:stun.l.google.com:19302`}],bundlePolicy:`max-bundle`}),n={id:e,pc:t,connected:!1,created:performance.now(),candidates:[],lastRestart:0,restarts:0,restarting:!1};this.peers.set(e,n),t.onicecandidate=e=>{if(!this.current(n)||!e.candidate||!this.signalingAdmitted)return;let t=e.candidate.toJSON();(!this.resumeGrant||n.localIceUfrag&&dr(t)===n.localIceUfrag)&&this.peerSignal(n,{type:`candidate`,candidate:t})},t.ondatachannel=e=>this.bind(n,e.channel);let r=()=>{this.closed||this.peers.get(e)!==n||(t.connectionState===`closed`?(this.hooks.status(`A peer disconnected.`),this.remove(e)):t.connectionState===`connected`&&[`connected`,`completed`].includes(t.iceConnectionState)?this.noteHealthy(n):([`failed`,`disconnected`].includes(t.connectionState)||[`failed`,`disconnected`].includes(t.iceConnectionState))&&(n.lostAt??=performance.now(),this.hooks.status(`Direct connection interrupted. Attempting recovery…`)))};return t.onconnectionstatechange=r,t.oniceconnectionstatechange=r,n}bind(e,t){if(this.closed||this.peers.get(e.id)!==e||![`control`,`realtime`].includes(t.label)){t.close();return}if(t.maxPacketLifeTime!==null||t.label===`control`&&(t.ordered!==!0||t.maxRetransmits!==null)||t.label===`realtime`&&(t.ordered!==!1||t.maxRetransmits!==0)||(t.label===`control`?e.control:e.fast)){t.close(),this.remove(e.id);return}t.binaryType=`arraybuffer`,t.label===`control`?e.control=t:e.fast=t,t.onclose=()=>{!this.closed&&this.peers.get(e.id)===e&&(this.hooks.status(`A peer closed its game channel.`),this.remove(e.id))},t.onopen=()=>{this.closed||this.peers.get(e.id)!==e||e.control?.readyState===`open`&&e.fast?.readyState===`open`&&!e.connected&&(e.connected=!0,this.host&&(e.admissionTimer=setTimeout(()=>{this.closed||this.peers.get(e.id)!==e||(this.hooks.status(`A peer did not complete room admission.`),this.remove(e.id))},1e4)),this.hooks.open(e))},t.onmessage=n=>{if(!(this.closed||this.peers.get(e.id)!==e)){this.bytesReceived+=typeof n.data==`string`?n.data.length:n.data.byteLength;try{if(t.label===`control`){let t=typeof n.data!=`string`||new TextEncoder().encode(n.data).length>4096;if(this.host&&t&&!this.hooks.allowStadiumUpload?.(e))throw Error(`Guest control size or permission`);if(typeof n.data!=`string`&&!(n.data instanceof ArrayBuffer))throw Error(`Invalid control type`);let r=this.controlAssemblers.get(e.id);r||(r=new ar,this.controlAssemblers.set(e.id,r));let i=r.push(n.data);if(i!==void 0){if(this.host&&t&&(!i||typeof i!=`object`||i.type!==`action`||i.action!==`customStadium`))throw Error(`Invalid bulk action`);this.hooks.control(e,i)}}else if(n.data instanceof ArrayBuffer&&n.data.byteLength<=1200)this.hooks.fast(e,n.data);else throw Error()}catch{this.hooks.status(`Invalid peer message rejected.`),this.remove(e.id)}}}}admit(e){clearTimeout(e.admissionTimer),e.admissionTimer=void 0}control(e,t){if(e.control?.readyState!==`open`)return;let n=ir(t,this.controlId++),r=n.reduce((e,t)=>e+(typeof t==`string`?new TextEncoder().encode(t).length:t.byteLength),0);if(e.control.bufferedAmount+r>1048576){this.remove(e.id);return}for(let t of n)e.control.send(t);this.bytesSent+=r}fast(e,t){e.fast?.readyState===`open`&&e.fast.bufferedAmount<32768&&(e.fast.send(t),this.bytesSent+=t.byteLength)}broadcast(e){for(let t of this.peers.values())this.control(t,e)}async stats(){if(!(this.pollingStats||this.closed)){this.pollingStats=!0;try{await Promise.allSettled([...this.peers.values()].map(async e=>{if(!e.connected||e.lostAt!==void 0){e.rtt=null;return}try{let t=await e.pc.getStats();!this.closed&&this.peers.get(e.id)===e&&(e.rtt=er(t.values()))}catch{e.rtt=null}}))}finally{this.pollingStats=!1}}}remove(e,t=!0){let n=this.peers.get(e);n&&(clearTimeout(n.admissionTimer),this.peers.delete(e),this.controlAssemblers.delete(e),n.pc.close(),this.host&&t?this.signal({type:`evict`,id:e}):this.host||this.close(),this.hooks.leave(e),this.host||this.hooks.ended?.(`The host connection ended.`))}close(){if(!this.closed){this.resumeGrant&&this.signalingAdmitted&&this.ws.readyState===sr&&this.signal({type:`leave`,connectionEpoch:this.resumeGrant.connectionEpoch}),this.recovery?.cancel(),this.resumeGrant=void 0,this.resumeAttempt=void 0,this.cancelHeartbeat(),this.socketSerial++,this.challenge?.abort(),this.rejectVerification(`Room closed before verification confirmation.`),this.verificationState=null,this.rejectBan(`Room closed before ban confirmation.`),this.rejectPasswordUpdate(`Room closed before password confirmation.`),this.closed=!0,clearInterval(this.timer),this.ws.close(1e3,`Left room`);for(let e of this.peers.values())clearTimeout(e.admissionTimer),e.pc.close();this.peers.clear(),this.controlAssemblers.clear()}}};function pr(e,t){return e!==t&&e-t>>>0<2147483648}function mr(e){if(e.byteLength!==14)throw Error(`Input length`);let t=new DataView(e);if(t.getUint8(0)!==1||t.getUint8(1)!==5||t.getUint8(6)>31||t.getUint8(7))throw Error(`Input format`);return{seq:t.getUint32(2,!0),keys:t.getUint8(6),time:t.getUint32(8,!0),epoch:t.getUint16(12,!0)}}function hr(e,t,n=0){if(e.surface?.length)throw Error(`Terrain transport is not enabled`);let r=[];for(let t=0;t<e.discs.length/18;t++){let n=t*18,i=e.discs,a=i[n+5]>0||i[n+2]!==0||i[n+3]!==0||i[n+8]!==0||i[n+9]!==0||i[n]!==i[n+16]||i[n+1]!==i[n+17];(i[n+12]>0?i[n+13]>0:a)&&r.push(t)}let i=[`lobby`,`playing`,`goal`,`finished`],a=new ArrayBuffer(36+r.length*24),o=new DataView(a);o.setUint32(0,e.tick,!0),o.setUint32(4,e.elapsed,!0),o.setUint16(8,e.red,!0),o.setUint16(10,e.blue,!0),o.setUint8(12,i.indexOf(e.phase)),o.setUint8(13,+e.paused),o.setUint8(14,e.kickoff),o.setUint8(15,+e.kickoffActive),o.setUint16(16,e.countdown,!0),o.setUint16(18,e.scoreLimit,!0),o.setUint16(20,e.timeLimit,!0),o.setUint16(22,e.discs.length/18,!0),o.setUint32(24,t,!0),o.setUint16(28,r.length,!0),o.setUint16(30,e.resumeTicks,!0),o.setUint32(32,e.kickRate,!0),r.forEach((t,n)=>{let r=t*18,i=36+n*24;o.setUint16(i,t,!0),o.setUint8(i+2,e.discs[r+13]),o.setUint8(i+3,e.discs[r+14]|(e.discs[r+12]>0?(e.discs[r+11]&24)<<2:0));for(let t=0;t<4;t++)o.setFloat32(i+4+t*4,e.discs[r+t],!0);o.setUint16(i+20,e.discs[r+15],!0),e.discs[r+12]>0&&o.setUint16(i+22,e.discs[r+17]+255,!0)});let s=new Uint8Array(a),c=[],l=Math.ceil(s.length/1188);for(let t=0;t<l;t++){let r=s.subarray(t*1188,(t+1)*1188),i=new ArrayBuffer(12+r.length),a=new DataView(i);a.setUint8(0,2),a.setUint8(1,5),a.setUint32(2,e.tick,!0),a.setUint8(6,t),a.setUint8(7,l),a.setUint16(8,n,!0),a.setUint16(10,r.length,!0),new Uint8Array(i,12).set(r),c.push(i)}return c}var gr=Object.freeze({...tn}),_r=class e{runtime;engine;network;roomId=``;roomLink=``;roomName=``;epoch=0;stadiumSelection=0;players=[];nextPlayerId=0;bans=new Map;loop;linkNotification;last=performance.now();accumulator=0;recorder;closed=!1;closeController=new AbortController;signal=this.closeController.signal;finishingRecording=!1;lastRecording=null;onRecordingComplete;locked=!1;teamStyles=[null,null];inputs=new Map;traffic=new wn;onRoomLink;onPlayerJoin;onPlayerTeamChange;onPlayerAdminChange;onGameStart;onGameStop;onTeamVictory;onGameVictory;onGamePauseChange;onGamePause;onGameUnpause;onPlayerLeave;onPlayerKicked;onPlayerActivity;onPlayerChat;onPlayerBallKick;onTeamGoal;onPositionsReset;onStadiumChange;onTeamsLockChange;onKickRateLimitSet;onGameTick;onError;report(e){try{let t=this.onError?.(e);t instanceof Promise&&t.catch(()=>{})}catch{}}invoke(e,t,...n){if(!(this.closed&&e!==`onRecordingComplete`))try{let r=t?.apply(this,n);return r instanceof Promise&&r.catch(t=>this.report(`${e}: ${String(t)}`)),r}catch(t){this.report(`${e}: ${String(t)}`);return}}constructor(e,t){this.runtime=t,this.engine=e}static async create(t,n=Sn(),r){let i=vn(n.network.serviceOrigin);if(t=ct(t),t.noPlayer!==void 0&&typeof t.noPlayer!=`boolean`)throw Error(`Invalid noPlayer setting`);let a=t.noPlayer===!1,o=t.playerName??`Host`;if(a&&(typeof o!=`string`||!o.trim()||o.length>24))throw Error(`Invalid host player name`);let s=ot(r),c;try{s.signal.throwIfAborted();let r=await s.run(n.loadEngine(s.signal));r.load(t.stadium??mn()),c=new e(r,n);let l=c,u=await s.run(n.request(new URL(`/api/rooms`,i),{signal:s.signal,method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({name:t.roomName,maxPlayers:t.maxPlayers??16,password:t.password??``,private:t.public===!1,hostPlayer:a})}));if(!u.ok)throw Error(`Room creation failed (${u.status})`);let d=await s.run(u.json());l.roomId=d.id,l.roomName=t.roomName,l.roomLink=`${i}${ut(d.id)}`;let f;try{await s.run(new Promise((e,t)=>{f=setTimeout(()=>t(Error(`Signaling timed out`)),12e3),l.network=new fr(d.id,{hostToken:d.hostToken},{ready:(n,r)=>{if(!r){t(Error(`Host authority was not granted`));return}a&&(l.players.push({id:l.nextPlayerId++,slot:0,peerId:n,name:o.trim(),team:0,admin:!0}),l.engine.joinPlayer(0)),clearTimeout(f),e()},allowStadiumUpload:e=>!!l.players.find(t=>t.peerId===e.id)?.admin&&[`lobby`,`finished`].includes(l.engine.phase)&&l.traffic.allow(e.id,`message`),open:()=>{},control:(e,t)=>l.control(e,t),fast:(e,t)=>l.fast(e,t),leave:e=>l.leave(e),status:e=>l.report(e),ended:e=>{clearTimeout(f),t(Error(e)),l.close(),l.report(e)}},n.network)}))}catch(e){throw l.close(),e}finally{clearTimeout(f)}if(l.closed)throw Error(`Room closed during startup`);l.last=performance.now(),l.loop=setInterval(()=>l.advance(),1e3/60);let p=l.roomLink;return l.linkNotification=setTimeout(()=>{l.linkNotification=void 0,l.invoke(`onRoomLink`,l.onRoomLink,p)},0),c}catch(e){throw c?.close(),e}finally{s.dispose()}}advance(){if(this.closed)return;let e=performance.now(),t=e-this.last;this.last=e,t>500&&this.engine.phase===`playing`&&!this.engine.paused&&(this.pauseGame(!0),this.report(`Host scheduler stalled; match paused.`)),this.accumulator+=Math.max(0,Math.min(t,500));let n=0;try{for(;!this.closed&&this.accumulator>=1e3/60&&n++<32;){for(let t of this.players){let n=this.inputs.get(t.peerId);n&&e-n.received>250&&this.engine.data[this.engine.index(t.slot)*18+14]&&this.command(`input`,t.slot,0)}if(this.recorder&&!this.recorder.canRecord(this.engine)&&this.finishRecording(`Recording limit reached`),this.closed||(this.engine.phase!==`lobby`&&!this.engine.paused&&!this.engine.resumeTicks&&this.invoke(`onGameTick`,this.onGameTick),this.closed))break;let t=this.engine.red,n=this.engine.blue,r=this.engine.phase;this.engine.step(),this.recorder?.step(this.engine),this.engine.phase!==r&&this.state();let i=r===`goal`&&this.engine.phase===`playing`;r===`finished`&&this.engine.phase===`lobby`&&this.invoke(`onGameStop`,this.onGameStop,null);let a=this.engine.ballKicks.map(e=>{let t=this.players.find(t=>t.slot===e);return t?this.playerCopy(t):null}).filter(e=>!!e),o=r!==`finished`&&this.engine.phase===`finished`?this.getScores():null;o&&(this.invoke(`onTeamVictory`,this.onTeamVictory,{...o}),this.invoke(`onGameVictory`,this.onGameVictory,{...o}));for(let e of a)this.invoke(`onPlayerBallKick`,this.onPlayerBallKick,e);if(this.engine.red>t&&this.invoke(`onTeamGoal`,this.onTeamGoal,1),this.engine.blue>n&&this.invoke(`onTeamGoal`,this.onTeamGoal,2),i&&this.invoke(`onPositionsReset`,this.onPositionsReset),this.closed)break;if(this.engine.tick%2==0){let e=this.engine.snapshot();if(e.surface?.length){if(this.engine.tick%6==0){let t=at(e,this.epoch);for(let e of this.network.peers.values())e.control?.readyState===`open`&&e.control.bufferedAmount<65536&&this.network.control(e,{...t,ack:this.inputs.get(e.id)?.seq??0})}}else for(let t of this.network.peers.values())for(let n of hr(e,this.inputs.get(t.id)?.seq??0,this.epoch))this.network.fast(t,n)}this.accumulator-=1e3/60}}catch(e){this.closed||(this.engine.setPaused(!0),this.report(String(e)))}}allowed(e){return this.traffic.allow(e.id,`message`)?!0:(this.network.remove(e.id),!1)}control(e,t){if(!this.allowed(e)||!t||typeof t!=`object`)return;let n=t,r=this.players.find(t=>t.peerId===e.id);if(n.type===`join`&&!r){if(n.version!==1||n.engine!==hn||typeof n.name!=`string`||!n.name.trim()||n.name.length>24){this.network.remove(e.id);return}let t=Array.from({length:32},(e,t)=>t).find(e=>!this.players.some(t=>t.slot===e));if(t===void 0){this.network.remove(e.id);return}r={id:this.nextPlayerId++,slot:t,peerId:e.id,name:n.name.trim(),team:0,admin:!1},this.players.push(r),this.network.admit(e),this.recorder?.player(this.engine.tick,r.slot,r.name),this.command(`join`,t,0),this.network.control(e,{type:`welcome`,epoch:this.epoch,roomName:this.roomName,engine:hn,slot:t,stadium:this.engine.source,state:this.engine.snapshot(),players:this.roster(),teamStyles:this.teamStyles,locked:this.locked}),this.sync(),this.invoke(`onPlayerJoin`,this.onPlayerJoin,this.playerCopy(r));return}if(r&&n.type===`action`){if(n.action===`chat`&&typeof n.text==`string`&&n.text.length<=200){if(!n.text.trim()||!this.traffic.allow(e.id,`chat`)||(this.invoke(`onPlayerActivity`,this.onPlayerActivity,this.playerCopy(r)),this.closed||!this.players.includes(r)))return;this.invoke(`onPlayerChat`,this.onPlayerChat,this.playerCopy(r),n.text)!==!1&&this.network.broadcast({type:`chat`,name:r.name,text:n.text})}if(n.action===`chat`||this.traffic.allow(e.id,`action`)){if(n.action===`avatar`&&ht(n.avatar)){r.avatar=n.avatar,this.recorder?.player(this.engine.tick,r.slot,r.name,r.avatarOverride??r.avatar),this.sync();return}if(n.action===`team`&&(!this.locked||r.admin)&&[0,1,2].includes(Number(n.team))){let e=n.slot===void 0?r:this.players.find(e=>e.slot===n.slot);e&&(e===r||r.admin)&&this.changeTeam(e.id,Number(n.team),r)}if(n.action===`defaultStadium`||n.action===`customStadium`){let t=t=>{!this.closed&&this.players.includes(r)&&this.network.control(e,{type:`stadiumResult`,text:t})};if(!r.admin||![`lobby`,`finished`].includes(this.engine.phase)){t(`Stadium change rejected: admin permission and a stopped match are required.`);return}if(n.action===`defaultStadium`?typeof n.name!=`string`:typeof n.source!=`string`)return;let i=++this.stadiumSelection;(n.action===`defaultStadium`?this.runtime.loadStadium(n.name):Promise.resolve(n.source)).then(e=>{if(!this.closed&&this.players.includes(r)){if(i!==this.stadiumSelection||!r.admin||![`lobby`,`finished`].includes(this.engine.phase)){t(`Stadium change cancelled: room state or permissions changed.`);return}this.changeStadium(e,this.playerCopy(r)),t(`Stadium applied.`)}}).catch(()=>t(`Stadium could not be loaded. Please try again.`));return}if(r.admin){if(n.action===`surface`&&typeof n.enabled==`boolean`&&[`lobby`,`finished`].includes(this.engine.phase)){this.setSurfaceEnabled(n.enabled);return}if(n.action===`ban`||n.action===`clearBans`){let t=this.players.find(e=>e.slot===n.slot);if(n.action===`ban`&&(!t||t===r||t.peerId===this.network.hostId))return;let i=t=>{!this.closed&&this.network.peers.has(e.id)&&this.network.control(e,{type:`moderationResult`,text:t})};if(n.action===`clearBans`){i(`Only the room owner can clear bans.`);return}this.banPlayer(t.id,`Removed by admin`,this.playerCopy(r)).then(()=>i(`Player banned.`)).catch(e=>i(e instanceof Error?e.message:`Moderation failed.`));return}if(n.action===`teamColors`&&(n.team===1||n.team===2)){let e=n.palette;this.changeTeamColors(n.team,e===null?null:dt(e.angle,e.textColor,e.colors))}if(n.action===`kickRate`&&Number.isInteger(n.value)&&Number(n.value)>=0&&Number(n.value)<=6619135){let e=Number(n.value);this.changeKickRateLimit(e&255,e>>>8&255,e>>>16,this.playerCopy(r))}if(n.action===`start`&&this.beginGame(r),n.action===`stop`&&this.endGame(r),n.action===`pause`&&(n.paused===void 0||typeof n.paused==`boolean`)&&this.changePause(n.paused===void 0?!this.engine.paused:n.paused,this.playerCopy(r)),n.action===`settings`&&[`lobby`,`finished`].includes(this.engine.phase)){let e=Number(n.score),t=Number(n.minutes);if(Number.isInteger(e)&&e>=0&&e<=99&&Number.isInteger(t)&&t>=0&&t<=99&&(n.kickRate===void 0||Number.isInteger(n.kickRate)&&Number(n.kickRate)>=0&&Number(n.kickRate)<=6619135)){if(this.setScoreLimit(e),this.setTimeLimit(t),this.changeTeamsLock(!!n.locked,this.playerCopy(r)),this.closed)return;if(n.kickRate!==void 0&&n.kickRate!==this.engine.kickRate){let e=Number(n.kickRate);this.changeKickRateLimit(e&255,e>>>8&255,e>>>16,this.playerCopy(r))}}}if(n.action===`kick`&&typeof n.slot==`number`&&n.slot!==r.slot){let e=this.players.find(e=>e.slot===n.slot);e&&this.removePlayer(e.id,`Removed by host`,this.playerCopy(r))}}}}}fast(e,t){if(!this.allowed(e))return;let n=this.players.find(t=>t.peerId===e.id);if(!n)return;let r=mr(t);if(r.epoch!==this.epoch)return;let i=this.inputs.get(e.id);(!i||pr(r.seq,i.seq))&&(this.inputs.set(e.id,{seq:r.seq,received:performance.now(),keys:r.keys}),this.command(`input`,n.slot,r.keys),r.keys!==(i?.keys??0)&&this.invoke(`onPlayerActivity`,this.onPlayerActivity,this.playerCopy(n)))}command(e,t=0,n=0){if(this.closed)throw Error(`Room is closed`);let r={tick:this.engine.tick,kind:e,slot:t,value:n};if(this.recorder&&(!this.recorder.canRecord(this.engine)||!this.recorder.command(r))&&this.finishRecording(`Recording limit reached`),this.closed)throw Error(`Room is closed`);Ln(this.engine,r)}roster(){return this.players.map(e=>({avatar:e.avatarOverride??e.avatar??null,id:e.peerId,slot:e.slot,name:e.name,team:e.team,admin:e.admin}))}sync(){this.network.broadcast({type:`lobby`,players:this.roster(),teamStyles:this.teamStyles,locked:this.locked,scoreLimit:this.engine.scoreLimit,timeLimit:this.engine.timeLimit})}state(){this.network.broadcast({type:`state`,epoch:this.epoch,state:this.engine.snapshot()})}leave(e){this.traffic.delete(e);let t=this.players.find(t=>t.peerId===e);t&&(this.recorder?.player(this.engine.tick,t.slot,null),this.command(`team`,t.slot,0),this.players=this.players.filter(t=>t.peerId!==e),this.inputs.delete(e),this.sync(),this.invoke(`onPlayerLeave`,this.onPlayerLeave,this.playerCopy(t)))}playerCopy(e){let t=this.engine.index(e.slot)*18,n=!this.closed&&this.engine.phase!==`lobby`&&this.engine.data[t+13]>0,{slot:r,avatarOverride:i,...a}=e;return{...a,avatar:e.avatarOverride??e.avatar??null,position:n?{x:this.engine.data[t],y:this.engine.data[t+1]}:null}}getPlayerList(){return this.players.map(e=>this.playerCopy(e))}getPlayer(e){let t=this.players.find(t=>t.id===e);return t?this.playerCopy(t):null}setTeamColors(e,t,n,r){this.changeTeamColors(e,dt(t,n,r))}changeTeamColors(e,t){if(this.closed)throw Error(`Room is closed`);if(e!==1&&e!==2)throw Error(`Invalid team`);JSON.stringify(this.teamStyles[e-1])!==JSON.stringify(t)&&(this.teamStyles[e-1]=t,this.recorder?.style(this.engine.tick,this.teamStyles),this.sync())}reorderPlayers(e,t){if(this.closed)throw Error(`Room is closed`);if(!Array.isArray(e)||e.length>32||e.some(e=>!Number.isSafeInteger(e)||e<0)||typeof t!=`boolean`)throw Error(`Invalid player order`);let n=new Set(e),r=[...n].flatMap(e=>{let t=this.players.find(t=>t.id===e);return t?[t]:[]}),i=this.players.filter(e=>!n.has(e.id)),a=t?[...r,...i]:[...i,...r];a.every((e,t)=>e===this.players[t])||(this.players=a,this.recorder?.order(this.engine.tick,a.map(e=>e.slot)),this.sync())}setPlayerAvatar(e,t){if(this.closed)throw Error(`Room is closed`);if(!ht(t))throw Error(`Avatar must be null or at most two visible characters.`);let n=this.players.find(t=>t.id===e);n&&(n.avatarOverride=t,this.recorder?.player(this.engine.tick,n.slot,n.name,t??n.avatar),this.sync())}setPlayerTeam(e,t){this.changeTeam(e,t,null)}changeTeam(e,t,n){if(this.closed)throw Error(`Room is closed`);if(![0,1,2].includes(t))throw Error(`Invalid team`);let r=this.players.find(t=>t.id===e);r&&r.team!==t&&(r.team=t,this.command(`team`,r.slot,t),this.sync(),this.invoke(`onPlayerTeamChange`,this.onPlayerTeamChange,this.playerCopy(r),n?this.playerCopy(n):null))}setPlayerAdmin(e,t){if(this.closed)throw Error(`Room is closed`);let n=this.players.find(t=>t.id===e);n&&n.admin!==!!t&&(n.admin=!!t,this.sync(),this.invoke(`onPlayerAdminChange`,this.onPlayerAdminChange,this.playerCopy(n),null))}setTeamsLock(e){this.changeTeamsLock(e,null)}changeTeamsLock(e,t){if(this.closed)throw Error(`Room is closed`);this.locked!==!!e&&(this.locked=!!e,this.sync(),this.invoke(`onTeamsLockChange`,this.onTeamsLockChange,this.locked,t))}kickPlayer(e,t=`Removed by host`,n=!1){if(this.closed)throw Error(`Room is closed`);if(typeof n!=`boolean`)throw Error(`Invalid ban flag`);if(n)return this.banPlayer(e,t);this.removePlayer(e,t,null)}async banPlayer(e,t,n=null){if(typeof t!=`string`)throw Error(`Invalid kick reason`);let r=this.players.find(t=>t.id===e);if(!r||r.peerId===this.network.hostId)return;let i=this.playerCopy(r),a=t.slice(0,100);if(this.bans.size>=256&&!this.bans.has(e))throw Error(`Clear existing bans before adding more.`);try{await this.network.updateBan(`ban`,r.peerId)}catch(t){throw t instanceof or&&this.bans.set(e,r.peerId),t}this.bans.set(e,r.peerId),this.network.remove(r.peerId),this.invoke(`onPlayerKicked`,this.onPlayerKicked,i,a,!0,n)}async clearBan(e){if(this.closed)throw Error(`Room is closed`);let t=this.bans.get(e);t&&(await this.network.updateBan(`clearBan`,t),this.bans.delete(e))}async clearBans(){if(this.closed)throw Error(`Room is closed`);await this.network.updateBan(`clearBans`),this.bans.clear()}removePlayer(e,t,n){if(this.closed)throw Error(`Room is closed`);if(typeof t!=`string`)throw Error(`Invalid kick reason`);let r=this.players.find(t=>t.id===e);if(r&&r.peerId!==this.network.hostId){let e=this.playerCopy(r),i=t.slice(0,100),a=this.network.peers.get(r.peerId);a&&this.network.control(a,{type:`kicked`,reason:i}),this.network.remove(r.peerId),this.players.includes(r)||this.invoke(`onPlayerKicked`,this.onPlayerKicked,e,i,!1,n)}}sendChat(e,t){if(this.closed)throw Error(`Room is closed`);if(typeof e!=`string`||e.length>200)throw Error(`Chat must contain at most 200 characters`);if(t!=null&&(!Number.isSafeInteger(t)||t<0))throw Error(`Invalid chat target`);let n=this.players.find(e=>e.peerId===this.network.hostId);if(!n)throw Error(`sendChat requires a host player; use sendAnnouncement`);if(!e.trim())return;let r={type:`chat`,name:n.name,text:e};if(t==null)this.network.broadcast(r);else{let e=this.players.find(e=>e.id===t),n=e&&this.network.peers.get(e.peerId);n&&this.network.control(n,r)}}sendAnnouncement(e,t,n,r,i){if(this.closed)throw Error(`Room is closed`);let a=mt(e,n,r,i);if(t!=null&&(!Number.isSafeInteger(t)||t<0))throw Error(`Invalid announcement target`);if(t==null)this.network.broadcast(a);else{let e=this.players.find(e=>e.id===t),n=e&&this.network.peers.get(e.peerId);n&&this.network.control(n,a)}}startGame(){this.beginGame(null)}beginGame(e){if(this.closed)throw Error(`Room is closed`);let t=this.engine.phase;(t===`lobby`||t===`finished`)&&(this.command(`start`),this.stadiumSelection++,this.state(),t!==this.engine.phase&&this.engine.phase===`playing`&&this.invoke(`onGameStart`,this.onGameStart,e?this.playerCopy(e):null))}stopGame(){this.endGame(null)}endGame(e){if(this.closed)throw Error(`Room is closed`);let t=this.engine.phase!==`lobby`;(t||this.engine.paused)&&(this.command(`stop`),this.state(),t&&this.invoke(`onGameStop`,this.onGameStop,e?this.playerCopy(e):null))}pauseGame(e){this.changePause(e,null)}changePause(e,t){if(this.closed)throw Error(`Room is closed`);this.engine.phase!==`lobby`&&(e=!!e,this.engine.paused!==e&&(this.command(`pause`,0,+e),this.state(),e?this.invoke(`onGamePause`,this.onGamePause,t):this.invoke(`onGameUnpause`,this.onGameUnpause,t),this.invoke(`onGamePauseChange`,this.onGamePauseChange,e)))}setSurfaceEnabled(e){if(this.closed)throw Error(`Room is closed`);if(typeof e!=`boolean`)throw Error(`Surface enabled must be a boolean`);if(![`lobby`,`finished`].includes(this.engine.phase))throw Error(`Stop the match before changing its surface`);!!this.engine.snapshotSurface().length!==e&&(this.command(`surface`,0,+e),this.state(),this.sync())}setKickRateLimit(e=2,t=0,n=0){this.changeKickRateLimit(e,t,n,null)}changeKickRateLimit(e,t,n,r){if(this.closed)throw Error(`Room is closed`);let i=_n(e,t,n);i!==this.engine.kickRate&&(this.command(`kickRate`,0,i),this.state(),this.invoke(`onKickRateLimitSet`,this.onKickRateLimitSet,i&255,i>>>8&255,i>>>16,r))}async setPassword(e){if(this.closed)throw Error(`Room is closed`);await this.network.setPassword(e)}get requireVerification(){return this.network.requireVerification}async setRequireVerification(e){if(this.closed)throw Error(`Room is closed`);await this.network.setRequireVerification(e)}async setRequireRecaptcha(e){await this.setRequireVerification(e)}setScoreLimit(e){if(this.closed)throw Error(`Room is closed`);if([`lobby`,`finished`].includes(this.engine.phase)){if(!Number.isInteger(e)||e<0||e>99)throw Error(`Invalid limit`);e!==this.engine.scoreLimit&&(this.command(`scoreLimit`,0,e),this.sync())}}setTimeLimit(e){if(this.closed)throw Error(`Room is closed`);if([`lobby`,`finished`].includes(this.engine.phase)){if(!Number.isInteger(e)||e<0||e>99)throw Error(`Invalid time limit`);e*60!==this.engine.timeLimit&&(this.command(`timeLimit`,0,e*60),this.sync())}}async setDefaultStadium(e){if(this.closed)throw Error(`Room is closed`);if(![`lobby`,`finished`].includes(this.engine.phase))return;let t=++this.stadiumSelection,n=await this.runtime.loadStadium(e);if(this.closed)throw Error(`Room is closed`);if(t!==this.stadiumSelection)throw Error(`Stadium selection superseded`);this.setCustomStadium(n)}setCustomStadium(e){this.changeStadium(e,null)}changeStadium(e,t){if(this.closed)throw Error(`Room is closed`);if(![`lobby`,`finished`].includes(this.engine.phase))return;pn(e);let n=++this.stadiumSelection;if(this.recorder&&this.finishRecording(`Stadium changed`),this.closed)throw Error(`Room is closed`);if([`lobby`,`finished`].includes(this.engine.phase)){if(n!==this.stadiumSelection)throw Error(`Stadium selection superseded`);this.engine.load(e);for(let e of this.players)this.engine.setTeam(e.slot,e.team);this.epoch=this.epoch+1&65535,this.inputs.clear(),this.network.broadcast({type:`stadium`,epoch:this.epoch,source:e,state:this.engine.snapshot()}),this.invoke(`onStadiumChange`,this.onStadiumChange,this.engine.stadium.name,t)}}getScores(){let e=this.engine;return this.closed||e.phase===`lobby`?null:{red:e.red,blue:e.blue,time:e.elapsed/60,scoreLimit:e.scoreLimit,timeLimit:e.timeLimit}}getBallPosition(){return this.closed||this.engine.phase===`lobby`?null:{x:this.engine.data[0],y:this.engine.data[1]}}readDisc(e){let t=this.engine.data,n=e*18;return{x:t[n],y:t[n+1],xspeed:t[n+2],yspeed:t[n+3],radius:t[n+4],invMass:t[n+5],damping:t[n+6],bCoeff:t[n+7],xgravity:t[n+8],ygravity:t[n+9],cGroup:t[n+10],cMask:t[n+11],color:this.engine.colors[e]}}get CollisionFlags(){return gr}getDiscCount(){return this.closed||this.engine.phase===`lobby`?0:this.engine.stadium.discs.length+this.players.filter(e=>e.team!==0).length}getDiscProperties(e){if(!Number.isInteger(e)||e<0||e>=this.getDiscCount())return null;let t=this.engine.stadium.discs.length;if(e<t)return this.readDisc(e);let n=this.players.filter(e=>e.team!==0)[e-t];return this.readDisc(this.engine.index(n.slot))}setDiscProperties(e,t){if(this.closed)throw Error(`Room is closed`);if(!Number.isInteger(e)||e<0||e>=this.getDiscCount())return;let n=this.engine.stadium.discs.length,r=e<n?e:this.engine.index(this.players.filter(e=>e.team!==0)[e-n].slot);this.changeDisc(r,t)}setPlayerDiscProperties(e,t){if(this.closed)throw Error(`Room is closed`);if(this.engine.phase===`lobby`)return;let n=this.players.find(t=>t.id===e&&t.team!==0);n&&this.changeDisc(this.engine.index(n.slot),t)}changeDisc(e,t){let n=_t(t),r=this.readDisc(e);if(Object.entries(n).every(([e,t])=>r[e]===t))return;let i={tick:this.engine.tick,kind:`disc`,slot:e,value:0,properties:n};if(this.recorder&&(!this.recorder.canRecord(this.engine)||!this.recorder.command(i))&&this.finishRecording(`Recording limit reached`),this.closed)throw Error(`Room is closed`);Ln(this.engine,i),this.state()}getPlayerDiscProperties(e){if(this.closed||this.engine.phase===`lobby`)return null;let t=this.players.find(t=>t.id===e&&t.team!==0);return t?this.readDisc(this.engine.index(t.slot)):null}getState(){return this.engine.snapshot()}startRecording(){if(this.closed)throw Error(`Room is closed`);if(this.finishingRecording)throw Error(`Recording completion is in progress`);if(this.recorder)throw Error(`Recording is already active`);this.recorder=new Rn(this.engine,this.players.map(e=>({slot:e.slot,name:e.name,avatar:e.avatarOverride??e.avatar})),this.teamStyles)}finishRecording(e){this.finishingRecording=!0;try{let t=this.stopRecording();t&&(this.lastRecording=t,this.invoke(`onRecordingComplete`,this.onRecordingComplete,t,e))}finally{this.finishingRecording=!1}}stopRecording(){let e=this.recorder?.finish(this.engine)??null;return this.recorder=void 0,e}close(){if(!this.closed){this.closed=!0,this.closeController.abort();try{this.recorder&&this.finishRecording(`Room closed`)}finally{clearInterval(this.loop),clearTimeout(this.linkNotification),this.linkNotification=void 0,this.network?.close(),this.players=[],this.traffic.clear()}}}};function vr(e){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`Room configuration must be an object`);let t={...e},n=t.maxPlayers??12;if(typeof n!=`number`||!Number.isFinite(n)||!Number.isInteger(n))throw Error(`maxPlayers must be a finite integer`);return ct({...t,roomName:t.roomName??`Headless Room`,playerName:t.playerName??`Host`,noPlayer:t.noPlayer??!1,public:t.public??!1,maxPlayers:Math.max(2,Math.min(30,n)),password:t.password??``})}var yr=class{onError;pending=[];active;scheduled=!1;closed=!1;constructor(e=()=>{}){this.onError=e}enqueue(e){let t=new Promise((t,n)=>{if(this.closed){n(Error(`Room is closed`));return}if(this.pending.length>=256){n(Error(`Room command queue is full`));return}this.pending.push({run:e,resolve:e=>t(e),reject:n}),this.scheduled||(this.scheduled=!0,queueMicrotask(()=>{this.drain()}))});return t.catch(e=>{if(!this.closed)try{this.onError(e)}catch{}}),t}async drain(){for(;!this.closed&&this.pending.length;){let e=this.pending.shift();this.active=e;try{e.resolve(await e.run())}catch(t){e.reject(t)}this.active=void 0}this.scheduled=!1}close(){if(this.closed)return;this.closed=!0;let e=Error(`Room is closed`);this.active?.reject(e);for(let t of this.pending.splice(0))t.reject(e)}},br=[`sendChat`,`sendAnnouncement`,`setPlayerAdmin`,`setPlayerTeam`,`kickPlayer`,`clearBan`,`clearBans`,`setScoreLimit`,`setTimeLimit`,`setCustomStadium`,`setDefaultStadium`,`setTeamsLock`,`setTeamColors`,`startGame`,`stopGame`,`pauseGame`,`setPassword`,`setRequireVerification`,`setRequireRecaptcha`,`reorderPlayers`,`setKickRateLimit`,`setSurfaceEnabled`,`setPlayerAvatar`,`setDiscProperties`,`setPlayerDiscProperties`];function xr(e,t){let n=Object.create(null);t&&Object.defineProperty(n,"closed",{enumerable:!0,value:t});let r=new yr(t=>{let n=e.onError?.(String(t));n instanceof Promise&&n.catch(()=>{})});e.signal.addEventListener(`abort`,()=>r.close(),{once:!0}),e.signal.aborted&&r.close();for(let t of br)Object.defineProperty(n,t,{enumerable:!0,value:(...n)=>{try{let i=structuredClone(n);return(t===`setScoreLimit`||t===`setTimeLimit`)&&typeof i[0]==`number`&&Number.isInteger(i[0])&&(i[0]=Math.max(0,Math.min(99,i[0]))),r.enqueue(()=>Reflect.apply(e[t],e,i))}catch(e){return r.enqueue(()=>{throw e})}}});for(let t of[`getPlayer`,`getPlayerList`,`getScores`,`getBallPosition`,`getDiscCount`,`getDiscProperties`,`getPlayerDiscProperties`,`getState`,`startRecording`,`stopRecording`])Object.defineProperty(n,t,{enumerable:!0,value:e[t].bind(e)});for(let t of[`roomId`,`roomLink`,`roomName`,`lastRecording`,`requireVerification`,`CollisionFlags`,`signal`])Object.defineProperty(n,t,{enumerable:!0,get:()=>e[t]});for(let t of[`onRoomLink`,`onPlayerJoin`,`onPlayerLeave`,`onPlayerChat`,`onPlayerTeamChange`,`onPlayerAdminChange`,`onPlayerKicked`,`onPlayerActivity`,`onPlayerBallKick`,`onTeamGoal`,`onTeamVictory`,`onGameVictory`,`onGameStart`,`onGameStop`,`onGameTick`,`onGamePause`,`onGameUnpause`,`onGamePauseChange`,`onPositionsReset`,`onStadiumChange`,`onTeamsLockChange`,`onKickRateLimitSet`,`onRecordingComplete`,`onError`]){let r;Object.defineProperty(n,t,{enumerable:!0,get:()=>r,set:i=>{if(i!=null&&typeof i!=`function`)throw Error(`Callback must be a function`);r=i,Reflect.set(e,t,i==null?void 0:(...e)=>Reflect.apply(i,n,e))}})}return Object.defineProperty(n,"close",{enumerable:!0,value:()=>{r.close(),e.close()}}),Object.preventExtensions(n)}var Sr=R(((e,t)=>{var n=1e3,r=n*60,i=r*60,a=i*24,o=a*7,s=a*365.25;t.exports=function(e,t){t||={};var n=typeof e;if(n===`string`&&e.length>0)return c(e);if(n===`number`&&isFinite(e))return t.long?u(e):l(e);throw Error(`val is not a non-empty string or a valid number. val=`+JSON.stringify(e))};function c(e){if(e=String(e),!(e.length>100)){var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(t){var c=parseFloat(t[1]);switch((t[2]||`ms`).toLowerCase()){case`years`:case`year`:case`yrs`:case`yr`:case`y`:return c*s;case`weeks`:case`week`:case`w`:return c*o;case`days`:case`day`:case`d`:return c*a;case`hours`:case`hour`:case`hrs`:case`hr`:case`h`:return c*i;case`minutes`:case`minute`:case`mins`:case`min`:case`m`:return c*r;case`seconds`:case`second`:case`secs`:case`sec`:case`s`:return c*n;case`milliseconds`:case`millisecond`:case`msecs`:case`msec`:case`ms`:return c;default:return}}}}function l(e){var t=Math.abs(e);return t>=a?Math.round(e/a)+`d`:t>=i?Math.round(e/i)+`h`:t>=r?Math.round(e/r)+`m`:t>=n?Math.round(e/n)+`s`:e+`ms`}function u(e){var t=Math.abs(e);return t>=a?d(e,t,a,`day`):t>=i?d(e,t,i,`hour`):t>=r?d(e,t,r,`minute`):t>=n?d(e,t,n,`second`):e+` ms`}function d(e,t,n,r){var i=t>=n*1.5;return Math.round(e/n)+` `+r+(i?`s`:``)}})),Cr=R(((e,t)=>{function n(e){n.debug=n,n.default=n,n.coerce=c,n.disable=o,n.enable=i,n.enabled=s,n.humanize=Sr(),n.destroy=l,Object.keys(e).forEach(t=>{n[t]=e[t]}),n.names=[],n.skips=[],n.formatters={};function t(e){let t=0;for(let n=0;n<e.length;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return n.colors[Math.abs(t)%n.colors.length]}n.selectColor=t;function n(e){let t,i=null,a,o;function s(...e){if(!s.enabled)return;let r=s,i=Number(new Date);r.diff=i-(t||i),r.prev=t,r.curr=i,t=i,e[0]=n.coerce(e[0]),typeof e[0]!=`string`&&e.unshift(`%O`);let a=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,(t,i)=>{if(t===`%%`)return`%`;a++;let o=n.formatters[i];if(typeof o==`function`){let n=e[a];t=o.call(r,n),e.splice(a,1),a--}return t}),n.formatArgs.call(r,e),(r.log||n.log).apply(r,e)}return s.namespace=e,s.useColors=n.useColors(),s.color=n.selectColor(e),s.extend=r,s.destroy=n.destroy,Object.defineProperty(s,"enabled",{enumerable:!0,configurable:!1,get:()=>i===null?(a!==n.namespaces&&(a=n.namespaces,o=n.enabled(e)),o):i,set:e=>{i=e}}),typeof n.init==`function`&&n.init(s),s}function r(e,t){let r=n(this.namespace+(t===void 0?`:`:t)+e);return r.log=this.log,r}function i(e){n.save(e),n.namespaces=e,n.names=[],n.skips=[];let t=(typeof e==`string`?e:``).trim().replace(` `,`,`).split(`,`).filter(Boolean);for(let e of t)e[0]===`-`?n.skips.push(e.slice(1)):n.names.push(e)}function a(e,t){let n=0,r=0,i=-1,a=0;for(;n<e.length;)if(r<t.length&&(t[r]===e[n]||t[r]===`*`))t[r]===`*`?(i=r,a=n,r++):(n++,r++);else if(i!==-1)r=i+1,a++,n=a;else return!1;for(;r<t.length&&t[r]===`*`;)r++;return r===t.length}function o(){let e=[...n.names,...n.skips.map(e=>`-`+e)].join(`,`);return n.enable(``),e}function s(e){for(let t of n.skips)if(a(e,t))return!1;for(let t of n.names)if(a(e,t))return!0;return!1}function c(e){return e instanceof Error?e.stack||e.message:e}function l(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}return n.enable(n.load()),n}t.exports=n})),wr=R(((e,t)=>{e.formatArgs=r,e.save=i,e.load=a,e.useColors=n,e.storage=o(),e.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),e.colors=`#0000CC.#0000FF.#0033CC.#0033FF.#0066CC.#0066FF.#0099CC.#0099FF.#00CC00.#00CC33.#00CC66.#00CC99.#00CCCC.#00CCFF.#3300CC.#3300FF.#3333CC.#3333FF.#3366CC.#3366FF.#3399CC.#3399FF.#33CC00.#33CC33.#33CC66.#33CC99.#33CCCC.#33CCFF.#6600CC.#6600FF.#6633CC.#6633FF.#66CC00.#66CC33.#9900CC.#9900FF.#9933CC.#9933FF.#99CC00.#99CC33.#CC0000.#CC0033.#CC0066.#CC0099.#CC00CC.#CC00FF.#CC3300.#CC3333.#CC3366.#CC3399.#CC33CC.#CC33FF.#CC6600.#CC6633.#CC9900.#CC9933.#CCCC00.#CCCC33.#FF0000.#FF0033.#FF0066.#FF0099.#FF00CC.#FF00FF.#FF3300.#FF3333.#FF3366.#FF3399.#FF33CC.#FF33FF.#FF6600.#FF6633.#FF9900.#FF9933.#FFCC00.#FFCC33`.split(`.`);function n(){if(typeof window<`u`&&window.process&&(window.process.type===`renderer`||window.process.__nwjs))return!0;if(typeof navigator<`u`&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;let e;return typeof document<`u`&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<`u`&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<`u`&&navigator.userAgent&&(e=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/))&&parseInt(e[1],10)>=31||typeof navigator<`u`&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function r(e){if(e[0]=(this.useColors?`%c`:``)+this.namespace+(this.useColors?` %c`:` `)+e[0]+(this.useColors?`%c `:` `)+`+`+t.exports.humanize(this.diff),!this.useColors)return;let n=`color: `+this.color;e.splice(1,0,n,`color: inherit`);let r=0,i=0;e[0].replace(/%[a-zA-Z%]/g,e=>{e!==`%%`&&(r++,e===`%c`&&(i=r))}),e.splice(i,0,n)}e.log=console.debug||console.log||(()=>{});function i(t){try{t?e.storage.setItem(`debug`,t):e.storage.removeItem(`debug`)}catch{}}function a(){let t;try{t=e.storage.getItem(`debug`)}catch{}return!t&&typeof process<`u`&&`env`in process&&(t=process.env.DEBUG),t}function o(){try{return localStorage}catch{}}t.exports=Cr()(e);var{formatters:s}=t.exports;s.j=function(e){try{return JSON.stringify(e)}catch(e){return`[UnexpectedJSONParseError]: `+e.message}}})),Tr=z({createSupportsColor:()=>Ar,default:()=>Nr});function Er(e,t=globalThis.Deno?globalThis.Deno.args:p.argv){let n=e.startsWith(`-`)?``:e.length===1?`-`:`--`,r=t.indexOf(n+e),i=t.indexOf(`--`);return r!==-1&&(i===-1||r<i)}function Dr(){if(!(`FORCE_COLOR`in jr))return;if(jr.FORCE_COLOR===`true`)return 1;if(jr.FORCE_COLOR===`false`)return 0;if(jr.FORCE_COLOR.length===0)return 1;let e=Math.min(Number.parseInt(jr.FORCE_COLOR,10),3);if([0,1,2,3].includes(e))return e}function Or(e){return e!==0&&{level:e,hasBasic:!0,has256:e>=2,has16m:e>=3}}function kr(e,{streamIsTTY:t,sniffFlags:n=!0}={}){let r=Dr();r!==void 0&&(Mr=r);let i=n?Mr:r;if(i===0)return 0;if(n){if(Er(`color=16m`)||Er(`color=full`)||Er(`color=truecolor`))return 3;if(Er(`color=256`))return 2}if(`TF_BUILD`in jr&&`AGENT_NAME`in jr)return 1;if(e&&!t&&i===void 0)return 0;let a=i||0;if(jr.TERM===`dumb`)return a;if(p.platform===`win32`){let e=h.release().split(`.`);return Number(e[0])>=10&&Number(e[2])>=10586?Number(e[2])>=14931?3:2:1}if(`CI`in jr)return[`GITHUB_ACTIONS`,`GITEA_ACTIONS`,`CIRCLECI`].some(e=>e in jr)?3:[`TRAVIS`,`APPVEYOR`,`GITLAB_CI`,`BUILDKITE`,`DRONE`].some(e=>e in jr)||jr.CI_NAME===`codeship`?1:a;if(`TEAMCITY_VERSION`in jr)return+!!/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(jr.TEAMCITY_VERSION);if(jr.COLORTERM===`truecolor`||jr.TERM===`xterm-kitty`||jr.TERM===`xterm-ghostty`||jr.TERM===`wezterm`)return 3;if(`TERM_PROGRAM`in jr){let e=Number.parseInt((jr.TERM_PROGRAM_VERSION||``).split(`.`)[0],10);switch(jr.TERM_PROGRAM){case`iTerm.app`:return e>=3?3:2;case`Apple_Terminal`:return 2}}return/-256(color)?$/i.test(jr.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(jr.TERM)||`COLORTERM`in jr?1:a}function Ar(e,t={}){return Or(kr(e,{streamIsTTY:e&&e.isTTY,...t}))}var jr,Mr,Nr,Pr=L((()=>{({env:jr}=p),Er(`no-color`)||Er(`no-colors`)||Er(`color=false`)||Er(`color=never`)?Mr=0:(Er(`color`)||Er(`colors`)||Er(`color=true`)||Er(`color=always`))&&(Mr=1),Nr={stdout:Ar({isTTY:g.isatty(1)}),stderr:Ar({isTTY:g.isatty(2)})}})),Fr=R(((e,t)=>{var n=te(`tty`),r=te(`util`);e.init=u,e.log=s,e.formatArgs=a,e.save=c,e.load=l,e.useColors=i,e.destroy=r.deprecate(()=>{},"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."),e.colors=[6,2,3,4,5,1];try{let t=(Pr(),ee(Tr));t&&(t.stderr||t).level>=2&&(e.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221])}catch{}e.inspectOpts=Object.keys(process.env).filter(e=>/^debug_/i.test(e)).reduce((e,t)=>{let n=t.substring(6).toLowerCase().replace(/_([a-z])/g,(e,t)=>t.toUpperCase()),r=process.env[t];return r=/^(yes|on|true|enabled)$/i.test(r)?!0:/^(no|off|false|disabled)$/i.test(r)?!1:r===`null`?null:Number(r),e[n]=r,e},{});function i(){return`colors`in e.inspectOpts?!!e.inspectOpts.colors:n.isatty(process.stderr.fd)}function a(e){let{namespace:n,useColors:r}=this;if(r){let r=this.color,i=`\x1B[3`+(r<8?r:`8;5;`+r),a=` ${i};1m${n} \u001B[0m`;e[0]=a+e[0].split(`
|
|
14
|
+
`+t+`]`}return r.pop(),i=t,a}}},tn={ball:1,red:2,blue:4,redKO:8,blueKO:16,wall:32,kick:64,score:128,c0:268435456,c1:536870912,c2:1073741824,c3:-2147483648,all:63},nn=e=>{if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`Expected an object`);return e},rn=(e,t,n=-4096,r=4096)=>{let i=e===void 0?t:e;if(typeof i!=`number`||!Number.isFinite(i)||i<n||i>r)throw Error(`Number must be between ${n} and ${r}`);return i},an=(e,t=[0,0])=>{if(e===void 0)return[...t];if(!Array.isArray(e)||e.length!==2)throw Error(`Expected [x, y]`);return[rn(e[0],0),rn(e[1],0)]},on=(e,t)=>{if(e===void 0)return[];if(!Array.isArray(e)||e.length>t)throw Error(`Array limit: ${t}`);return e};function sn(e,t){return e===void 0?t:typeof e==`number`?rn(e,t,-2147483648,4294967295)|0:on(e,16).reduce((e,t)=>{if(typeof t!=`string`||!Object.hasOwn(tn,t))throw Error(`Unknown collision flag`);return e|tn[t]},0)}function cn(e,t=`FFFFFF`){if(e===void 0)return t;if(e===`transparent`)return e;if(Array.isArray(e)&&e.length===3)return e.map(e=>Math.round(rn(e,0,0,255)).toString(16).padStart(2,`0`)).join(``);if(typeof e==`string`&&/^[0-9a-f]{6}$/i.test(e))return e;throw Error(`Invalid color`)}var ln=Object.fromEntries(Object.entries({root:`version physicsMode name width height maxViewWidth cameraFollow spawnDistance canBeStored kickOffReset bg traits vertexes segments goals discs planes joints redSpawnPoints blueSpawnPoints playerPhysics ballPhysics`,bg:`type width height kickOffRadius cornerRadius goalLine color`,vertexes:`trait x y bCoef cMask cGroup`,segments:`trait v0 v1 bCoef cMask cGroup curve curveF bias color vis`,discs:`trait pos speed gravity radius invMass damping bCoef cGroup cMask color`,planes:`trait normal dist bCoef cMask cGroup`,goals:`trait p0 p1 team`,joints:`trait d0 d1 length strength color`,playerPhysics:`trait pos speed gravity radius invMass damping bCoef cGroup cMask color acceleration kickingAcceleration kickingDamping kickStrength kickback`}).map(([e,t])=>[e,new Set(t.split(` `))])),un=new Set([`vertexes`,`segments`,`discs`,`planes`,`goals`,`joints`,`playerPhysics`].flatMap(e=>[...ln[e]]));function dn(e){let t=[],n=(e,t)=>{let n=t.length>80?t.slice(0,80)+`…`:t;return e+(/^[A-Za-z_$][\w$]*$/.test(n)?`.`+n:`[`+JSON.stringify(n)+`]`)},r=(e,r,i)=>{if(e&&typeof e==`object`&&!Array.isArray(e))for(let a of Object.keys(e))r.has(a)||(t.length<64?t.push(`Unsupported stadium field: `+n(i,a)):t.length===64&&t.push(`Additional unsupported stadium fields omitted.`))};r(e,ln.root,`$`),r(e.bg,ln.bg,`$.bg`);for(let t of[`vertexes`,`segments`,`discs`,`planes`,`goals`,`joints`]){let n=e[t];Array.isArray(n)&&n.forEach((e,n)=>r(e,ln[t],`$.`+t+`[`+n+`]`))}if(r(e.ballPhysics,ln.discs,`$.ballPhysics`),r(e.playerPhysics,ln.playerPhysics,`$.playerPhysics`),e.traits&&typeof e.traits==`object`&&!Array.isArray(e.traits))for(let[t,i]of Object.entries(e.traits))r(i,un,n(`$.traits`,t));return t}function fn(e,t,n,r,i){let a=e===`hbs`?1:Math.ceil(2*Math.SQRT2*100/Math.min(10,i));if((t+32)*(n+t+32+r)*a>2e6)throw Error(`Stadium collision complexity exceeds the room budget`)}function pn(e){if(new TextEncoder().encode(e).length>262144)throw Error(`Stadium exceeds 256 KB`);let t=nn(en.parse(e));if(t.physicsMode!==void 0&&t.physicsMode!==`hbs`&&t.physicsMode!==`substeps`)throw Error(`Invalid physics mode`);let n=t.physicsMode===`substeps`?`substeps`:`hbs`;if(t.version!==void 0&&t.version!==1)throw Error(`Unsupported stadium version`);let r=t.traits===void 0?{}:nn(t.traits),i=e=>{let t=nn(e);if(t.trait===void 0)return t;if(typeof t.trait!=`string`||!Object.hasOwn(r,t.trait))throw Error(`Unknown trait`);return{...nn(r[t.trait]),...t}},a=(e,t=!1)=>({pos:an(e.pos),speed:an(e.speed),gravity:an(e.gravity),radius:rn(e.radius,10,.5,100),invMass:rn(e.invMass,1,0,8192),damping:rn(e.damping,.99,0,8192),bCoef:rn(e.bCoef,.5,-1,8192),cGroup:sn(e.cGroup,t?193:63),cMask:sn(e.cMask,63),color:cn(e.color)}),o=on(t.discs,63).map(e=>a(i(e)));if(t.ballPhysics!==`disc0`){let e=a(t.ballPhysics===void 0?{}:i(t.ballPhysics),!0);e.cGroup|=192,o.unshift(e)}else if(!o.length)throw Error(`disc0 needs a disc`);let s=on(t.vertexes,1024).map(e=>i(e)),c=[],l=[],u=dn(t);for(let e of s)c.push({a:[rn(e.x,0),rn(e.y,0)],b:[rn(e.x,0),rn(e.y,0)],bCoef:rn(e.bCoef,1,-1,8192),cGroup:sn(e.cGroup,32),cMask:sn(e.cMask,63),bias:0,color:`transparent`,vis:!1});let d=[...c];for(let e of on(t.segments,1024)){let t=i(e),n=rn(t.v0,-1,0,s.length-1),r=rn(t.v1,-1,0,s.length-1);if(!Number.isInteger(n)||!Number.isInteger(r))throw Error(`Vertex indices must be integers`);let a=[rn(s[n].x,0),rn(s[n].y,0)],o=[rn(s[r].x,0),rn(s[r].y,0)],u={bCoef:rn(t.bCoef,1,-1,8192),cGroup:sn(t.cGroup,32),cMask:sn(t.cMask,63),bias:rn(t.bias,0,-100,100),color:cn(t.color,`000000`),vis:t.vis!==!1},f=t.curveF===void 0?rn(t.curve,0,-359,359):2*Math.atan2(1,rn(t.curveF,0,-1e8,1e8))*180/Math.PI;if(Math.abs(f)<1e-4){let e={a,b:o,...u};c.push(e),(a[0]!==o[0]||a[1]!==o[1])&&d.push(e);continue}let p=f*Math.PI/180,m=o[0]-a[0],h=o[1]-a[1];if(Math.hypot(m,h)<.001)throw Error(`Arc endpoints overlap`);let g=1/(2*Math.tan(p/2)),_=[(a[0]+o[0])/2-h*g,(a[1]+o[1])/2+m*g],v=Math.hypot(a[0]-_[0],a[1]-_[1]),y=Math.atan2(a[1]-_[1],a[0]-_[0]),b=Math.ceil(Math.abs(p)/Math.max(1e-8,2*Math.acos(Math.max(-1,1-.15/v))));if(c.length+b>4096)throw Error(`Compiled geometry exceeds 4096 segments`);let x={a,b:o,...u,center:_,radius:v,start:y,sweep:p,major:t.curveF===void 0?Math.abs(f)>180:Number(t.curveF)<=0};l.push(x),d.push(x);let S=a;for(let e=1;e<=b;e++){let t=e===b?o:[_[0]+v*Math.cos(y+p*e/b),_[1]+v*Math.sin(y+p*e/b)];c.push({a:S,b:t,...u,renderOnly:!0}),S=t}}if(c.length>4096)throw Error(`Compiled geometry exceeds 4096 segments`);let f=t.playerPhysics===void 0?{}:i(t.playerPhysics),p={...a({...f,radius:f.radius??15,invMass:f.invMass??.5,damping:f.damping??.96,cGroup:f.cGroup??0}),acceleration:rn(f.acceleration,.1,-8192,8192),kickingAcceleration:rn(f.kickingAcceleration,.07,-8192,8192),kickingDamping:rn(f.kickingDamping,.96,0,8192),kickStrength:rn(f.kickStrength,5,-8192,8192),kickback:rn(f.kickback,0,-8192,8192)};fn(n,o.length,c.length,on(t.planes,64).length+on(t.joints,128).length,Math.min(p.radius,...o.map(e=>e.radius)));let m=t.bg===void 0?{}:nn(t.bg);return{version:1,physicsMode:n,name:typeof t.name==`string`?t.name.slice(0,64):`Untitled stadium`,canBeStored:t.canBeStored!==!1,width:rn(t.width,520,100,2048),height:rn(t.height,300,80,2048),maxViewWidth:rn(t.maxViewWidth,0,0,4096),cameraFollow:t.cameraFollow===`player`?`player`:`ball`,bg:{type:m.type===`grass`?`grass`:m.type===`hockey`?`hockey`:`none`,cornerRadius:rn(m.cornerRadius,0,0,500),goalLine:rn(m.goalLine,0,0,2048),width:rn(m.width,0,0,2048),height:rn(m.height,0,0,2048),color:cn(m.color,`718C5A`),kickOffRadius:rn(m.kickOffRadius,0,0,500)},discs:o,segments:c,arcs:l,colliders:d,player:p,spawnDistance:rn(t.spawnDistance,200,0,1500),kickOffReset:t.kickOffReset===`full`?`full`:`partial`,redSpawnPoints:on(t.redSpawnPoints,32).map(e=>an(e)),blueSpawnPoints:on(t.blueSpawnPoints,32).map(e=>an(e)),warnings:u,planes:on(t.planes,64).map(e=>{let t=i(e),n=an(t.normal);if(Math.hypot(...n)<1e-6)throw Error(`Plane normal is zero`);return{normal:n,dist:rn(t.dist,0),bCoef:rn(t.bCoef,1,-1,8192),cGroup:sn(t.cGroup,32),cMask:sn(t.cMask,63)}}),goals:on(t.goals,16).map(e=>{let t=i(e);if(t.team!==`red`&&t.team!==`blue`)throw Error(`Invalid goal team`);let n=an(t.p0),r=an(t.p1);if(Math.hypot(r[0]-n[0],r[1]-n[1])<1)throw Error(`Goal has zero length`);return{p0:n,p1:r,team:t.team===`red`?1:2}}),joints:on(t.joints,128).map(e=>{let t=i(e),n=rn(t.d0,-1,0,o.length-1),r=rn(t.d1,-1,0,o.length-1);if(!Number.isInteger(n)||!Number.isInteger(r)||n===r)throw Error(`Invalid joint indices`);let a=Math.hypot(o[r].pos[0]-o[n].pos[0],o[r].pos[1]-o[n].pos[1]),s=t.length==null?[a,a]:typeof t.length==`number`?[t.length,t.length]:an(t.length);return{d0:n,d1:r,min:rn(s[0],0,0),max:rn(s[1],0,0),strength:t.strength===void 0||t.strength===`rigid`?`rigid`:rn(t.strength,0,-8192,8192),color:cn(t.color,`000000`)}})}}function mn(e=`Emerald Arena`,t=440,n=220){let r=[[-t,-n],[t,-n],[-t,n],[t,n],[-t,-70],[-t,70],[t,-70],[t,70],[-t-30,-70],[-t-30,70],[t+30,-70],[t+30,70],[0,-n-40],[0,-65],[0,65],[0,n+40]];return JSON.stringify({version:1,physicsMode:`substeps`,name:e,width:t+75,height:n+65,spawnDistance:t*.4,bg:{type:`grass`,width:t,height:n,kickOffRadius:65,color:`285B35`},vertexes:r.map(([e,t],n)=>({x:e,y:t,...n>=12?{cGroup:[`redKO`,`blueKO`],cMask:[`red`,`blue`]}:{}})),segments:[...[[0,1],[2,3],[0,4],[5,2],[1,6],[7,3],[4,8],[8,9],[9,5],[6,10],[10,11],[11,7]].map(([e,t],n)=>({v0:e,v1:t,cMask:[`ball`],color:n<6?`72A99C`:`3D7267`,bCoef:n<6?.8:.15})),{v0:12,v1:13,vis:!1,cGroup:[`redKO`,`blueKO`],cMask:[`red`,`blue`]},{v0:14,v1:15,vis:!1,cGroup:[`redKO`,`blueKO`],cMask:[`red`,`blue`]},{v0:14,v1:13,curve:-180,vis:!1,cGroup:[`redKO`],cMask:[`red`,`blue`]},{v0:14,v1:13,curve:180,vis:!1,cGroup:[`blueKO`],cMask:[`red`,`blue`]}],planes:[{normal:[0,1],dist:-n-40},{normal:[0,-1],dist:-n-40},{normal:[1,0],dist:-t-50},{normal:[-1,0],dist:-t-50}],goals:[{p0:[-t,-70],p1:[-t,70],team:`red`},{p0:[t,-70],p1:[t,70],team:`blue`}],discs:[...[-t,t].flatMap(e=>[-70,70].map(t=>({pos:[e,t],radius:6,invMass:0,color:`DAEEE4`,bCoef:.5})))],ballPhysics:{radius:9,damping:.991,bCoef:.6},playerPhysics:{radius:15,acceleration:.11,damping:.96,kickStrength:5.5}},null,2)}var hn=`ball2d-core/1/${vt}`,gn=class e{core;terrain;stadium;source=``;colors=[];tick=0;elapsed=0;ballKicks=[];red=0;blue=0;phase=`lobby`;paused=!1;resumeTicks=0;countdown=0;kickoff=1;kickoffActive=!0;scoreLimit=5;timeLimit=300;lastGoal=0;kickRate=2;setKickRateLimit(e,t,n){this.kickRate=_n(e,t,n),this.core.kick_limits(this.kickRate&255,this.kickRate>>>8&255,this.kickRate>>>16)}constructor(e){this.core=e.exports,this.terrain=new et(this.core)}configureSurface(e){if(this.phase!==`lobby`&&this.phase!==`finished`)throw Error(`Stop the match before configuring its surface`);e===null?this.terrain.disable():this.terrain.configure(e)}setSurfaceWeather(e){this.terrain.setWeather(e)}sampleSurface(e,t){return this.terrain.sample(e,t)}get surfaceEnabled(){return this.terrain.enabled}static async create(t,n){let r=t??await(await fetch(`/core.wasm?v=edb227eac070ad86a151`,{signal:n})).arrayBuffer();if(Array.from(new Uint8Array(await crypto.subtle.digest(`SHA-256`,r))).map(e=>e.toString(16).padStart(2,`0`)).join(``)!==`1229b1b4ba3892d6073fb85b3b6231282c2d81ee270808cb0acda874d49cb87e`)throw Error(`Physics build changed. Refresh the page to load a matching version.`);return new e(await WebAssembly.instantiate(await WebAssembly.compile(r)))}get data(){return new Float64Array(this.core.memory.buffer,this.core.data_ptr(),this.core.count()*18)}load(e){this.stadium=pn(e),this.source=e,this.core.reset(),this.terrain.disable(),this.colors=[],this.core.physics_mode(+(this.stadium.physicsMode===`substeps`)),this.tick=0,this.elapsed=0,this.red=this.blue=0,this.phase=`lobby`,this.paused=!1,this.resumeTicks=0,this.countdown=0,this.kickoffActive=!0;for(let e of this.stadium.discs)this.add(e);for(let e=0;e<32;e++)this.add(this.stadium.player,e+1);for(let e of this.stadium.colliders)if(`center`in e){let t=e;this.core.arc(...t.center,t.radius,...t.a,...t.b,t.sweep,+t.major,t.bCoef,t.cGroup,t.cMask,t.bias)}else{let t=e;this.core.wall(...t.a,...t.b,t.bCoef,t.cGroup,t.cMask,t.bias)}for(let e of this.stadium.planes)this.core.plane(...e.normal,e.dist,e.bCoef,e.cGroup,e.cMask);for(let e of this.stadium.joints)this.core.joint(e.d0,e.d1,e.min,e.max,e.strength===`rigid`?1/0:e.strength);for(let e of this.stadium.goals)this.core.goal(...e.p0,...e.p1,e.team);let t=this.stadium.player;this.core.configure(t.acceleration,t.kickStrength,t.kickingAcceleration,t.kickingDamping,t.kickback,this.kickRate&255),this.setKickRateLimit(this.kickRate&255,this.kickRate>>>8&255,this.kickRate>>>16)}add(e,t=0){let n=this.core.add_disc();if(n<0)throw Error(`Disc capacity exceeded`);this.colors.push(e.color===`transparent`?-1:parseInt(e.color,16)),[...e.pos,...e.speed,e.radius,e.invMass,e.damping,e.bCoef,...e.gravity,e.cGroup,e.cMask,t,0,0,0,e.pos[0],t?0:e.pos[1]].forEach((e,t)=>this.core.set_disc(n,t,e))}index(e){if(!Number.isInteger(e)||e<0||e>=32)throw Error(`Invalid slot`);return this.stadium.discs.length+e}joinPlayer(e){let t=this.index(e)*18;this.data[t+15]=0,this.data[t+17]=0,this.setTeam(e,0)}setTeam(e,t){if(![0,1,2].includes(t))throw Error(`Invalid team`);let n=this.index(e),r=this.data;r[n*18+13]=t,r[n*18+10]=this.stadium.player.cGroup|(t===1?2:t===2?4:0),r[n*18+14]=0,this.spawn(n,e,t,this.phase!==`lobby`)}input(e,t){let n=this.data,r=this.index(e)*18,i=t&31;i&16?n[r+14]&16||(n[r+15]=n[r+15]|1024):n[r+15]=n[r+15]&1023,n[r+14]=i}applyDiscProperties(e,t){let n=this.data;if(this.phase===`lobby`||!Number.isInteger(e)||e<0||e>=this.colors.length||n[e*18+12]>0&&n[e*18+13]===0)return!1;let r=_t(t),i=!1;for(let[t,a]of gt){let o=r[t];if(o===void 0)continue;let s=a===-1?this.colors[e]:n[e*18+a];Object.is(s,o)||(i=!0)}if(!i)return!1;if(r.radius!==void 0){let t=r.radius;for(let r=0;r<this.colors.length;r++)r!==e&&(t=Math.min(t,n[r*18+4]));fn(this.stadium.physicsMode,this.stadium.discs.length,this.stadium.segments.length,this.stadium.planes.length+this.stadium.joints.length,t)}for(let[t,i]of gt){let a=r[t];a!==void 0&&(i===-1?this.colors[e]=a:n[e*18+i]=a)}return!0}restoreDiscProperties(e,t){let n=e*18,r=this.data;this.colors[e]=t.color===`transparent`?-1:parseInt(t.color,16),r[n+4]=t.radius,r[n+5]=t.invMass,r[n+6]=t.damping,r[n+7]=t.bCoef,r[n+8]=t.gravity[0],r[n+9]=t.gravity[1],r[n+10]=t.cGroup,r[n+11]=t.cMask}spawn(e,t,n,r=!1){this.restoreDiscProperties(e,this.stadium.player),this.colors[e]=n===1?16087152:n===2?7516147:16777215,this.data[e*18+10]|=n===1?2:n===2?4:0;let i=n===1?this.stadium.redSpawnPoints:this.stadium.blueSpawnPoints,a=this.data,o=0;for(let e=0;e<t;e++)a[this.index(e)*18+13]===n&&o++;let s=n===1?-1:1,c=i.length?i[r?i.length-1:Math.min(o,i.length-1)]:r?[s*this.stadium.width,0]:[s*this.stadium.spawnDistance,o?Math.ceil(o/2)*55*(o%2?1:-1):0];a[e*18]=c[0],a[e*18+1]=c[1],a[e*18+2]=a[e*18+3]=a[e*18+14]=0,a[e*18+15]&=1023,a[e*18+11]=this.stadium.player.cMask&-25}resetPositions(e=!1){this.kickoffActive=!0;let t=this.data;for(let n=0;n<this.stadium.discs.length;n++){let r=this.stadium.discs[n];(e||n===0||this.stadium.kickOffReset===`full`)&&(this.restoreDiscProperties(n,r),t[n*18]=r.pos[0],t[n*18+1]=r.pos[1],t[n*18+2]=r.speed[0],t[n*18+3]=r.speed[1])}for(let e=0;e<32;e++){let n=this.index(e);this.spawn(n,e,t[n*18+13])}}start(){(this.phase===`lobby`||this.phase===`finished`)&&(this.red=this.blue=this.elapsed=0,this.phase=`playing`,this.paused=!1,this.resumeTicks=0,this.kickoff=1,this.countdown=0,this.resetPositions(!0))}stop(){this.phase=`lobby`,this.paused=!1,this.resumeTicks=0}setPaused(e){this.phase!==`lobby`&&(e=!!e,this.paused!==e&&(this.paused=e,this.resumeTicks=e?0:119))}finish(){this.phase=`finished`,this.countdown=300}step(){if(this.ballKicks.length=0,this.tick++,this.paused||this.phase===`lobby`)return;if(this.resumeTicks>0){this.resumeTicks--;return}let e=this.data;this.core.step();for(let e=this.core.ball_kick_events()>>>0,t=0;e;e>>>=1,t++)e&1&&this.ballKicks.push(t);if(this.phase===`finished`){--this.countdown<=0&&this.stop();return}if(this.phase===`goal`){--this.countdown<=0&&(this.scoreLimit>0&&Math.max(this.red,this.blue)>=this.scoreLimit||this.timeLimit>0&&this.elapsed>=this.timeLimit*60&&this.red!==this.blue?this.finish():(this.phase=`playing`,this.resetPositions()));return}for(let t=0;t<32;t++){let n=this.index(t)*18,r=this.stadium.player.cMask;e[n+11]=r&-25|(this.kickoffActive?r&(this.kickoff===1?8:16):0)}if(this.kickoffActive){e[2]*e[2]+e[3]*e[3]>0&&(this.kickoffActive=!1);return}this.elapsed++;let t=this.core.goal_event();if(t===1||t===2){t===1?this.red++:this.blue++,this.kickoff=t===1?2:1,this.phase=`goal`,this.countdown=150,this.lastGoal=this.tick;return}this.timeLimit>0&&this.elapsed>=this.timeLimit*60&&this.red!==this.blue&&this.finish()}snapshotSurface(){return this.terrain.snapshot()}snapshot(){let e=this.snapshotSurface();return{...e.length?{surface:e}:{},tick:this.tick,elapsed:this.elapsed,red:this.red,blue:this.blue,phase:this.phase,paused:this.paused,resumeTicks:this.resumeTicks,countdown:this.countdown,kickoff:this.kickoff,kickoffActive:this.kickoffActive,scoreLimit:this.scoreLimit,timeLimit:this.timeLimit,kickRate:this.kickRate,discs:Array.from(this.data),colors:[...this.colors]}}restore(e){if(!e||typeof e!=`object`||!Array.isArray(e.discs)||e.discs.length!==this.data.length||!e.discs.every((e,t)=>typeof e==`number`&&Number.isFinite(e)&&Math.abs(e)<=(t%18==10||t%18==11?2147483648:t%18==17?25500:8192)))throw Error(`Invalid state`);if(!Array.isArray(e.colors)||e.colors.length!==e.discs.length/18||e.colors.some(e=>!Number.isInteger(e)||e<-1||e>16777215))throw Error(`Invalid disc colors`);let t=(e,t,n=0)=>Number.isInteger(e)&&e>=n&&e<=t;if(!t(e.kickRate,6619135)||!t(e.tick,4294967295)||!t(e.elapsed,4294967295)||!t(e.red,65535)||!t(e.blue,65535)||!t(e.countdown,300)||!t(e.resumeTicks,119)||(e.paused||e.phase===`lobby`)&&e.resumeTicks!==0||!t(e.scoreLimit,99)||!t(e.timeLimit,5940)||![`lobby`,`playing`,`goal`,`finished`].includes(e.phase)||typeof e.paused!=`boolean`||typeof e.kickoffActive!=`boolean`||![1,2].includes(e.kickoff))throw Error(`Invalid match metadata`);for(let n=0;n<e.discs.length;n+=18)if(e.discs[n+4]<.5||e.discs[n+4]>100||e.discs[n+5]<0||e.discs[n+5]>8192||e.discs[n+6]<0||e.discs[n+6]>8192||e.discs[n+7]<-1||e.discs[n+7]>8192||!t(e.discs[n+10],2147483647,-2147483648)||!t(e.discs[n+11],2147483647,-2147483648)||!t(e.discs[n+13],2)||!t(e.discs[n+14],31)||!t(e.discs[n+15],2047)||e.discs[n+12]>0&&(!Number.isInteger(e.discs[n+17])||e.discs[n+17]<-255||e.discs[n+17]>25500))throw Error(`Invalid disc properties`);let n=10;for(let t=4;t<e.discs.length;t+=18)n=Math.min(n,e.discs[t]);fn(this.stadium.physicsMode,this.stadium.discs.length,this.stadium.segments.length,this.stadium.planes.length+this.stadium.joints.length,n),this.terrain.restore(e.surface===void 0?[]:e.surface),this.setKickRateLimit(e.kickRate&255,e.kickRate>>>8&255,e.kickRate>>>16),this.tick=e.tick,this.elapsed=e.elapsed,this.red=e.red,this.blue=e.blue,this.phase=e.phase,this.paused=e.paused,this.resumeTicks=e.resumeTicks,this.countdown=e.countdown,this.kickoff=e.kickoff,this.kickoffActive=e.kickoffActive,this.scoreLimit=e.scoreLimit,this.timeLimit=e.timeLimit,this.data.set(e.discs),this.colors=[...e.colors]}};function _n(e,t,n){if(![e,t,n].every(Number.isInteger))throw Error(`Invalid kick rate limit`);return Math.max(0,Math.min(255,e))|Math.max(0,Math.min(255,t))<<8|Math.max(0,Math.min(100,n))<<16}function vn(e){let t=new URL(e);if(![`http:`,`https:`].includes(t.protocol)||t.username||t.password||t.pathname!==`/`||t.search||t.hash)throw Error(`Expected an HTTP(S) service origin without credentials or a path`);return t.origin}function yn(){return{serviceOrigin:location.origin,signalingResume:!0,createWebSocket:e=>new WebSocket(e),createPeerConnection:e=>new RTCPeerConnection(e)}}var bn=[[`classic`,`Classic`],[`easy`,`Easy`],[`small`,`Small`],[`big`,`Big`],[`rounded`,`Rounded`],[`hockey`,`Hockey`],[`big_easy`,`Big Easy`],[`big_rounded`,`Big Rounded`],[`big_hockey`,`Big Hockey`],[`huge`,`Huge`]];function xn(e){let t=new Map;return async n=>{let r=bn.find(([e,t])=>e===n||t===n);if(!r)throw Error(`Unknown default stadium`);let i=t.get(r[0]);return i||(i=(async()=>{let t=await e(`/stadiums/${r[0]}.hbs`);if(!t.ok)throw Error(`Could not load stadium`);let n=await t.text();return pn(n),n})(),t.set(r[0],i),i.catch(()=>t.delete(r[0]))),i}}function Sn(){let e=yn(),t=(e,t)=>fetch(e,t);return{network:e,request:t,loadEngine:e=>gn.create(void 0,e),loadStadium:xn(n=>t(new URL(n,e.serviceOrigin)))}}var Cn={message:{burst:240,perSecond:160},action:{burst:12,perSecond:6},chat:{burst:4,perSecond:1}},wn=class{peers=new Map;allow(e,t,n=performance.now()){let r=this.peers.get(e);r||(r={},this.peers.set(e,r));let{burst:i,perSecond:a}=Cn[t],o=r[t]??{tokens:i,at:n};return o.tokens=Math.min(i,o.tokens+Math.max(0,n-o.at)*a/1e3),o.at=Math.max(o.at,n),r[t]=o,o.tokens<1?!1:(o.tokens--,!0)}delete(e){this.peers.delete(e)}clear(){this.peers.clear()}},Tn=33554432,En=new TextEncoder;new TextDecoder(`utf-8`,{fatal:!0});function Dn(e){let t=2166136261;for(let n of e)t=Math.imul(t^n,16777619);return t>>>0}function On(e){if(e.length>33554432)throw Error(`Replay exceeds 32 MB`);let t=Je(e,{level:6}),n=new Uint8Array(16+t.length),r=new DataView(n.buffer);return n.set([66,50,68,90,1,0,0,0]),r.setUint32(8,e.length,!0),r.setUint32(12,Dn(e),!0),n.set(t,16),n}function kn(e){if(typeof e==`string`){if(En.encode(e).length>33554432)throw Error(`Replay exceeds 32 MB`);return En.encode(e)}let t=e instanceof Uint8Array?e:new Uint8Array(e);if(t.length>33554432)throw Error(`Replay exceeds 32 MB`);if(t[0]!==66||t[1]!==50||t[2]!==68||t[3]!==90)return t;if(t.length<17||t[4]!==1||t[5]||t[6]||t[7])throw Error(`Invalid compressed replay header`);let n=new DataView(t.buffer,t.byteOffset,t.byteLength),r=n.getUint32(8,!0);if(!r||r>33554432)throw Error(`Invalid expanded replay size`);let i=new Uint8Array(r),a=0,o=!1,s=new Ye((e,t)=>{if(a+e.length>r)throw Error(`Expanded replay exceeds declared size`);i.set(e,a),a+=e.length,o=t});for(let e=16;e<t.length;e+=1024)s.push(t.subarray(e,e+1024),e+1024>=t.length);if(!o||a!==r||Dn(i)!==n.getUint32(12,!0))throw Error(`Compressed replay integrity failure`);return i}var An=[`input`,`team`,`start`,`stop`,`pause`,`scoreLimit`,`timeLimit`,`kickRate`,`join`,`disc`,`surface`],jn=new TextEncoder,Mn=new TextDecoder(`utf-8`,{fatal:!0});function Nn(e){return On(Pn(e))}function Pn(e){let{commands:t,...n}=e,r=t.some(e=>e.kind===`surface`)||e.initial.surface!==void 0||e.checkpoints.some(e=>e.state.surface!==void 0)?4:t.some(e=>e.kind===`disc`)?3:e.checkpoints.length?2:1,i=0,a=e.checkpoints.map(e=>{let t=e.state.discs;if(!Array.isArray(t)||t.length>1728||t.some(e=>!Number.isFinite(e)))throw Error(`Invalid checkpoint discs`);i+=t.length*8;let n=e.state.surface;if(n!==void 0){if(!Array.isArray(n)||n.length!==0&&n.length!==5389||n.some(e=>!Number.isInteger(e)||e<0||e>4294967295))throw Error(`Invalid checkpoint surface`);i+=n.length*4}return{...e,state:{...e.state,discs:t.length,...n===void 0?{}:{surface:n.length}}}});if(a.length>721)throw Error(`Too many replay checkpoints`);let o=jn.encode(JSON.stringify(r>=2?{...n,checkpoints:a}:n));if(t.length>5e5||o.length+16>33554432)throw Error(`Replay exceeds bounds`);let s=t.length*12+t.filter(e=>e.kind===`disc`).length*106,c=new Uint8Array(Math.min(Tn,s)),l=new DataView(c.buffer),u=e=>{if(d+e>c.length)throw Error(`Replay exceeds bounds`)},d=0,f=e.initial.tick,p=e=>{if(!Number.isInteger(e)||e<0||e>4294967295)throw Error(`Invalid replay integer`);do{u(1);let t=Math.floor(e/128);c[d++]=e%128|(t?128:0),e=t}while(e)};for(let e of t){let t=An.indexOf(r<3&&e.kind===`join`?`team`:e.kind);if(e.kind===`join`&&e.value!==0||e.kind===`team`&&e.value>2)throw Error(`Invalid replay team command`);if(t<0||!Number.isInteger(e.slot)||e.slot<0||e.slot>(e.kind===`disc`?95:31))throw Error(`Invalid replay command`);if(p(e.tick-f),u(1),c[d++]=r>=3?t:t<<5|e.slot,r>=3&&p(e.slot),p(r<3&&e.kind===`join`?3:e.value),e.kind===`disc`){let t=_t(e.properties),n=0;gt.forEach(([e],r)=>{t[e]!==void 0&&(n|=1<<r)}),p(n);for(let[e]of gt){let n=t[e];n!==void 0&&(u(8),l.setFloat64(d,n,!0),d+=8)}}f=e.tick}let m=16+o.length+i+d;if(m>33554432)throw Error(`Replay exceeds 32 MB`);let h=new Uint8Array(m),g=new DataView(h.buffer);h.set([66,50,68,80,r,0,0,0]),g.setUint32(8,o.length,!0),g.setUint32(12,t.length,!0),h.set(o,16);let _=16+o.length;for(let t of e.checkpoints){for(let e of t.state.discs)g.setFloat64(_,e,!0),_+=8;for(let e of t.state.surface??[])g.setUint32(_,e,!0),_+=4}return h.set(c.subarray(0,d),_),h}function Fn(e){let t=kn(e);if(t[0]!==66||t[1]!==50||t[2]!==68||t[3]!==80)return JSON.parse(Mn.decode(t));if(t.length<16||![1,2,3,4].includes(t[4])||t[5]||t[6]||t[7])throw Error(`Invalid packed replay header`);let n=new DataView(t.buffer,t.byteOffset,t.byteLength),r=n.getUint32(8,!0),i=n.getUint32(12,!0);if(r>t.length-16||i>5e5||i>(t.length-16-r)/3)throw Error(`Invalid packed replay bounds`);let a=JSON.parse(Mn.decode(t.subarray(16,16+r)));if(!a||!Number.isSafeInteger(a.initial?.tick)||a.initial.tick<0)throw Error(`Invalid replay initial tick`);a.commands=[];let o=16+r,s=a.initial.tick;if(t[4]>=2){if(!Array.isArray(a.checkpoints)||a.checkpoints.length>721)throw Error(`Invalid packed checkpoints`);let e=0;for(let n of a.checkpoints){let r=n?.state?.discs;if(typeof r!=`number`||!Number.isInteger(r)||r<0||r>1728)throw Error(`Invalid checkpoint disc count`);if(e+=r*8,t[4]>=4&&n.state.surface!==void 0){let t=n.state.surface;if(t!==0&&t!==5389)throw Error(`Invalid checkpoint surface count`);e+=t*4}}if(e>t.length-o-i*3)throw Error(`Truncated checkpoint discs`);for(let e of a.checkpoints){let r=e.state.discs,i=Array(r);for(let e=0;e<r;e++){let t=n.getFloat64(o,!0);if(!Number.isFinite(t))throw Error(`Nonfinite checkpoint disc`);i[e]=t,o+=8}if(e.state.discs=i,t[4]>=4&&e.state.surface!==void 0){let t=e.state.surface,r=Array(t);for(let e=0;e<t;e++)r[e]=n.getUint32(o,!0),o+=4;e.state.surface=r}}}let c=()=>{let e=0;for(let n=0;n<=28;n+=7){if(o>=t.length)throw Error(`Truncated replay command`);let r=t[o++];if(n===28&&r>15)throw Error(`Replay integer overflow`);if(e+=(r&127)*2**n,!(r&128)){if(n&&r===0)throw Error(`Noncanonical replay integer`);return e}}throw Error(`Invalid replay integer`)};for(let e=0;e<i;e++){if(s+=c(),!Number.isSafeInteger(s)||o>=t.length)throw Error(`Invalid replay tick`);let e=t[o++],r=An[t[4]>=3?e:e>>5];if(!r)throw Error(`Unknown replay command`);let i=t[4]>=3?c():e&31,l=c();if(r===`disc`){let e=c();if(e>8191)throw Error(`Invalid disc property mask`);let u={};gt.forEach(([r],i)=>{if(e&1<<i){if(o+8>t.length)throw Error(`Truncated disc properties`);u[r]=n.getFloat64(o,!0),o+=8}}),a.commands.push({tick:s,kind:r,slot:i,value:l,properties:_t(u)});continue}a.commands.push(t[4]<3&&r===`team`&&l===3?{tick:s,kind:`join`,slot:i,value:0}:{tick:s,kind:r,slot:i,value:l})}if(o!==t.length)throw Error(`Trailing replay command data`);return a}function In(e){let t=JSON.stringify(e),n=2166136261;for(let e=0;e<t.length;e++)n^=t.charCodeAt(e),n=Math.imul(n,16777619);return(n>>>0).toString(16).padStart(8,`0`)}function Ln(e,t){switch(t.kind){case`surface`:if(t.slot!==0||t.value!==0&&t.value!==1)throw Error(`Invalid surface command`);e.configureSurface(t.value?{seed:42,halfWidth:e.stadium.bg.width||e.stadium.width,halfHeight:e.stadium.bg.height||e.stadium.height,moisturePermille:1e3}:null),t.value&&e.setSurfaceWeather({rainMilliMmH:2e5,temperatureMilliC:2e4,humidityPermille:1e3,windMilliMS:0});break;case`disc`:e.applyDiscProperties(t.slot,t.properties);break;case`input`:e.input(t.slot,t.value);break;case`join`:e.joinPlayer(t.slot);break;case`team`:e.setTeam(t.slot,t.value);break;case`start`:e.start();break;case`stop`:e.stop();break;case`scoreLimit`:e.scoreLimit=t.value;break;case`timeLimit`:e.timeLimit=t.value;break;case`kickRate`:e.setKickRateLimit(t.value&255,t.value>>>8&255,t.value>>>16);break;case`pause`:e.setPaused(!!t.value)}}var Rn=class{replay;playerOrder=[];lastInputs=new Map;bytes=0;full=!1;canRecord(e){return!this.full&&e.tick-this.replay.initial.tick<216e3}constructor(e,t=[],n=[null,null]){let r=e.snapshot();this.playerOrder=t.map(e=>e.slot),this.replay={magic:`B2DR`,version:1,engine:hn,stadium:e.source,initial:r,commands:[],checkpoints:[],roster:t.map(e=>({...e,tick:r.tick})),styles:[{tick:r.tick,teams:ft(n)}],orders:[{tick:r.tick,slots:[...this.playerOrder]}],end:r.tick,finalHash:In(r)},this.bytes=new TextEncoder().encode(JSON.stringify(this.replay)).length;for(let t=0;t<32;t++)this.lastInputs.set(t,e.data[e.index(t)*18+14])}reserve(e){let t=new TextEncoder().encode(JSON.stringify(e)).length+1;return this.full||this.bytes+t>31457280?(this.full=!0,!1):(this.bytes+=t,!0)}player(e,t,n,r){let i={tick:e,slot:t,name:n,avatar:r};return this.replay.roster.length>=4096||!this.reserve(i)?(this.full=!0,!1):(this.replay.roster.push(i),n===null?this.order(e,this.playerOrder.filter(e=>e!==t)):this.playerOrder.includes(t)?!0:this.order(e,[...this.playerOrder,t]))}style(e,t){let n={tick:e,teams:ft(t)},r=this.replay.styles;return r.length>=4096||!this.reserve(n)?(this.full=!0,!1):(r.push(n),!0)}order(e,t){if(t.length===this.playerOrder.length&&t.every((e,t)=>e===this.playerOrder[t]))return!0;let n={tick:e,slots:[...t]},r=this.replay.orders;return r.length>=4096||!this.reserve(n)?(this.full=!0,!1):(this.playerOrder=[...t],r.push(n),!0)}command(e){return e.kind===`input`&&this.lastInputs.get(e.slot)===e.value?!0:this.replay.commands.length>=5e5||!this.reserve(e)?(this.full=!0,!1):(e.kind===`input`&&this.lastInputs.set(e.slot,e.value),(e.kind===`team`||e.kind===`join`)&&this.lastInputs.set(e.slot,0),e.kind===`start`&&this.lastInputs.clear(),this.replay.commands.push(e.kind===`disc`?{...e,properties:_t(e.properties)}:{...e}),!0)}step(e){for(let t=0;t<32;t++)this.lastInputs.set(t,e.data[e.index(t)*18+14]);if(e.tick%300==0){let t=e.snapshot(),n={tick:e.tick,state:t,hash:In(t)};this.reserve(n)&&this.replay.checkpoints.push(n)}this.replay.end=e.tick}pack(e){return this.replay.end=e.tick,this.replay.finalHash=In(e.snapshot()),Pn(this.replay)}finish(e){return this.replay.end=e.tick,this.replay.finalHash=In(e.snapshot()),new Blob([Nn(this.replay)],{type:`application/x-ball2d-replay`})}};async function zn(e){if(e.size>33554432)throw Error(`Replay exceeds 32 MB`);return Bn(await e.arrayBuffer())}function Bn(e){let t=Fn(e);if(t.magic!==`B2DR`||t.version!==1||t.engine!==hn)throw Error(`Unsupported replay engine/version`);if(!Array.isArray(t.commands)||t.commands.length>5e5||!Array.isArray(t.checkpoints)||t.checkpoints.length>721||!Number.isInteger(t.end)||t.end<t.initial.tick||t.end-t.initial.tick>216e3)throw Error(`Invalid replay bounds`);let n=t.initial.tick;for(let e of t.commands){if(!Number.isInteger(e.tick)||e.tick<n||e.tick>t.end||![`input`,`team`,`start`,`stop`,`pause`,`scoreLimit`,`timeLimit`,`kickRate`,`join`,`disc`,`surface`].includes(e.kind)||e.kind===`surface`&&e.slot!==0||!Number.isInteger(e.slot)||e.slot<0||e.slot>(e.kind===`disc`?95:31)||!Number.isInteger(e.value)||e.value<0||e.value>(e.kind===`disc`||e.kind===`join`?0:e.kind===`kickRate`?6619135:e.kind===`timeLimit`?5940:e.kind===`scoreLimit`?99:e.kind===`team`?2:e.kind===`pause`||e.kind===`surface`?1:31))throw Error(`Invalid replay command`);e.kind===`disc`&&(e.properties=_t(e.properties)),n=e.tick}if(!Array.isArray(t.roster)||t.roster.length>4096)throw Error(`Invalid replay roster`);n=t.initial.tick;for(let e of t.roster){if(!Number.isInteger(e.tick)||e.tick<n||e.tick>t.end||!Number.isInteger(e.slot)||e.slot<0||e.slot>31||e.name!==null&&(typeof e.name!=`string`||e.name.length>24)||e.avatar!==void 0&&!ht(e.avatar))throw Error(`Invalid roster event`);n=e.tick}if(t.styles!==void 0){if(!Array.isArray(t.styles)||t.styles.length>4096)throw Error(`Invalid replay styles`);let e=t.initial.tick;for(let n of t.styles){if(!n||!Number.isInteger(n.tick)||n.tick<e||n.tick>t.end||n.teams===void 0)throw Error(`Invalid replay style`);n.teams=ft(n.teams),e=n.tick}}if(t.orders!==void 0){if(!Array.isArray(t.orders)||t.orders.length>4096)throw Error(`Invalid replay orders`);let e=t.initial.tick;for(let n of t.orders){if(!n||!Number.isInteger(n.tick)||n.tick<e||n.tick>t.end||!Array.isArray(n.slots)||n.slots.length>32||n.slots.some(e=>!Number.isInteger(e)||e<0||e>31)||new Set(n.slots).size!==n.slots.length)throw Error(`Invalid replay order`);e=n.tick}}let r=t.initial.tick;for(let e of t.checkpoints){if(!Number.isInteger(e.tick)||e.tick<=r||e.tick>t.end||e.state.tick!==e.tick||typeof e.hash!=`string`)throw Error(`Invalid checkpoint`);r=e.tick}return t}var Vn=e=>Number.isSafeInteger(e)&&e>0&&e<=9e4,Hn=class{io;state=`admitted`;currentEpoch=0;membershipDeadline;recoveryDeadline=1/0;phaseDeadline=1/0;attemptId;retry=0;timer;timerVersion=0;transport;constructor(e,t){if(this.io=e,!Vn(t))throw RangeError(`Invalid membership duration`);this.membershipDeadline=e.now()+t,this.arm()}get epoch(){return this.currentEpoch}get status(){return this.state}disconnected(e){e!==this.currentEpoch||this.terminal()||this.checkExpiry()||(this.state===`admitted`?(this.recoveryDeadline=Math.min(this.io.now()+3e4,this.membershipDeadline),this.attemptId=this.io.newAttemptId(),this.retry=0,this.wait()):(this.state===`connecting`||this.state===`awaiting-ack`)&&this.wait())}acknowledge(e,t){if(e!==this.currentEpoch||this.state!==`awaiting-ack`||t!==void 0&&!Vn(t)||this.checkExpiry()||this.checkAttemptTimeout())return!1;t!==void 0&&(this.membershipDeadline=Math.min(this.membershipDeadline,this.io.now()+t));let n={attemptId:this.attemptId,epoch:e};return this.state=`admitted`,this.recoveryDeadline=1/0,this.phaseDeadline=1/0,this.attemptId=void 0,this.retry=0,this.arm(),this.io.onRecovered(n),!0}heartbeat(e,t){return e!==this.currentEpoch||this.state!==`admitted`||!Vn(t)||this.checkExpiry()?!1:(this.membershipDeadline=this.io.now()+t,this.arm(),!0)}cancel(){this.terminal()||(this.state=`cancelled`,this.clearTimer(),this.retire())}terminal(){return this.state===`expired`||this.state===`cancelled`}retire(){let e=this.transport;this.transport=void 0;try{e?.close()}catch{}}clearTimer(){this.timerVersion++,this.timer!==void 0&&this.io.clearTimer(this.timer),this.timer=void 0}checkExpiry(){if(this.terminal())return!0;let e=this.io.now(),t=e>=this.membershipDeadline;return!t&&e<this.recoveryDeadline?!1:(this.state=`expired`,this.clearTimer(),this.retire(),this.io.onExpired(t?`membership`:`recovery`),!0)}checkAttemptTimeout(){return(this.state===`connecting`||this.state===`awaiting-ack`)&&this.io.now()>=this.phaseDeadline&&(this.wait(),!0)}wait(){this.state=`waiting`,this.retire();let e=this.io.random(),t=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.5,n=Math.min(4e3,250*2**Math.min(this.retry++,4));this.phaseDeadline=this.io.now()+n*(.75+t*.25),this.arm()}arm(){if(this.clearTimer(),this.terminal())return;let e=this.timerVersion,t=Math.min(this.membershipDeadline,this.recoveryDeadline,this.phaseDeadline);this.timer=this.io.setTimer(()=>{if(!(e!==this.timerVersion||this.checkExpiry())){if(this.timer=void 0,this.io.now()<this.phaseDeadline){this.arm();return}this.state===`waiting`?this.attempt():this.state===`connecting`||this.state===`awaiting-ack`?this.wait():this.arm()}},Math.max(0,t-this.io.now()))}attempt(){if(this.checkExpiry())return;this.state=`connecting`;let e=++this.currentEpoch;this.phaseDeadline=this.io.now()+5e3,this.arm();let t;try{t=this.io.createAttempt({attemptId:this.attemptId,epoch:e},{opened:()=>{e!==this.currentEpoch||this.state!==`connecting`||this.checkExpiry()||this.checkAttemptTimeout()||(this.state=`awaiting-ack`)},closed:()=>this.disconnected(e)})}catch{e===this.currentEpoch&&this.disconnected(e);return}if(e===this.currentEpoch&&(this.state===`connecting`||this.state===`awaiting-ack`||this.state===`admitted`))this.transport=t;else try{t.close()}catch{}}};function Un(e,t){return typeof e==`object`&&!!e&&!Array.isArray(e)&&Object.keys(e).length===t.length&&t.every(t=>Object.hasOwn(e,t))}var Wn=e=>typeof e==`string`&&/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(e),Gn=e=>typeof e==`string`&&/^[0-9a-f]{64}$/.test(e),Kn=(e,t)=>Number.isSafeInteger(e)&&e>=t,qn=e=>Kn(e,1)&&e<=9e4,Jn=e=>e===`host`||e===`guest`;function Yn(e){return!Un(e,[`version`,`roomGeneration`,`secret`,`connectionEpoch`,`membershipValidForMs`])||e.version!==2||!Wn(e.roomGeneration)||!Gn(e.secret)||!Kn(e.connectionEpoch,1)||!qn(e.membershipValidForMs)?null:{version:2,roomGeneration:e.roomGeneration,secret:e.secret,connectionEpoch:e.connectionEpoch,membershipValidForMs:e.membershipValidForMs}}function Xn(e){if(!Un(e,[`type`,`version`,`roomGeneration`,`attemptId`,`id`,`hostId`,`role`,`connectionEpoch`,`membershipValidForMs`,`rosterRevision`,`members`,`requireVerification`,`locked`])||e.type!==`resumed`||e.version!==2||!Wn(e.roomGeneration)||!Wn(e.attemptId)||!Wn(e.id)||!Wn(e.hostId)||!Jn(e.role)||!Kn(e.connectionEpoch,1)||!qn(e.membershipValidForMs)||!Kn(e.rosterRevision,0)||typeof e.requireVerification!=`boolean`||typeof e.locked!=`boolean`||!Array.isArray(e.members)||e.members.length<1||e.members.length>33)return null;let t=Qn(e.members,e.hostId);return!t||!t.some(t=>t.id===e.id&&t.role===e.role&&t.attached&&t.connectionEpoch===e.connectionEpoch)?null:{type:`resumed`,version:2,roomGeneration:e.roomGeneration,attemptId:e.attemptId,id:e.id,hostId:e.hostId,role:e.role,connectionEpoch:e.connectionEpoch,membershipValidForMs:e.membershipValidForMs,rosterRevision:e.rosterRevision,members:t,requireVerification:e.requireVerification,locked:e.locked}}function Zn(e){if(!Un(e,[`type`,`id`,`hostId`,`role`,`resumeGrant`,`rosterRevision`,`members`,`requireVerification`,`locked`])||e.type!==`ready`)return null;let t=Yn(e.resumeGrant);if(!t)return null;let n=Xn({type:`resumed`,version:2,roomGeneration:t.roomGeneration,attemptId:t.roomGeneration,id:e.id,hostId:e.hostId,role:e.role,connectionEpoch:t.connectionEpoch,membershipValidForMs:t.membershipValidForMs,rosterRevision:e.rosterRevision,members:e.members,requireVerification:e.requireVerification,locked:e.locked});return n?{type:`ready`,id:n.id,hostId:n.hostId,role:n.role,resumeGrant:t,rosterRevision:n.rosterRevision,members:n.members,requireVerification:n.requireVerification,locked:n.locked}:null}function Qn(e,t){if(!Array.isArray(e)||e.length<1||e.length>33)return null;let n=[],r=new Set;for(let t of e){if(!Un(t,[`id`,`role`,`attached`,`connectionEpoch`])||!Wn(t.id)||!Jn(t.role)||typeof t.attached!=`boolean`||!Kn(t.connectionEpoch,1)||r.has(t.id))return null;r.add(t.id),n.push({id:t.id,role:t.role,attached:t.attached,connectionEpoch:t.connectionEpoch})}let i=n.filter(e=>e.role===`host`);return i.length===1&&i[0].id===t?n:null}function $n(e){if(!Un(e,[`type`,`roomGeneration`,`hostId`,`rosterRevision`,`members`])||e.type!==`roster`||!Wn(e.roomGeneration)||!Wn(e.hostId)||!Kn(e.rosterRevision,0))return null;let t=Qn(e.members,e.hostId);return t?{type:`roster`,roomGeneration:e.roomGeneration,hostId:e.hostId,rosterRevision:e.rosterRevision,members:t}:null}function er(e){let t=[...e],n=new Set(t.filter(e=>e.type===`transport`&&e.selectedCandidatePairId).map(e=>e.selectedCandidatePairId)),r=t.filter(e=>e.type===`candidate-pair`&&e.state===`succeeded`),i=n.size?r.filter(e=>n.has(e.id)):r.filter(e=>e.nominated===!0);if(i.length!==1)return null;let a=i[0].currentRoundTripTime;return typeof a==`number`&&Number.isFinite(a)&&a>=0?a*1e3:null}var tr=524288,nr=16384,rr=12;function ir(e,t){let n=JSON.stringify(e);if(n===void 0)throw Error(`Missing control message`);let r=new TextEncoder().encode(n);if(r.length>tr)throw Error(`Control message exceeds 512 KB`);if(r.length<=nr)return[n];let i=Math.ceil(r.length/nr),a=[];for(let e=0;e<i;e++){let n=r.subarray(e*nr,(e+1)*nr),o=new ArrayBuffer(rr+n.length),s=new DataView(o);s.setUint16(0,45635),s.setUint8(2,1),s.setUint32(4,t,!0),s.setUint16(8,e,!0),s.setUint16(10,i,!0),new Uint8Array(o,rr).set(n),a.push(o)}return a}var ar=class{partial;push(e,t=performance.now()){if(typeof e==`string`){if(this.partial||new TextEncoder().encode(e).length>nr)throw Error(`Invalid control message`);return JSON.parse(e)}if(e.byteLength<13||e.byteLength>16396)throw Error(`Control fragment length`);let n=new DataView(e);if(n.getUint16(0)!==45635||n.getUint8(2)!==1||n.getUint8(3)!==0)throw Error(`Control fragment version`);let r=n.getUint32(4,!0),i=n.getUint16(8,!0),a=n.getUint16(10,!0);if(a<2||a>32||i>=a)throw Error(`Control fragment bounds`);if(!this.partial){if(i!==0)throw Error(`Missing first fragment`);this.partial={id:r,count:a,next:0,bytes:0,parts:[],since:t}}let o=this.partial;if(o.id!==r||o.count!==a||o.next!==i||t-o.since>1e4)throw Error(`Control fragment sequence`);if(o.next++,o.bytes+=e.byteLength-rr,o.bytes>tr)throw Error(`Control size limit`);if(o.parts.push(new Uint8Array(e.slice(rr))),o.next!==a)return;let s=new Uint8Array(o.bytes),c=0;for(let e of o.parts)s.set(e,c),c+=e.length;return this.partial=void 0,JSON.parse(new TextDecoder(`utf-8`,{fatal:!0}).decode(s))}},or=class extends Error{},sr=1,cr=e=>typeof e==`string`&&/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/.test(e),lr=e=>Number.isSafeInteger(e)&&e>0,ur=e=>e?.match(/(?:^|\r?\n)a=ice-ufrag:([^\s]+)/)?.[1],dr=e=>e.usernameFragment??e.candidate?.match(/(?:^| )ufrag ([^ ]+)/)?.[1],fr=class{room;credentials;hooks;runtime;ws;peers=new Map;id=``;host=!1;hostId=``;closed=!1;timer;bytesSent=0;bytesReceived=0;pollingStats=!1;resumeGrant;recovery;resumeAttempt;socketSerial=0;requestSentAt=0;rosterRevision=-1;members=new Map;lockedState=null;get locked(){return this.lockedState}heartbeatSequence=0;heartbeatRequest;heartbeatTimer;heartbeatTimerVersion=0;heartbeatDeadline=0;cancelHeartbeat(){clearTimeout(this.heartbeatTimer),this.heartbeatTimer=void 0,this.heartbeatTimerVersion++,this.heartbeatRequest=void 0}armHeartbeat(e){clearTimeout(this.heartbeatTimer);let t=++this.heartbeatTimerVersion;this.heartbeatTimer=setTimeout(()=>{t===this.heartbeatTimerVersion&&(this.heartbeatTimer=void 0,this.sendHeartbeat())},e)}scheduleHeartbeat(e,t){this.cancelHeartbeat();let n=performance.now()+e;this.heartbeatDeadline=t?n:Math.min(this.heartbeatDeadline,n);let r=this.heartbeatDeadline-performance.now();r>0&&this.signalingReady&&this.armHeartbeat(Math.max(1,Math.floor(Math.min(3e4,r/3))))}sendHeartbeat(){let e=this.heartbeatDeadline-performance.now();if(!this.signalingReady||!this.resumeGrant||!this.recovery||e<=0)return;let t=this.heartbeatRequest??={id:++this.heartbeatSequence,sentAt:performance.now(),localEpoch:this.recovery.epoch,transmissions:0,retryDelay:Math.max(1,Math.floor(Math.min(5e3,e/3)))};if(!(t.transmissions>=3)){t.transmissions++;try{this.signal({type:`heartbeat`,requestId:t.id,connectionEpoch:this.resumeGrant.connectionEpoch})}catch{}this.heartbeatRequest===t&&this.signalingReady&&t.transmissions<3&&t.retryDelay<e&&this.armHeartbeat(t.retryDelay)}}get signalingReady(){return!this.closed&&!!this.id&&this.ws.readyState===sr&&this.signalingAdmitted}get signalingAdmitted(){return!this.recovery||this.recovery.status===`admitted`}verificationState=null;get requireVerification(){return this.verificationState}verificationSequence=0;verificationRequest;challenge;rejectVerification(e,t=!0){let n=this.verificationRequest;n&&(this.verificationRequest=void 0,clearTimeout(n.timer),t&&(this.verificationState=null),n.reject(Error(e)))}setRequireVerification(e){return typeof e==`boolean`?this.closed||!this.host||!this.signalingAdmitted||this.ws.readyState!==sr?Promise.reject(Error(`An active room-owner connection is required.`)):this.verificationRequest?Promise.reject(Error(`A verification update is already pending.`)):new Promise((t,n)=>{let r=++this.verificationSequence,i=setTimeout(()=>this.rejectVerification(`Verification update was not confirmed.`),1e4);this.verificationRequest={id:r,timer:i,resolve:t,reject:n};try{this.signal({type:`setVerification`,required:e,requestId:r})}catch{this.rejectVerification(`Verification update could not be sent.`)}}):Promise.reject(Error(`Expected a boolean.`))}passwordRequestId=0;passwordRequest;rejectPasswordUpdate(e){let t=this.passwordRequest;t&&(this.passwordRequest=void 0,clearTimeout(t.timer),t.reject(Error(e)))}setPassword(e){return e!==null&&(typeof e!=`string`||e.length>64)?Promise.reject(Error(`Password must contain at most 64 characters.`)):this.closed||!this.host||!this.signalingAdmitted||this.ws.readyState!==sr?Promise.reject(Error(`An active room-owner connection is required.`)):this.passwordRequest?Promise.reject(Error(`A password update is already pending.`)):new Promise((t,n)=>{let r=++this.passwordRequestId,i=setTimeout(()=>this.rejectPasswordUpdate(`Password update was not confirmed.`),1e4);this.passwordRequest={id:r,timer:i,resolve:t,reject:n};try{this.signal({type:`setPassword`,requestId:r,password:e??``})}catch{this.rejectPasswordUpdate(`Password update could not be sent.`)}})}banSequence=0;banRequest;rejectBan(e,t=!0){let n=this.banRequest;n&&(this.banRequest=void 0,clearTimeout(n.timer),n.reject(t?new or(e):Error(e)))}updateBan(e,t){return this.closed||!this.host||!this.signalingAdmitted||this.ws.readyState!==sr?Promise.reject(Error(`An active room-owner connection is required.`)):this.banRequest?Promise.reject(Error(`A ban operation is already pending.`)):new Promise((n,r)=>{let i=++this.banSequence,a=setTimeout(()=>this.rejectBan(`Ban operation was not confirmed.`),1e4);this.banRequest={id:i,resolve:n,reject:r,timer:a};try{this.signal({type:e,id:t,requestId:i})}catch{this.rejectBan(`Ban operation could not be sent.`)}})}get rtt(){let e=[...this.peers.values()].filter(e=>e.connected&&e.lostAt===void 0).map(e=>e.rtt).filter(e=>typeof e==`number`);return e.length?Math.max(...e):null}signalQueue=Promise.resolve();lastHeartbeat=0;controlId=0;controlAssemblers=new Map;constructor(e,t,n,r=yn()){this.room=e,this.credentials=t,this.hooks=n,this.runtime=r;let i=new URL(`/api/rooms/${encodeURIComponent(e)}/signal`,vn(r.serviceOrigin));i.protocol=i.protocol===`https:`?`wss:`:`ws:`,this.ws=r.createWebSocket(i),this.attachSocket(this.ws,()=>{this.requestSentAt=performance.now(),this.signal({type:`hello`,...t,...r.signalingResume?{signalingVersion:2}:{}})},0),this.timer=setInterval(()=>{!this.resumeGrant&&this.signalingAdmitted&&this.ws.readyState===sr&&performance.now()-this.lastHeartbeat>=3e4&&(this.signal({type:`heartbeat`}),this.lastHeartbeat=performance.now());for(let e of this.peers.values()){if(!e.connected&&performance.now()-e.created>2e4){n.status(`Direct connection failed. This network pair may require a relay; this game does not use TURN.`),this.remove(e.id);continue}e.lostAt!==void 0&&(performance.now()-e.lostAt>2e4?(n.status(`The direct connection could not be recovered. Rejoin the room.`),this.remove(e.id)):this.host&&performance.now()-e.lastRestart>5e3&&this.restartPeer(e.id))}},5e3)}attachSocket(e,t,n){let r=++this.socketSerial,i=()=>!this.closed&&this.ws===e&&this.socketSerial===r;e.onopen=()=>{i()&&t()},e.onmessage=e=>{i()&&(this.signalQueue=this.signalQueue.then(async()=>{i()&&await this.message(JSON.parse(e.data),r)}).catch(()=>{i()&&this.hooks.status(`Connection negotiation failed. Try another room or network.`)}))},e.onclose=e=>{if(i()){if(this.socketSerial++,this.challenge?.abort(),this.cancelHeartbeat(),this.rejectVerification(`Signaling disconnected before verification confirmation.`),this.rejectBan(`Signaling disconnected before ban confirmation.`),this.rejectPasswordUpdate(`Signaling disconnected before password confirmation.`),this.recovery&&this.resumeGrant&&![1e3,1008,1009].includes(e.code)){this.recovery.disconnected(n),this.hooks.status(`Signaling interrupted. Reconnecting…`);return}if(!this.id||this.recovery||[1001,1008,1009].includes(e.code)){this.close(),this.hooks.ended?.(e.reason||`Room connection ended.`);return}this.hooks.status(e.reason||`Signaling disconnected. Established matches can continue; new joins are unavailable.`)}},e.onerror=()=>{i()&&this.hooks.status(`Room service is unavailable.`)}}startRecovery(e){let t=Math.floor(e.membershipValidForMs-(performance.now()-this.requestSentAt));if(t<=0){this.close(),this.hooks.ended?.(`Room membership expired.`);return}this.resumeGrant=e,this.recovery=new Hn({now:()=>performance.now(),setTimer:(e,t)=>setTimeout(e,t),clearTimer:e=>clearTimeout(e),random:()=>Math.random(),newAttemptId:()=>crypto.randomUUID(),createAttempt:(e,t)=>{this.resumeAttempt=e;let n=new URL(`/api/rooms/${encodeURIComponent(this.room)}/signal`,vn(this.runtime.serviceOrigin));n.protocol=n.protocol===`https:`?`wss:`:`ws:`;let r=this.runtime.createWebSocket(n);return this.ws=r,this.attachSocket(r,()=>{t.opened(),this.recovery?.status===`awaiting-ack`&&(this.requestSentAt=performance.now(),r.send(JSON.stringify({type:`resume`,version:2,roomGeneration:this.resumeGrant.roomGeneration,peerId:this.id,secret:this.resumeGrant.secret,attemptId:e.attemptId,expectedEpoch:this.resumeGrant.connectionEpoch})))},e.epoch),{close:()=>{this.ws===r&&this.socketSerial++,r.onopen=null,r.onmessage=null,r.onclose=null,r.onerror=null,r.close()}}},onExpired:()=>{this.close(),this.hooks.ended?.(`Room signaling recovery expired.`)},onRecovered:()=>{}},t),this.scheduleHeartbeat(t,!0)}signal(e){!this.closed&&this.signalingAdmitted&&this.ws.readyState===sr&&this.ws.send(JSON.stringify(e))}async message(e,t=this.socketSerial){if(this.closed||t!==this.socketSerial)return;if(e.type===`resumed`){let n=Xn(e),r=this.resumeGrant,i=this.resumeAttempt;if(!n||!r||!i||!this.recovery||n.roomGeneration!==r.roomGeneration||n.attemptId!==i.attemptId||n.id!==this.id||n.hostId!==this.hostId||n.role===`host`!==this.host||n.connectionEpoch<=r.connectionEpoch||n.rosterRevision<this.rosterRevision||n.members.some(e=>e.connectionEpoch<(this.members.get(e.id)?.connectionEpoch??0)))return;let a=Math.floor(n.membershipValidForMs-(performance.now()-this.requestSentAt));if(a<=0||!this.recovery.acknowledge(i.epoch,a))return;this.resumeGrant={...r,connectionEpoch:n.connectionEpoch,membershipValidForMs:a},this.resumeAttempt=void 0,this.scheduleHeartbeat(a,!1),this.verificationState=n.requireVerification,this.lockedState=n.locked,this.reconcile(n.members,n.rosterRevision,t),this.hooks.status(`Room signaling restored.`);return}if(e.type===`heartbeat`&&this.resumeGrant&&this.recovery){let t=this.heartbeatRequest;if(!t||e.requestId!==t.id||e.connectionEpoch!==this.resumeGrant.connectionEpoch||!Number.isSafeInteger(e.membershipValidForMs)||e.membershipValidForMs<1||e.membershipValidForMs>9e4)return;let n=Math.floor(e.membershipValidForMs-(performance.now()-t.sentAt));n>0&&this.recovery.heartbeat(t.localEpoch,n)&&this.scheduleHeartbeat(n,!0);return}if(this.recovery&&!this.signalingAdmitted)return;if(e.type===`roster`&&this.resumeGrant){let n=$n(e);if(!n||n.roomGeneration!==this.resumeGrant.roomGeneration||n.hostId!==this.hostId||n.rosterRevision<=this.rosterRevision)return;let r=n.members.find(e=>e.id===this.id);if(!r||!r.attached||r.connectionEpoch!==this.resumeGrant.connectionEpoch||r.role===`host`!==this.host){this.close(),this.hooks.ended?.(`Room membership ended.`);return}if(n.members.some(e=>e.connectionEpoch<(this.members.get(e.id)?.connectionEpoch??0)))return;this.reconcile(n.members,n.rosterRevision,t);return}if(e.type===`verificationUpdated`&&this.verificationRequest&&this.verificationRequest.id===e.requestId){if(e.ok!==!0||typeof e.required!=`boolean`)this.rejectVerification(typeof e.error==`string`?e.error:`Verification update failed.`,e.ok!==!1);else{let t=this.verificationRequest;this.verificationRequest=void 0,clearTimeout(t.timer),this.verificationState=e.required,t.resolve(e.required)}return}if(e.type===`verificationRequired`){if(this.closed||this.id||this.credentials.hostToken||this.challenge||e.roomId!==this.room||typeof e.siteKey!=`string`||!/^[A-Za-z0-9_-]{1,100}$/.test(e.siteKey))return;if(!this.hooks.verify){this.close(),this.hooks.ended?.(`This client cannot complete the room verification challenge.`);return}let t=new AbortController;this.challenge=t;try{let n=await this.hooks.verify({siteKey:e.siteKey,roomId:this.room},t.signal);if(t.signal.aborted||this.closed||this.ws.readyState!==sr)return;if(typeof n!=`string`||n.length===0||n.length>2048)throw Error(`Invalid verification response.`);this.requestSentAt=performance.now(),this.signal({type:`hello`,...this.credentials,verificationToken:n,...this.runtime.signalingResume?{signalingVersion:2}:{}})}catch(e){this.closed||(this.close(),this.hooks.ended?.(e instanceof Error?e.message:`Room verification failed.`))}finally{this.challenge===t&&(this.challenge=void 0)}return}if(e.type===`passwordUpgradeRequired`&&this.host){this.hooks.status(`Update the room password or explicitly unlock it to allow new guests.`);return}if(e.type===`passwordUpdated`&&e.ok===!1&&this.passwordRequest?.id===e.requestId){this.rejectPasswordUpdate(typeof e.error==`string`?e.error:`Password update failed.`);return}if(e.type===`passwordUpdated`&&typeof e.locked==`boolean`&&this.passwordRequest&&this.passwordRequest.id===e.requestId){let t=this.passwordRequest;this.passwordRequest=void 0,clearTimeout(t.timer),t.resolve(e.locked);return}if(e.type===`banResult`&&this.banRequest&&this.banRequest.id===e.requestId){if(e.ok!==!0)this.rejectBan(typeof e.error==`string`?e.error:`Ban operation failed.`,!1);else{let e=this.banRequest;this.banRequest=void 0,clearTimeout(e.timer),e.resolve()}return}if(e.type===`ready`){if(this.id)return;if(this.runtime.signalingResume&&e.resumeGrant!==void 0){let t=Zn(e);if(!t){this.close(),this.hooks.ended?.(`Invalid room admission.`);return}if(this.id=t.id,this.host=t.role===`host`,this.hostId=t.hostId,this.verificationState=t.requireVerification,this.lockedState=t.locked,this.startRecovery(t.resumeGrant),this.closed)return;this.members=new Map(t.members.map(e=>[e.id,e])),this.rosterRevision=t.rosterRevision}else this.id=e.id,this.host=e.role===`host`,this.hostId=e.hostId,this.verificationState=typeof e.requireVerification==`boolean`?e.requireVerification:null;this.hooks.ready(this.id,this.host),this.resumeGrant&&this.reconcile([...this.members.values()],this.rosterRevision,t);return}if(e.type===`peer`||e.type===`leave`){if(this.resumeGrant){if(!cr(e.id)||!lr(e.connectionEpoch)||!Number.isSafeInteger(e.rosterRevision)||e.rosterRevision<=this.rosterRevision||e.id===this.id)return;let t=this.members.get(e.id);if(t&&e.connectionEpoch<t.connectionEpoch)return;this.rosterRevision=e.rosterRevision,e.type===`peer`?this.members.set(e.id,{id:e.id,role:e.id===this.hostId?`host`:`guest`,attached:!0,connectionEpoch:e.connectionEpoch}):this.members.delete(e.id)}if(e.type===`leave`){this.remove(e.id,!1);return}this.host&&!this.peers.has(e.id)&&await this.offerPeer(e.id,t);return}if(e.type!==`signal`||this.resumeGrant&&(!cr(e.negotiationId)||e.toConnectionEpoch!==this.resumeGrant.connectionEpoch||e.fromConnectionEpoch!==this.members.get(e.from)?.connectionEpoch||!this.members.get(e.from)?.attached))return;let n=this.peers.get(e.from);if(!n){if(this.host||e.from!==this.hostId||![`offer`,`candidate`].includes(e.signal.type))return;n=this.make(e.from)}if(this.resumeGrant){if(e.signal.type===`offer`){if(this.host||!ur(e.signal.sdp))return;n.negotiationId!==e.negotiationId&&(n.candidates=[]),this.beginNegotiation(n,e.negotiationId),n.remoteIceUfrag=ur(e.signal.sdp),n.localIceUfrag=void 0}else if(e.signal.type===`candidate`&&!n.negotiationId&&!this.host)this.beginNegotiation(n,e.negotiationId);else if(n.negotiationId!==e.negotiationId)return;if(n.negotiationLocalEpoch!==e.toConnectionEpoch||n.negotiationRemoteEpoch!==e.fromConnectionEpoch)return;if(e.signal.type===`answer`){if(!ur(e.signal.sdp))return;n.remoteIceUfrag=ur(e.signal.sdp)}}let r=n.negotiationId,i=()=>this.current(n)&&t===this.socketSerial&&this.signalingAdmitted&&n.negotiationId===r&&this.negotiationCurrent(n);if(e.signal.type===`offer`){if(this.host)throw Error(`Only the host can offer`);if(await n.pc.setRemoteDescription({type:`offer`,sdp:e.signal.sdp}),!i()||(await this.flushCandidates(n,i),!i()))return;let t=await n.pc.createAnswer();if(!i()||(n.localIceUfrag=ur(t.sdp),await n.pc.setLocalDescription(t),!i()))return;this.peerSignal(n,{type:`answer`,sdp:n.pc.localDescription.sdp})}else if(e.signal.type===`answer`){if(!this.host)throw Error(`Only guests can answer`);if(await n.pc.setRemoteDescription({type:`answer`,sdp:e.signal.sdp}),!i())return;await this.flushCandidates(n,i),this.noteHealthy(n)}else if(e.signal.type===`candidate`&&e.signal.candidate){if(this.resumeGrant&&(!dr(e.signal.candidate)||n.remoteIceUfrag&&dr(e.signal.candidate)!==n.remoteIceUfrag))return;if(!n.pc.remoteDescription)this.queueCandidate(n,e.signal.candidate);else try{await n.pc.addIceCandidate(e.signal.candidate)}catch{i()&&this.queueCandidate(n,e.signal.candidate)}}}reconcile(e,t,n){this.members=new Map(e.map(e=>[e.id,e])),this.rosterRevision=t;for(let e of[...this.peers.keys()])this.members.has(e)||this.remove(e,!1);if(this.host)for(let t of e)t.id!==this.id&&t.attached&&!this.peers.has(t.id)&&this.offerPeer(t.id,n).catch(()=>{!this.closed&&n===this.socketSerial&&this.hooks.status(`Connection negotiation failed.`)})}negotiationCurrent(e){return!this.resumeGrant||e.negotiationLocalEpoch===this.resumeGrant.connectionEpoch&&e.negotiationRemoteEpoch===this.members.get(e.id)?.connectionEpoch&&this.members.get(e.id)?.attached===!0}beginNegotiation(e,t){e.negotiationId=t,e.negotiationLocalEpoch=this.resumeGrant?.connectionEpoch,e.negotiationRemoteEpoch=this.members.get(e.id)?.connectionEpoch}peerSignal(e,t){let n=this.resumeGrant,r=this.members.get(e.id);(!n||r?.attached&&e.negotiationId&&this.signalingAdmitted&&e.negotiationLocalEpoch===n.connectionEpoch&&e.negotiationRemoteEpoch===r.connectionEpoch)&&this.signal({type:`signal`,to:e.id,signal:t,...n?{fromConnectionEpoch:n.connectionEpoch,toConnectionEpoch:r.connectionEpoch,negotiationId:e.negotiationId}:{}})}async offerPeer(e,t){let n=this.make(e);this.bind(n,n.pc.createDataChannel(`control`,{ordered:!0})),this.bind(n,n.pc.createDataChannel(`realtime`,{ordered:!1,maxRetransmits:0})),this.resumeGrant&&this.beginNegotiation(n,crypto.randomUUID());let r=n.negotiationId,i=()=>this.current(n)&&t===this.socketSerial&&this.signalingAdmitted&&n.negotiationId===r&&this.negotiationCurrent(n),a=await n.pc.createOffer();i()&&(n.localIceUfrag=ur(a.sdp),await n.pc.setLocalDescription(a),i()&&this.peerSignal(n,{type:`offer`,sdp:n.pc.localDescription.sdp}))}current(e){return!this.closed&&this.peers.get(e.id)===e}queueCandidate(e,t){if(this.current(e)){if(e.candidates.length>=128)throw Error(`Too many pending ICE candidates`);e.candidates.push(t)}}noteHealthy(e){if(!this.current(e)||e.pc.connectionState!==`connected`||![`connected`,`completed`].includes(e.pc.iceConnectionState))return;let t=e.lostAt!==void 0;e.lostAt=void 0,e.restarts=0,t&&this.hooks.status(`Direct connection restored.`)}async flushCandidates(e,t=()=>this.current(e)){let n=e.candidates.splice(0);for(let r of n){if(!t())return;if(!this.resumeGrant||e.remoteIceUfrag&&dr(r)===e.remoteIceUfrag)try{await e.pc.addIceCandidate(r)}catch{}}}async restartPeer(e){let t=this.peers.get(e);if(this.closed||!this.host||!t||t.restarting||t.restarts>=2||t.pc.signalingState!==`stable`||!this.signalingAdmitted||this.ws.readyState!==sr)return!1;let n=this.socketSerial;this.resumeGrant&&(this.beginNegotiation(t,crypto.randomUUID()),t.localIceUfrag=void 0,t.remoteIceUfrag=void 0,t.candidates=[]);let r=t.negotiationId,i=()=>this.current(t)&&n===this.socketSerial&&this.signalingAdmitted&&t.negotiationId===r&&this.negotiationCurrent(t);t.restarting=!0,t.lastRestart=performance.now(),t.lostAt??=t.lastRestart,t.restarts++;try{let e=await t.pc.createOffer({iceRestart:!0});return!i()||(t.localIceUfrag=ur(e.sdp),await t.pc.setLocalDescription(e),!i())?!1:(this.peerSignal(t,{type:`offer`,sdp:t.pc.localDescription.sdp}),!0)}catch{return!this.closed&&this.peers.get(e)===t&&this.hooks.status(`Direct connection recovery is still pending.`),!1}finally{t.restarting=!1}}make(e){let t=this.runtime.createPeerConnection({iceServers:[{urls:`stun:stun.l.google.com:19302`}],bundlePolicy:`max-bundle`}),n={id:e,pc:t,connected:!1,created:performance.now(),candidates:[],lastRestart:0,restarts:0,restarting:!1};this.peers.set(e,n),t.onicecandidate=e=>{if(!this.current(n)||!e.candidate||!this.signalingAdmitted)return;let t=e.candidate.toJSON();(!this.resumeGrant||n.localIceUfrag&&dr(t)===n.localIceUfrag)&&this.peerSignal(n,{type:`candidate`,candidate:t})},t.ondatachannel=e=>this.bind(n,e.channel);let r=()=>{this.closed||this.peers.get(e)!==n||(t.connectionState===`closed`?(this.hooks.status(`A peer disconnected.`),this.remove(e)):t.connectionState===`connected`&&[`connected`,`completed`].includes(t.iceConnectionState)?this.noteHealthy(n):([`failed`,`disconnected`].includes(t.connectionState)||[`failed`,`disconnected`].includes(t.iceConnectionState))&&(n.lostAt??=performance.now(),this.hooks.status(`Direct connection interrupted. Attempting recovery…`)))};return t.onconnectionstatechange=r,t.oniceconnectionstatechange=r,n}bind(e,t){if(this.closed||this.peers.get(e.id)!==e||![`control`,`realtime`].includes(t.label)){t.close();return}if(t.maxPacketLifeTime!==null||t.label===`control`&&(t.ordered!==!0||t.maxRetransmits!==null)||t.label===`realtime`&&(t.ordered!==!1||t.maxRetransmits!==0)||(t.label===`control`?e.control:e.fast)){t.close(),this.remove(e.id);return}t.binaryType=`arraybuffer`,t.label===`control`?e.control=t:e.fast=t,t.onclose=()=>{!this.closed&&this.peers.get(e.id)===e&&(this.hooks.status(`A peer closed its game channel.`),this.remove(e.id))},t.onopen=()=>{this.closed||this.peers.get(e.id)!==e||e.control?.readyState===`open`&&e.fast?.readyState===`open`&&!e.connected&&(e.connected=!0,this.host&&(e.admissionTimer=setTimeout(()=>{this.closed||this.peers.get(e.id)!==e||(this.hooks.status(`A peer did not complete room admission.`),this.remove(e.id))},1e4)),this.hooks.open(e))},t.onmessage=n=>{if(!(this.closed||this.peers.get(e.id)!==e)){this.bytesReceived+=typeof n.data==`string`?n.data.length:n.data.byteLength;try{if(t.label===`control`){let t=typeof n.data!=`string`||new TextEncoder().encode(n.data).length>4096;if(this.host&&t&&!this.hooks.allowStadiumUpload?.(e))throw Error(`Guest control size or permission`);if(typeof n.data!=`string`&&!(n.data instanceof ArrayBuffer))throw Error(`Invalid control type`);let r=this.controlAssemblers.get(e.id);r||(r=new ar,this.controlAssemblers.set(e.id,r));let i=r.push(n.data);if(i!==void 0){if(this.host&&t&&(!i||typeof i!=`object`||i.type!==`action`||i.action!==`customStadium`))throw Error(`Invalid bulk action`);this.hooks.control(e,i)}}else if(n.data instanceof ArrayBuffer&&n.data.byteLength<=1200)this.hooks.fast(e,n.data);else throw Error()}catch{this.hooks.status(`Invalid peer message rejected.`),this.remove(e.id)}}}}admit(e){clearTimeout(e.admissionTimer),e.admissionTimer=void 0}control(e,t){if(e.control?.readyState!==`open`)return;let n=ir(t,this.controlId++),r=n.reduce((e,t)=>e+(typeof t==`string`?new TextEncoder().encode(t).length:t.byteLength),0);if(e.control.bufferedAmount+r>1048576){this.remove(e.id);return}for(let t of n)e.control.send(t);this.bytesSent+=r}fast(e,t){e.fast?.readyState===`open`&&e.fast.bufferedAmount<32768&&(e.fast.send(t),this.bytesSent+=t.byteLength)}broadcast(e){for(let t of this.peers.values())this.control(t,e)}async stats(){if(!(this.pollingStats||this.closed)){this.pollingStats=!0;try{await Promise.allSettled([...this.peers.values()].map(async e=>{if(!e.connected||e.lostAt!==void 0){e.rtt=null;return}try{let t=await e.pc.getStats();!this.closed&&this.peers.get(e.id)===e&&(e.rtt=er(t.values()))}catch{e.rtt=null}}))}finally{this.pollingStats=!1}}}remove(e,t=!0){let n=this.peers.get(e);n&&(clearTimeout(n.admissionTimer),this.peers.delete(e),this.controlAssemblers.delete(e),n.pc.close(),this.host&&t?this.signal({type:`evict`,id:e}):this.host||this.close(),this.hooks.leave(e),this.host||this.hooks.ended?.(`The host connection ended.`))}close(){if(!this.closed){this.resumeGrant&&this.signalingAdmitted&&this.ws.readyState===sr&&this.signal({type:`leave`,connectionEpoch:this.resumeGrant.connectionEpoch}),this.recovery?.cancel(),this.resumeGrant=void 0,this.resumeAttempt=void 0,this.cancelHeartbeat(),this.socketSerial++,this.challenge?.abort(),this.rejectVerification(`Room closed before verification confirmation.`),this.verificationState=null,this.rejectBan(`Room closed before ban confirmation.`),this.rejectPasswordUpdate(`Room closed before password confirmation.`),this.closed=!0,clearInterval(this.timer),this.ws.close(1e3,`Left room`);for(let e of this.peers.values())clearTimeout(e.admissionTimer),e.pc.close();this.peers.clear(),this.controlAssemblers.clear()}}};function pr(e,t){return e!==t&&e-t>>>0<2147483648}function mr(e){if(e.byteLength!==14)throw Error(`Input length`);let t=new DataView(e);if(t.getUint8(0)!==1||t.getUint8(1)!==5||t.getUint8(6)>31||t.getUint8(7))throw Error(`Input format`);return{seq:t.getUint32(2,!0),keys:t.getUint8(6),time:t.getUint32(8,!0),epoch:t.getUint16(12,!0)}}function hr(e,t,n=0){if(e.surface?.length)throw Error(`Terrain transport is not enabled`);let r=[];for(let t=0;t<e.discs.length/18;t++){let n=t*18,i=e.discs,a=i[n+5]>0||i[n+2]!==0||i[n+3]!==0||i[n+8]!==0||i[n+9]!==0||i[n]!==i[n+16]||i[n+1]!==i[n+17];(i[n+12]>0?i[n+13]>0:a)&&r.push(t)}let i=[`lobby`,`playing`,`goal`,`finished`],a=new ArrayBuffer(36+r.length*24),o=new DataView(a);o.setUint32(0,e.tick,!0),o.setUint32(4,e.elapsed,!0),o.setUint16(8,e.red,!0),o.setUint16(10,e.blue,!0),o.setUint8(12,i.indexOf(e.phase)),o.setUint8(13,+e.paused),o.setUint8(14,e.kickoff),o.setUint8(15,+e.kickoffActive),o.setUint16(16,e.countdown,!0),o.setUint16(18,e.scoreLimit,!0),o.setUint16(20,e.timeLimit,!0),o.setUint16(22,e.discs.length/18,!0),o.setUint32(24,t,!0),o.setUint16(28,r.length,!0),o.setUint16(30,e.resumeTicks,!0),o.setUint32(32,e.kickRate,!0),r.forEach((t,n)=>{let r=t*18,i=36+n*24;o.setUint16(i,t,!0),o.setUint8(i+2,e.discs[r+13]),o.setUint8(i+3,e.discs[r+14]|(e.discs[r+12]>0?(e.discs[r+11]&24)<<2:0));for(let t=0;t<4;t++)o.setFloat32(i+4+t*4,e.discs[r+t],!0);o.setUint16(i+20,e.discs[r+15],!0),e.discs[r+12]>0&&o.setUint16(i+22,e.discs[r+17]+255,!0)});let s=new Uint8Array(a),c=[],l=Math.ceil(s.length/1188);for(let t=0;t<l;t++){let r=s.subarray(t*1188,(t+1)*1188),i=new ArrayBuffer(12+r.length),a=new DataView(i);a.setUint8(0,2),a.setUint8(1,5),a.setUint32(2,e.tick,!0),a.setUint8(6,t),a.setUint8(7,l),a.setUint16(8,n,!0),a.setUint16(10,r.length,!0),new Uint8Array(i,12).set(r),c.push(i)}return c}var gr=Object.freeze({...tn}),_r=class e{runtime;engine;network;roomId=``;roomLink=``;roomName=``;epoch=0;stadiumSelection=0;players=[];nextPlayerId=0;bans=new Map;loop;linkNotification;last=performance.now();accumulator=0;recorder;closed=!1;closeController=new AbortController;signal=this.closeController.signal;finishingRecording=!1;lastRecording=null;onRecordingComplete;locked=!1;teamStyles=[null,null];inputs=new Map;traffic=new wn;onRoomLink;onPlayerJoin;onPlayerTeamChange;onPlayerMuteChange;onPlayerAdminChange;onGameStart;onGameStop;onTeamVictory;onGameVictory;onGamePauseChange;onGamePause;onGameUnpause;onPlayerLeave;onPlayerKicked;onPlayerActivity;onPlayerChat;onPlayerBallKick;onTeamGoal;onPositionsReset;onStadiumChange;onTeamsLockChange;onKickRateLimitSet;onGameTick;onError;report(e){try{let t=this.onError?.(e);t instanceof Promise&&t.catch(()=>{})}catch{}}invoke(e,t,...n){if(!(this.closed&&e!==`onRecordingComplete`))try{let r=t?.apply(this,n);return r instanceof Promise&&r.catch(t=>this.report(`${e}: ${String(t)}`)),r}catch(t){this.report(`${e}: ${String(t)}`);return}}constructor(e,t){this.runtime=t,this.engine=e}static async create(t,n=Sn(),r){let i=vn(n.network.serviceOrigin);if(t=ct(t),t.noPlayer!==void 0&&typeof t.noPlayer!=`boolean`)throw Error(`Invalid noPlayer setting`);let a=t.noPlayer===!1,o=t.playerName??`Host`;if(a&&(typeof o!=`string`||!o.trim()||o.length>24))throw Error(`Invalid host player name`);let s=ot(r),c;try{s.signal.throwIfAborted();let r=await s.run(n.loadEngine(s.signal));r.load(t.stadium??mn()),c=new e(r,n);let l=c,u=await s.run(n.request(new URL(`/api/rooms`,i),{signal:s.signal,method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({name:t.roomName,maxPlayers:t.maxPlayers??16,password:t.password??``,private:t.public===!1,hostPlayer:a})}));if(!u.ok)throw Error(`Room creation failed (${u.status})`);let d=await s.run(u.json());l.roomId=d.id,l.roomName=t.roomName,l.roomLink=`${i}${ut(d.id)}`;let f;try{await s.run(new Promise((e,t)=>{f=setTimeout(()=>t(Error(`Signaling timed out`)),12e3),l.network=new fr(d.id,{hostToken:d.hostToken},{ready:(n,r)=>{if(!r){t(Error(`Host authority was not granted`));return}a&&(l.players.push({id:l.nextPlayerId++,slot:0,peerId:n,name:o.trim(),team:0,admin:!0}),l.engine.joinPlayer(0)),clearTimeout(f),e()},allowStadiumUpload:e=>!!l.players.find(t=>t.peerId===e.id)?.admin&&[`lobby`,`finished`].includes(l.engine.phase)&&l.traffic.allow(e.id,`message`),open:()=>{},control:(e,t)=>l.control(e,t),fast:(e,t)=>l.fast(e,t),leave:e=>l.leave(e),status:e=>l.report(e),ended:e=>{clearTimeout(f),t(Error(e)),l.close(),l.report(e)}},n.network)}))}catch(e){throw l.close(),e}finally{clearTimeout(f)}if(l.closed)throw Error(`Room closed during startup`);l.last=performance.now(),l.loop=setInterval(()=>l.advance(),1e3/60);let p=l.roomLink;return l.linkNotification=setTimeout(()=>{l.linkNotification=void 0,l.invoke(`onRoomLink`,l.onRoomLink,p)},0),c}catch(e){throw c?.close(),e}finally{s.dispose()}}advance(){if(this.closed)return;let e=performance.now(),t=e-this.last;this.last=e,t>500&&this.engine.phase===`playing`&&!this.engine.paused&&(this.pauseGame(!0),this.report(`Host scheduler stalled; match paused.`)),this.accumulator+=Math.max(0,Math.min(t,500));let n=0;try{for(;!this.closed&&this.accumulator>=1e3/60&&n++<32;){for(let t of this.players){let n=this.inputs.get(t.peerId);n&&e-n.received>250&&this.engine.data[this.engine.index(t.slot)*18+14]&&this.command(`input`,t.slot,0)}if(this.recorder&&!this.recorder.canRecord(this.engine)&&this.finishRecording(`Recording limit reached`),this.closed||(this.engine.phase!==`lobby`&&!this.engine.paused&&!this.engine.resumeTicks&&this.invoke(`onGameTick`,this.onGameTick),this.closed))break;let t=this.engine.red,n=this.engine.blue,r=this.engine.phase;this.engine.step(),this.recorder?.step(this.engine),this.engine.phase!==r&&this.state();let i=r===`goal`&&this.engine.phase===`playing`;r===`finished`&&this.engine.phase===`lobby`&&this.invoke(`onGameStop`,this.onGameStop,null);let a=this.engine.ballKicks.map(e=>{let t=this.players.find(t=>t.slot===e);return t?this.playerCopy(t):null}).filter(e=>!!e),o=r!==`finished`&&this.engine.phase===`finished`?this.getScores():null;o&&(this.invoke(`onTeamVictory`,this.onTeamVictory,{...o}),this.invoke(`onGameVictory`,this.onGameVictory,{...o}));for(let e of a)this.invoke(`onPlayerBallKick`,this.onPlayerBallKick,e);if(this.engine.red>t&&this.invoke(`onTeamGoal`,this.onTeamGoal,1),this.engine.blue>n&&this.invoke(`onTeamGoal`,this.onTeamGoal,2),i&&this.invoke(`onPositionsReset`,this.onPositionsReset),this.closed)break;if(this.engine.tick%2==0){let e=this.engine.snapshot();if(e.surface?.length){if(this.engine.tick%6==0){let t=at(e,this.epoch);for(let e of this.network.peers.values())e.control?.readyState===`open`&&e.control.bufferedAmount<65536&&this.network.control(e,{...t,ack:this.inputs.get(e.id)?.seq??0})}}else for(let t of this.network.peers.values())for(let n of hr(e,this.inputs.get(t.id)?.seq??0,this.epoch))this.network.fast(t,n)}this.accumulator-=1e3/60}}catch(e){this.closed||(this.engine.setPaused(!0),this.report(String(e)))}}allowed(e){return this.traffic.allow(e.id,`message`)?!0:(this.network.remove(e.id),!1)}control(e,t){if(!this.allowed(e)||!t||typeof t!=`object`)return;let n=t,r=this.players.find(t=>t.peerId===e.id);if(n.type===`join`&&!r){if(n.version!==1||n.engine!==hn||typeof n.name!=`string`||!n.name.trim()||n.name.length>24){this.network.remove(e.id);return}let t=Array.from({length:32},(e,t)=>t).find(e=>!this.players.some(t=>t.slot===e));if(t===void 0){this.network.remove(e.id);return}r={id:this.nextPlayerId++,slot:t,peerId:e.id,name:n.name.trim(),team:0,admin:!1},this.players.push(r),this.network.admit(e),this.recorder?.player(this.engine.tick,r.slot,r.name),this.command(`join`,t,0),this.network.control(e,{type:`welcome`,epoch:this.epoch,roomName:this.roomName,engine:hn,slot:t,stadium:this.engine.source,state:this.engine.snapshot(),players:this.roster(),teamStyles:this.teamStyles,locked:this.locked}),this.sync(),this.invoke(`onPlayerJoin`,this.onPlayerJoin,this.playerCopy(r));return}if(r&&n.type===`action`){if(n.action===`chat`&&typeof n.text==`string`&&n.text.length<=200){if(r.muted||!n.text.trim()||!this.traffic.allow(e.id,`chat`)||(this.invoke(`onPlayerActivity`,this.onPlayerActivity,this.playerCopy(r)),this.closed||!this.players.includes(r)))return;this.invoke(`onPlayerChat`,this.onPlayerChat,this.playerCopy(r),n.text)!==!1&&!this.closed&&this.players.includes(r)&&!r.muted&&this.network.broadcast({type:`chat`,name:r.name,text:n.text})}if(n.action===`chat`||this.traffic.allow(e.id,`action`)){if(n.action===`avatar`&&ht(n.avatar)){r.avatar=n.avatar,this.recorder?.player(this.engine.tick,r.slot,r.name,r.avatarOverride??r.avatar),this.sync();return}if(n.action===`team`&&(!this.locked||r.admin)&&[0,1,2].includes(Number(n.team))){let e=n.slot===void 0?r:this.players.find(e=>e.slot===n.slot);e&&(e===r||r.admin)&&this.changeTeam(e.id,Number(n.team),r)}if(n.action===`defaultStadium`||n.action===`customStadium`){let t=t=>{!this.closed&&this.players.includes(r)&&this.network.control(e,{type:`stadiumResult`,text:t})};if(!r.admin||![`lobby`,`finished`].includes(this.engine.phase)){t(`Stadium change rejected: admin permission and a stopped match are required.`);return}if(n.action===`defaultStadium`?typeof n.name!=`string`:typeof n.source!=`string`)return;let i=++this.stadiumSelection;(n.action===`defaultStadium`?this.runtime.loadStadium(n.name):Promise.resolve(n.source)).then(e=>{if(!this.closed&&this.players.includes(r)){if(i!==this.stadiumSelection||!r.admin||![`lobby`,`finished`].includes(this.engine.phase)){t(`Stadium change cancelled: room state or permissions changed.`);return}this.changeStadium(e,this.playerCopy(r)),t(`Stadium applied.`)}}).catch(()=>t(`Stadium could not be loaded. Please try again.`));return}if(r.admin){if(n.action===`mute`&&typeof n.muted==`boolean`){let e=this.players.find(e=>e.slot===n.slot);e&&e!==r&&e.peerId!==this.network.hostId&&this.changePlayerMuted(e.id,n.muted,this.playerCopy(r));return}if(n.action===`surface`&&typeof n.enabled==`boolean`&&[`lobby`,`finished`].includes(this.engine.phase)){this.setSurfaceEnabled(n.enabled);return}if(n.action===`ban`||n.action===`clearBans`){let t=this.players.find(e=>e.slot===n.slot);if(n.action===`ban`&&(!t||t===r||t.peerId===this.network.hostId))return;let i=t=>{!this.closed&&this.network.peers.has(e.id)&&this.network.control(e,{type:`moderationResult`,text:t})};if(n.action===`clearBans`){i(`Only the room owner can clear bans.`);return}this.banPlayer(t.id,`Removed by admin`,this.playerCopy(r)).then(()=>i(`Player banned.`)).catch(e=>i(e instanceof Error?e.message:`Moderation failed.`));return}if(n.action===`teamColors`&&(n.team===1||n.team===2)){let e=n.palette;this.changeTeamColors(n.team,e===null?null:dt(e.angle,e.textColor,e.colors))}if(n.action===`kickRate`&&Number.isInteger(n.value)&&Number(n.value)>=0&&Number(n.value)<=6619135){let e=Number(n.value);this.changeKickRateLimit(e&255,e>>>8&255,e>>>16,this.playerCopy(r))}if(n.action===`start`&&this.beginGame(r),n.action===`stop`&&this.endGame(r),n.action===`pause`&&(n.paused===void 0||typeof n.paused==`boolean`)&&this.changePause(n.paused===void 0?!this.engine.paused:n.paused,this.playerCopy(r)),n.action===`settings`&&[`lobby`,`finished`].includes(this.engine.phase)){let e=Number(n.score),t=Number(n.minutes);if(Number.isInteger(e)&&e>=0&&e<=99&&Number.isInteger(t)&&t>=0&&t<=99&&(n.kickRate===void 0||Number.isInteger(n.kickRate)&&Number(n.kickRate)>=0&&Number(n.kickRate)<=6619135)){if(this.setScoreLimit(e),this.setTimeLimit(t),this.changeTeamsLock(!!n.locked,this.playerCopy(r)),this.closed)return;if(n.kickRate!==void 0&&n.kickRate!==this.engine.kickRate){let e=Number(n.kickRate);this.changeKickRateLimit(e&255,e>>>8&255,e>>>16,this.playerCopy(r))}}}if(n.action===`kick`&&typeof n.slot==`number`&&n.slot!==r.slot){let e=this.players.find(e=>e.slot===n.slot);e&&this.removePlayer(e.id,`Removed by host`,this.playerCopy(r))}}}}}fast(e,t){if(!this.allowed(e))return;let n=this.players.find(t=>t.peerId===e.id);if(!n)return;let r=mr(t);if(r.epoch!==this.epoch)return;let i=this.inputs.get(e.id);(!i||pr(r.seq,i.seq))&&(this.inputs.set(e.id,{seq:r.seq,received:performance.now(),keys:r.keys}),this.command(`input`,n.slot,r.keys),r.keys!==(i?.keys??0)&&this.invoke(`onPlayerActivity`,this.onPlayerActivity,this.playerCopy(n)))}command(e,t=0,n=0){if(this.closed)throw Error(`Room is closed`);let r={tick:this.engine.tick,kind:e,slot:t,value:n};if(this.recorder&&(!this.recorder.canRecord(this.engine)||!this.recorder.command(r))&&this.finishRecording(`Recording limit reached`),this.closed)throw Error(`Room is closed`);Ln(this.engine,r)}roster(){return this.players.map(e=>({avatar:e.avatarOverride??e.avatar??null,id:e.peerId,slot:e.slot,name:e.name,team:e.team,admin:e.admin,muted:!!e.muted}))}sync(){this.network.broadcast({type:`lobby`,players:this.roster(),teamStyles:this.teamStyles,locked:this.locked,scoreLimit:this.engine.scoreLimit,timeLimit:this.engine.timeLimit})}state(){this.network.broadcast({type:`state`,epoch:this.epoch,state:this.engine.snapshot()})}leave(e){this.traffic.delete(e);let t=this.players.find(t=>t.peerId===e);t&&(this.recorder?.player(this.engine.tick,t.slot,null),this.command(`team`,t.slot,0),this.players=this.players.filter(t=>t.peerId!==e),this.inputs.delete(e),this.sync(),this.invoke(`onPlayerLeave`,this.onPlayerLeave,this.playerCopy(t)))}playerCopy(e){let t=this.engine.index(e.slot)*18,n=!this.closed&&this.engine.phase!==`lobby`&&this.engine.data[t+13]>0,{slot:r,avatarOverride:i,...a}=e;return{...a,muted:!!e.muted,avatar:e.avatarOverride??e.avatar??null,position:n?{x:this.engine.data[t],y:this.engine.data[t+1]}:null}}getPlayerList(){return this.players.map(e=>this.playerCopy(e))}getPlayer(e){let t=this.players.find(t=>t.id===e);return t?this.playerCopy(t):null}setTeamColors(e,t,n,r){this.changeTeamColors(e,dt(t,n,r))}changeTeamColors(e,t){if(this.closed)throw Error(`Room is closed`);if(e!==1&&e!==2)throw Error(`Invalid team`);JSON.stringify(this.teamStyles[e-1])!==JSON.stringify(t)&&(this.teamStyles[e-1]=t,this.recorder?.style(this.engine.tick,this.teamStyles),this.sync())}reorderPlayers(e,t){if(this.closed)throw Error(`Room is closed`);if(!Array.isArray(e)||e.length>32||e.some(e=>!Number.isSafeInteger(e)||e<0)||typeof t!=`boolean`)throw Error(`Invalid player order`);let n=new Set(e),r=[...n].flatMap(e=>{let t=this.players.find(t=>t.id===e);return t?[t]:[]}),i=this.players.filter(e=>!n.has(e.id)),a=t?[...r,...i]:[...i,...r];a.every((e,t)=>e===this.players[t])||(this.players=a,this.recorder?.order(this.engine.tick,a.map(e=>e.slot)),this.sync())}setPlayerAvatar(e,t){if(this.closed)throw Error(`Room is closed`);if(!ht(t))throw Error(`Avatar must be null or at most two visible characters.`);let n=this.players.find(t=>t.id===e);n&&(n.avatarOverride=t,this.recorder?.player(this.engine.tick,n.slot,n.name,t??n.avatar),this.sync())}setPlayerTeam(e,t){this.changeTeam(e,t,null)}changeTeam(e,t,n){if(this.closed)throw Error(`Room is closed`);if(![0,1,2].includes(t))throw Error(`Invalid team`);let r=this.players.find(t=>t.id===e);r&&r.team!==t&&(r.team=t,this.command(`team`,r.slot,t),this.sync(),this.invoke(`onPlayerTeamChange`,this.onPlayerTeamChange,this.playerCopy(r),n?this.playerCopy(n):null))}setPlayerAdmin(e,t){if(this.closed)throw Error(`Room is closed`);let n=this.players.find(t=>t.id===e);n&&n.admin!==!!t&&(n.admin=!!t,this.sync(),this.invoke(`onPlayerAdminChange`,this.onPlayerAdminChange,this.playerCopy(n),null))}setPlayerMuted(e,t){this.changePlayerMuted(e,t,null)}changePlayerMuted(e,t,n){if(this.closed)throw Error(`Room is closed`);if(!Number.isInteger(e)||typeof t!=`boolean`)throw Error(`Invalid player mute`);let r=this.players.find(t=>t.id===e);r&&r.peerId!==this.network.hostId&&!!r.muted!==t&&(r.muted=t,this.sync(),this.invoke(`onPlayerMuteChange`,this.onPlayerMuteChange,this.playerCopy(r),n))}setTeamsLock(e){this.changeTeamsLock(e,null)}changeTeamsLock(e,t){if(this.closed)throw Error(`Room is closed`);this.locked!==!!e&&(this.locked=!!e,this.sync(),this.invoke(`onTeamsLockChange`,this.onTeamsLockChange,this.locked,t))}kickPlayer(e,t=`Removed by host`,n=!1){if(this.closed)throw Error(`Room is closed`);if(typeof n!=`boolean`)throw Error(`Invalid ban flag`);if(n)return this.banPlayer(e,t);this.removePlayer(e,t,null)}async banPlayer(e,t,n=null){if(typeof t!=`string`)throw Error(`Invalid kick reason`);let r=this.players.find(t=>t.id===e);if(!r||r.peerId===this.network.hostId)return;let i=this.playerCopy(r),a=t.slice(0,100);if(this.bans.size>=256&&!this.bans.has(e))throw Error(`Clear existing bans before adding more.`);try{await this.network.updateBan(`ban`,r.peerId)}catch(t){throw t instanceof or&&this.bans.set(e,r.peerId),t}this.bans.set(e,r.peerId),this.network.remove(r.peerId),this.invoke(`onPlayerKicked`,this.onPlayerKicked,i,a,!0,n)}async clearBan(e){if(this.closed)throw Error(`Room is closed`);let t=this.bans.get(e);t&&(await this.network.updateBan(`clearBan`,t),this.bans.delete(e))}async clearBans(){if(this.closed)throw Error(`Room is closed`);await this.network.updateBan(`clearBans`),this.bans.clear()}removePlayer(e,t,n){if(this.closed)throw Error(`Room is closed`);if(typeof t!=`string`)throw Error(`Invalid kick reason`);let r=this.players.find(t=>t.id===e);if(r&&r.peerId!==this.network.hostId){let e=this.playerCopy(r),i=t.slice(0,100),a=this.network.peers.get(r.peerId);a&&this.network.control(a,{type:`kicked`,reason:i}),this.network.remove(r.peerId),this.players.includes(r)||this.invoke(`onPlayerKicked`,this.onPlayerKicked,e,i,!1,n)}}sendChat(e,t){if(this.closed)throw Error(`Room is closed`);if(typeof e!=`string`||e.length>200)throw Error(`Chat must contain at most 200 characters`);if(t!=null&&(!Number.isSafeInteger(t)||t<0))throw Error(`Invalid chat target`);let n=this.players.find(e=>e.peerId===this.network.hostId);if(!n)throw Error(`sendChat requires a host player; use sendAnnouncement`);if(!e.trim())return;let r={type:`chat`,name:n.name,text:e};if(t==null)this.network.broadcast(r);else{let e=this.players.find(e=>e.id===t),n=e&&this.network.peers.get(e.peerId);n&&this.network.control(n,r)}}sendAnnouncement(e,t,n,r,i){if(this.closed)throw Error(`Room is closed`);let a=mt(e,n,r,i);if(t!=null&&(!Number.isSafeInteger(t)||t<0))throw Error(`Invalid announcement target`);if(t==null)this.network.broadcast(a);else{let e=this.players.find(e=>e.id===t),n=e&&this.network.peers.get(e.peerId);n&&this.network.control(n,a)}}startGame(){this.beginGame(null)}beginGame(e){if(this.closed)throw Error(`Room is closed`);let t=this.engine.phase;(t===`lobby`||t===`finished`)&&(this.command(`start`),this.stadiumSelection++,this.state(),t!==this.engine.phase&&this.engine.phase===`playing`&&this.invoke(`onGameStart`,this.onGameStart,e?this.playerCopy(e):null))}stopGame(){this.endGame(null)}endGame(e){if(this.closed)throw Error(`Room is closed`);let t=this.engine.phase!==`lobby`;(t||this.engine.paused)&&(this.command(`stop`),this.state(),t&&this.invoke(`onGameStop`,this.onGameStop,e?this.playerCopy(e):null))}pauseGame(e){this.changePause(e,null)}changePause(e,t){if(this.closed)throw Error(`Room is closed`);this.engine.phase!==`lobby`&&(e=!!e,this.engine.paused!==e&&(this.command(`pause`,0,+e),this.state(),e?this.invoke(`onGamePause`,this.onGamePause,t):this.invoke(`onGameUnpause`,this.onGameUnpause,t),this.invoke(`onGamePauseChange`,this.onGamePauseChange,e)))}setSurfaceEnabled(e){if(this.closed)throw Error(`Room is closed`);if(typeof e!=`boolean`)throw Error(`Surface enabled must be a boolean`);if(![`lobby`,`finished`].includes(this.engine.phase))throw Error(`Stop the match before changing its surface`);!!this.engine.snapshotSurface().length!==e&&(this.command(`surface`,0,+e),this.state(),this.sync())}setKickRateLimit(e=2,t=0,n=0){this.changeKickRateLimit(e,t,n,null)}changeKickRateLimit(e,t,n,r){if(this.closed)throw Error(`Room is closed`);let i=_n(e,t,n);i!==this.engine.kickRate&&(this.command(`kickRate`,0,i),this.state(),this.invoke(`onKickRateLimitSet`,this.onKickRateLimitSet,i&255,i>>>8&255,i>>>16,r))}async setPassword(e){if(this.closed)throw Error(`Room is closed`);await this.network.setPassword(e)}get requireVerification(){return this.network.requireVerification}async setRequireVerification(e){if(this.closed)throw Error(`Room is closed`);await this.network.setRequireVerification(e)}async setRequireRecaptcha(e){await this.setRequireVerification(e)}setScoreLimit(e){if(this.closed)throw Error(`Room is closed`);if([`lobby`,`finished`].includes(this.engine.phase)){if(!Number.isInteger(e)||e<0||e>99)throw Error(`Invalid limit`);e!==this.engine.scoreLimit&&(this.command(`scoreLimit`,0,e),this.sync())}}setTimeLimit(e){if(this.closed)throw Error(`Room is closed`);if([`lobby`,`finished`].includes(this.engine.phase)){if(!Number.isInteger(e)||e<0||e>99)throw Error(`Invalid time limit`);e*60!==this.engine.timeLimit&&(this.command(`timeLimit`,0,e*60),this.sync())}}async setDefaultStadium(e){if(this.closed)throw Error(`Room is closed`);if(![`lobby`,`finished`].includes(this.engine.phase))return;let t=++this.stadiumSelection,n=await this.runtime.loadStadium(e);if(this.closed)throw Error(`Room is closed`);if(t!==this.stadiumSelection)throw Error(`Stadium selection superseded`);this.setCustomStadium(n)}setCustomStadium(e){this.changeStadium(e,null)}changeStadium(e,t){if(this.closed)throw Error(`Room is closed`);if(![`lobby`,`finished`].includes(this.engine.phase))return;pn(e);let n=++this.stadiumSelection;if(this.recorder&&this.finishRecording(`Stadium changed`),this.closed)throw Error(`Room is closed`);if([`lobby`,`finished`].includes(this.engine.phase)){if(n!==this.stadiumSelection)throw Error(`Stadium selection superseded`);this.engine.load(e);for(let e of this.players)this.engine.setTeam(e.slot,e.team);this.epoch=this.epoch+1&65535,this.inputs.clear(),this.network.broadcast({type:`stadium`,epoch:this.epoch,source:e,state:this.engine.snapshot()}),this.invoke(`onStadiumChange`,this.onStadiumChange,this.engine.stadium.name,t)}}getScores(){let e=this.engine;return this.closed||e.phase===`lobby`?null:{red:e.red,blue:e.blue,time:e.elapsed/60,scoreLimit:e.scoreLimit,timeLimit:e.timeLimit}}getBallPosition(){return this.closed||this.engine.phase===`lobby`?null:{x:this.engine.data[0],y:this.engine.data[1]}}readDisc(e){let t=this.engine.data,n=e*18;return{x:t[n],y:t[n+1],xspeed:t[n+2],yspeed:t[n+3],radius:t[n+4],invMass:t[n+5],damping:t[n+6],bCoeff:t[n+7],xgravity:t[n+8],ygravity:t[n+9],cGroup:t[n+10],cMask:t[n+11],color:this.engine.colors[e]}}get CollisionFlags(){return gr}getDiscCount(){return this.closed||this.engine.phase===`lobby`?0:this.engine.stadium.discs.length+this.players.filter(e=>e.team!==0).length}getDiscProperties(e){if(!Number.isInteger(e)||e<0||e>=this.getDiscCount())return null;let t=this.engine.stadium.discs.length;if(e<t)return this.readDisc(e);let n=this.players.filter(e=>e.team!==0)[e-t];return this.readDisc(this.engine.index(n.slot))}setDiscProperties(e,t){if(this.closed)throw Error(`Room is closed`);if(!Number.isInteger(e)||e<0||e>=this.getDiscCount())return;let n=this.engine.stadium.discs.length,r=e<n?e:this.engine.index(this.players.filter(e=>e.team!==0)[e-n].slot);this.changeDisc(r,t)}setPlayerDiscProperties(e,t){if(this.closed)throw Error(`Room is closed`);if(this.engine.phase===`lobby`)return;let n=this.players.find(t=>t.id===e&&t.team!==0);n&&this.changeDisc(this.engine.index(n.slot),t)}changeDisc(e,t){let n=_t(t),r=this.readDisc(e);if(Object.entries(n).every(([e,t])=>r[e]===t))return;let i={tick:this.engine.tick,kind:`disc`,slot:e,value:0,properties:n};if(this.recorder&&(!this.recorder.canRecord(this.engine)||!this.recorder.command(i))&&this.finishRecording(`Recording limit reached`),this.closed)throw Error(`Room is closed`);Ln(this.engine,i),this.state()}getPlayerDiscProperties(e){if(this.closed||this.engine.phase===`lobby`)return null;let t=this.players.find(t=>t.id===e&&t.team!==0);return t?this.readDisc(this.engine.index(t.slot)):null}getState(){return this.engine.snapshot()}startRecording(){if(this.closed)throw Error(`Room is closed`);if(this.finishingRecording)throw Error(`Recording completion is in progress`);if(this.recorder)throw Error(`Recording is already active`);this.recorder=new Rn(this.engine,this.players.map(e=>({slot:e.slot,name:e.name,avatar:e.avatarOverride??e.avatar})),this.teamStyles)}finishRecording(e){this.finishingRecording=!0;try{let t=this.stopRecording();t&&(this.lastRecording=t,this.invoke(`onRecordingComplete`,this.onRecordingComplete,t,e))}finally{this.finishingRecording=!1}}stopRecording(){let e=this.recorder?.finish(this.engine)??null;return this.recorder=void 0,e}close(){if(!this.closed){this.closed=!0,this.closeController.abort();try{this.recorder&&this.finishRecording(`Room closed`)}finally{clearInterval(this.loop),clearTimeout(this.linkNotification),this.linkNotification=void 0,this.network?.close(),this.players=[],this.traffic.clear()}}}};function vr(e){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`Room configuration must be an object`);let t={...e},n=t.maxPlayers??12;if(typeof n!=`number`||!Number.isFinite(n)||!Number.isInteger(n))throw Error(`maxPlayers must be a finite integer`);return ct({...t,roomName:t.roomName??`Headless Room`,playerName:t.playerName??`Host`,noPlayer:t.noPlayer??!1,public:t.public??!1,maxPlayers:Math.max(2,Math.min(30,n)),password:t.password??``})}var yr=class{onError;pending=[];active;scheduled=!1;closed=!1;constructor(e=()=>{}){this.onError=e}enqueue(e){let t=new Promise((t,n)=>{if(this.closed){n(Error(`Room is closed`));return}if(this.pending.length>=256){n(Error(`Room command queue is full`));return}this.pending.push({run:e,resolve:e=>t(e),reject:n}),this.scheduled||(this.scheduled=!0,queueMicrotask(()=>{this.drain()}))});return t.catch(e=>{if(!this.closed)try{this.onError(e)}catch{}}),t}async drain(){for(;!this.closed&&this.pending.length;){let e=this.pending.shift();this.active=e;try{e.resolve(await e.run())}catch(t){e.reject(t)}this.active=void 0}this.scheduled=!1}close(){if(this.closed)return;this.closed=!0;let e=Error(`Room is closed`);this.active?.reject(e);for(let t of this.pending.splice(0))t.reject(e)}},br=`sendChat.sendAnnouncement.setPlayerAdmin.setPlayerMuted.setPlayerTeam.kickPlayer.clearBan.clearBans.setScoreLimit.setTimeLimit.setCustomStadium.setDefaultStadium.setTeamsLock.setTeamColors.startGame.stopGame.pauseGame.setPassword.setRequireVerification.setRequireRecaptcha.reorderPlayers.setKickRateLimit.setSurfaceEnabled.setPlayerAvatar.setDiscProperties.setPlayerDiscProperties`.split(`.`);function xr(e,t){let n=Object.create(null);t&&Object.defineProperty(n,"closed",{enumerable:!0,value:t});let r=new yr(t=>{let n=e.onError?.(String(t));n instanceof Promise&&n.catch(()=>{})});e.signal.addEventListener(`abort`,()=>r.close(),{once:!0}),e.signal.aborted&&r.close();for(let t of br)Object.defineProperty(n,t,{enumerable:!0,value:(...n)=>{try{let i=structuredClone(n);return(t===`setScoreLimit`||t===`setTimeLimit`)&&typeof i[0]==`number`&&Number.isInteger(i[0])&&(i[0]=Math.max(0,Math.min(99,i[0]))),r.enqueue(()=>Reflect.apply(e[t],e,i))}catch(e){return r.enqueue(()=>{throw e})}}});for(let t of[`getPlayer`,`getPlayerList`,`getScores`,`getBallPosition`,`getDiscCount`,`getDiscProperties`,`getPlayerDiscProperties`,`getState`,`startRecording`,`stopRecording`])Object.defineProperty(n,t,{enumerable:!0,value:e[t].bind(e)});for(let t of[`roomId`,`roomLink`,`roomName`,`lastRecording`,`requireVerification`,`CollisionFlags`,`signal`])Object.defineProperty(n,t,{enumerable:!0,get:()=>e[t]});for(let t of[`onRoomLink`,`onPlayerJoin`,`onPlayerLeave`,`onPlayerChat`,`onPlayerTeamChange`,`onPlayerAdminChange`,`onPlayerMuteChange`,`onPlayerKicked`,`onPlayerActivity`,`onPlayerBallKick`,`onTeamGoal`,`onTeamVictory`,`onGameVictory`,`onGameStart`,`onGameStop`,`onGameTick`,`onGamePause`,`onGameUnpause`,`onGamePauseChange`,`onPositionsReset`,`onStadiumChange`,`onTeamsLockChange`,`onKickRateLimitSet`,`onRecordingComplete`,`onError`]){let r;Object.defineProperty(n,t,{enumerable:!0,get:()=>r,set:i=>{if(i!=null&&typeof i!=`function`)throw Error(`Callback must be a function`);r=i,Reflect.set(e,t,i==null?void 0:(...e)=>Reflect.apply(i,n,e))}})}return Object.defineProperty(n,"close",{enumerable:!0,value:()=>{r.close(),e.close()}}),Object.preventExtensions(n)}var Sr=R(((e,t)=>{var n=1e3,r=n*60,i=r*60,a=i*24,o=a*7,s=a*365.25;t.exports=function(e,t){t||={};var n=typeof e;if(n===`string`&&e.length>0)return c(e);if(n===`number`&&isFinite(e))return t.long?u(e):l(e);throw Error(`val is not a non-empty string or a valid number. val=`+JSON.stringify(e))};function c(e){if(e=String(e),!(e.length>100)){var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(t){var c=parseFloat(t[1]);switch((t[2]||`ms`).toLowerCase()){case`years`:case`year`:case`yrs`:case`yr`:case`y`:return c*s;case`weeks`:case`week`:case`w`:return c*o;case`days`:case`day`:case`d`:return c*a;case`hours`:case`hour`:case`hrs`:case`hr`:case`h`:return c*i;case`minutes`:case`minute`:case`mins`:case`min`:case`m`:return c*r;case`seconds`:case`second`:case`secs`:case`sec`:case`s`:return c*n;case`milliseconds`:case`millisecond`:case`msecs`:case`msec`:case`ms`:return c;default:return}}}}function l(e){var t=Math.abs(e);return t>=a?Math.round(e/a)+`d`:t>=i?Math.round(e/i)+`h`:t>=r?Math.round(e/r)+`m`:t>=n?Math.round(e/n)+`s`:e+`ms`}function u(e){var t=Math.abs(e);return t>=a?d(e,t,a,`day`):t>=i?d(e,t,i,`hour`):t>=r?d(e,t,r,`minute`):t>=n?d(e,t,n,`second`):e+` ms`}function d(e,t,n,r){var i=t>=n*1.5;return Math.round(e/n)+` `+r+(i?`s`:``)}})),Cr=R(((e,t)=>{function n(e){n.debug=n,n.default=n,n.coerce=c,n.disable=o,n.enable=i,n.enabled=s,n.humanize=Sr(),n.destroy=l,Object.keys(e).forEach(t=>{n[t]=e[t]}),n.names=[],n.skips=[],n.formatters={};function t(e){let t=0;for(let n=0;n<e.length;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return n.colors[Math.abs(t)%n.colors.length]}n.selectColor=t;function n(e){let t,i=null,a,o;function s(...e){if(!s.enabled)return;let r=s,i=Number(new Date);r.diff=i-(t||i),r.prev=t,r.curr=i,t=i,e[0]=n.coerce(e[0]),typeof e[0]!=`string`&&e.unshift(`%O`);let a=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,(t,i)=>{if(t===`%%`)return`%`;a++;let o=n.formatters[i];if(typeof o==`function`){let n=e[a];t=o.call(r,n),e.splice(a,1),a--}return t}),n.formatArgs.call(r,e),(r.log||n.log).apply(r,e)}return s.namespace=e,s.useColors=n.useColors(),s.color=n.selectColor(e),s.extend=r,s.destroy=n.destroy,Object.defineProperty(s,"enabled",{enumerable:!0,configurable:!1,get:()=>i===null?(a!==n.namespaces&&(a=n.namespaces,o=n.enabled(e)),o):i,set:e=>{i=e}}),typeof n.init==`function`&&n.init(s),s}function r(e,t){let r=n(this.namespace+(t===void 0?`:`:t)+e);return r.log=this.log,r}function i(e){n.save(e),n.namespaces=e,n.names=[],n.skips=[];let t=(typeof e==`string`?e:``).trim().replace(` `,`,`).split(`,`).filter(Boolean);for(let e of t)e[0]===`-`?n.skips.push(e.slice(1)):n.names.push(e)}function a(e,t){let n=0,r=0,i=-1,a=0;for(;n<e.length;)if(r<t.length&&(t[r]===e[n]||t[r]===`*`))t[r]===`*`?(i=r,a=n,r++):(n++,r++);else if(i!==-1)r=i+1,a++,n=a;else return!1;for(;r<t.length&&t[r]===`*`;)r++;return r===t.length}function o(){let e=[...n.names,...n.skips.map(e=>`-`+e)].join(`,`);return n.enable(``),e}function s(e){for(let t of n.skips)if(a(e,t))return!1;for(let t of n.names)if(a(e,t))return!0;return!1}function c(e){return e instanceof Error?e.stack||e.message:e}function l(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}return n.enable(n.load()),n}t.exports=n})),wr=R(((e,t)=>{e.formatArgs=r,e.save=i,e.load=a,e.useColors=n,e.storage=o(),e.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),e.colors=`#0000CC.#0000FF.#0033CC.#0033FF.#0066CC.#0066FF.#0099CC.#0099FF.#00CC00.#00CC33.#00CC66.#00CC99.#00CCCC.#00CCFF.#3300CC.#3300FF.#3333CC.#3333FF.#3366CC.#3366FF.#3399CC.#3399FF.#33CC00.#33CC33.#33CC66.#33CC99.#33CCCC.#33CCFF.#6600CC.#6600FF.#6633CC.#6633FF.#66CC00.#66CC33.#9900CC.#9900FF.#9933CC.#9933FF.#99CC00.#99CC33.#CC0000.#CC0033.#CC0066.#CC0099.#CC00CC.#CC00FF.#CC3300.#CC3333.#CC3366.#CC3399.#CC33CC.#CC33FF.#CC6600.#CC6633.#CC9900.#CC9933.#CCCC00.#CCCC33.#FF0000.#FF0033.#FF0066.#FF0099.#FF00CC.#FF00FF.#FF3300.#FF3333.#FF3366.#FF3399.#FF33CC.#FF33FF.#FF6600.#FF6633.#FF9900.#FF9933.#FFCC00.#FFCC33`.split(`.`);function n(){if(typeof window<`u`&&window.process&&(window.process.type===`renderer`||window.process.__nwjs))return!0;if(typeof navigator<`u`&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;let e;return typeof document<`u`&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<`u`&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<`u`&&navigator.userAgent&&(e=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/))&&parseInt(e[1],10)>=31||typeof navigator<`u`&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function r(e){if(e[0]=(this.useColors?`%c`:``)+this.namespace+(this.useColors?` %c`:` `)+e[0]+(this.useColors?`%c `:` `)+`+`+t.exports.humanize(this.diff),!this.useColors)return;let n=`color: `+this.color;e.splice(1,0,n,`color: inherit`);let r=0,i=0;e[0].replace(/%[a-zA-Z%]/g,e=>{e!==`%%`&&(r++,e===`%c`&&(i=r))}),e.splice(i,0,n)}e.log=console.debug||console.log||(()=>{});function i(t){try{t?e.storage.setItem(`debug`,t):e.storage.removeItem(`debug`)}catch{}}function a(){let t;try{t=e.storage.getItem(`debug`)}catch{}return!t&&typeof process<`u`&&`env`in process&&(t=process.env.DEBUG),t}function o(){try{return localStorage}catch{}}t.exports=Cr()(e);var{formatters:s}=t.exports;s.j=function(e){try{return JSON.stringify(e)}catch(e){return`[UnexpectedJSONParseError]: `+e.message}}})),Tr=z({createSupportsColor:()=>Ar,default:()=>Nr});function Er(e,t=globalThis.Deno?globalThis.Deno.args:p.argv){let n=e.startsWith(`-`)?``:e.length===1?`-`:`--`,r=t.indexOf(n+e),i=t.indexOf(`--`);return r!==-1&&(i===-1||r<i)}function Dr(){if(!(`FORCE_COLOR`in jr))return;if(jr.FORCE_COLOR===`true`)return 1;if(jr.FORCE_COLOR===`false`)return 0;if(jr.FORCE_COLOR.length===0)return 1;let e=Math.min(Number.parseInt(jr.FORCE_COLOR,10),3);if([0,1,2,3].includes(e))return e}function Or(e){return e!==0&&{level:e,hasBasic:!0,has256:e>=2,has16m:e>=3}}function kr(e,{streamIsTTY:t,sniffFlags:n=!0}={}){let r=Dr();r!==void 0&&(Mr=r);let i=n?Mr:r;if(i===0)return 0;if(n){if(Er(`color=16m`)||Er(`color=full`)||Er(`color=truecolor`))return 3;if(Er(`color=256`))return 2}if(`TF_BUILD`in jr&&`AGENT_NAME`in jr)return 1;if(e&&!t&&i===void 0)return 0;let a=i||0;if(jr.TERM===`dumb`)return a;if(p.platform===`win32`){let e=h.release().split(`.`);return Number(e[0])>=10&&Number(e[2])>=10586?Number(e[2])>=14931?3:2:1}if(`CI`in jr)return[`GITHUB_ACTIONS`,`GITEA_ACTIONS`,`CIRCLECI`].some(e=>e in jr)?3:[`TRAVIS`,`APPVEYOR`,`GITLAB_CI`,`BUILDKITE`,`DRONE`].some(e=>e in jr)||jr.CI_NAME===`codeship`?1:a;if(`TEAMCITY_VERSION`in jr)return+!!/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(jr.TEAMCITY_VERSION);if(jr.COLORTERM===`truecolor`||jr.TERM===`xterm-kitty`||jr.TERM===`xterm-ghostty`||jr.TERM===`wezterm`)return 3;if(`TERM_PROGRAM`in jr){let e=Number.parseInt((jr.TERM_PROGRAM_VERSION||``).split(`.`)[0],10);switch(jr.TERM_PROGRAM){case`iTerm.app`:return e>=3?3:2;case`Apple_Terminal`:return 2}}return/-256(color)?$/i.test(jr.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(jr.TERM)||`COLORTERM`in jr?1:a}function Ar(e,t={}){return Or(kr(e,{streamIsTTY:e&&e.isTTY,...t}))}var jr,Mr,Nr,Pr=L((()=>{({env:jr}=p),Er(`no-color`)||Er(`no-colors`)||Er(`color=false`)||Er(`color=never`)?Mr=0:(Er(`color`)||Er(`colors`)||Er(`color=true`)||Er(`color=always`))&&(Mr=1),Nr={stdout:Ar({isTTY:g.isatty(1)}),stderr:Ar({isTTY:g.isatty(2)})}})),Fr=R(((e,t)=>{var n=te(`tty`),r=te(`util`);e.init=u,e.log=s,e.formatArgs=a,e.save=c,e.load=l,e.useColors=i,e.destroy=r.deprecate(()=>{},"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."),e.colors=[6,2,3,4,5,1];try{let t=(Pr(),ee(Tr));t&&(t.stderr||t).level>=2&&(e.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221])}catch{}e.inspectOpts=Object.keys(process.env).filter(e=>/^debug_/i.test(e)).reduce((e,t)=>{let n=t.substring(6).toLowerCase().replace(/_([a-z])/g,(e,t)=>t.toUpperCase()),r=process.env[t];return r=/^(yes|on|true|enabled)$/i.test(r)?!0:/^(no|off|false|disabled)$/i.test(r)?!1:r===`null`?null:Number(r),e[n]=r,e},{});function i(){return`colors`in e.inspectOpts?!!e.inspectOpts.colors:n.isatty(process.stderr.fd)}function a(e){let{namespace:n,useColors:r}=this;if(r){let r=this.color,i=`\x1B[3`+(r<8?r:`8;5;`+r),a=` ${i};1m${n} \u001B[0m`;e[0]=a+e[0].split(`
|
|
15
15
|
`).join(`
|
|
16
16
|
`+a),e.push(i+`m+`+t.exports.humanize(this.diff)+`\x1B[0m`)}else e[0]=o()+n+` `+e[0]}function o(){return e.inspectOpts.hideDate?``:new Date().toISOString()+` `}function s(...t){return process.stderr.write(r.formatWithOptions(e.inspectOpts,...t)+`
|
|
17
17
|
`)}function c(e){e?process.env.DEBUG=e:delete process.env.DEBUG}function l(){return process.env.DEBUG}function u(t){t.inspectOpts={};let n=Object.keys(e.inspectOpts);for(let r=0;r<n.length;r++)t.inspectOpts[n[r]]=e.inspectOpts[n[r]]}t.exports=Cr()(e);var{formatters:d}=t.exports;d.o=function(e){return this.inspectOpts.colors=this.useColors,r.inspect(e,this.inspectOpts).split(`
|
package/dist/types/player.d.ts
CHANGED
package/dist/types/room.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface Room {
|
|
|
13
13
|
onRoomLink?: (url: string) => void;
|
|
14
14
|
onPlayerJoin?: (p: HostPlayer) => void;
|
|
15
15
|
onPlayerTeamChange?: (p: HostPlayer, byPlayer: HostPlayer | null) => void;
|
|
16
|
+
onPlayerMuteChange?: (p: HostPlayer, byPlayer: HostPlayer | null) => void;
|
|
16
17
|
onPlayerAdminChange?: (p: HostPlayer, byPlayer: HostPlayer | null) => void;
|
|
17
18
|
onGameStart?: (byPlayer: HostPlayer | null) => void;
|
|
18
19
|
onGameStop?: (byPlayer: HostPlayer | null) => void;
|
|
@@ -41,6 +42,8 @@ export interface Room {
|
|
|
41
42
|
setPlayerAvatar(id: number, avatar: string | null): Promise<void>;
|
|
42
43
|
setPlayerTeam(id: number, team: 0 | 1 | 2): Promise<void>;
|
|
43
44
|
setPlayerAdmin(id: number, admin: boolean): Promise<void>;
|
|
45
|
+
/** Mute room chat for this player until unmuted or they leave. */
|
|
46
|
+
setPlayerMuted(id: number, muted: boolean): Promise<void>;
|
|
44
47
|
setTeamsLock(locked: boolean): Promise<void>;
|
|
45
48
|
kickPlayer(id: number, reason?: string, ban?: boolean): Promise<void>;
|
|
46
49
|
clearBan(id: number): Promise<void>;
|