xxscreeps-mod-client 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -12
- package/backend.js +5 -4
- package/package.json +5 -7
- package/dist/assets/CodePanel-DjI4Md1t.js +0 -1
- package/dist/assets/MapViewer-D66NMczX.js +0 -1
- package/dist/assets/index-BKZ4Y5Yn.js +0 -4
- package/dist/assets/terrain.worker-D9zNeJfz.js +0 -1
- package/dist/assets/vendor-codemirror-BbK0dVBs.js +0 -24
- package/dist/assets/vendor-pixi-CqiKBxHw.js +0 -906
- package/dist/backend.js +0 -110
- package/dist/index.html +0 -29
- package/dist/index.js +0 -3
- package/dist/package.json +0 -7
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Environment variables:
|
|
|
23
23
|
| Mount path | `SCREEPS_MOD_CLIENT_MOUNT_PATH` | `/` |
|
|
24
24
|
| Redirect `/` → mount path | `SCREEPS_MOD_CLIENT_ROOT_REDIRECT` | `true` if `mountPath !== '/'`, else `false` |
|
|
25
25
|
|
|
26
|
-
When mounted at `/`, the mod only serves paths that map to an existing file in
|
|
26
|
+
When mounted at `/`, the mod only serves paths that map to an existing file in the client bundle or that look like an SPA route (no file extension). Requests to xxscreeps' own endpoints (`/api/`, `/socket/`, …) are passed through to subsequent middleware.
|
|
27
27
|
|
|
28
28
|
### Example
|
|
29
29
|
|
|
@@ -31,18 +31,9 @@ When mounted at `/`, the mod only serves paths that map to an existing file in `
|
|
|
31
31
|
SCREEPS_MOD_CLIENT_MOUNT_PATH=/play npx xxscreeps start
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## How it works
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
pnpm --filter xxscreeps-mod-client build
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
This builds `screeps-client` with `base=/` (absolute asset URLs at the server root) and copies the artifacts into `dist/`. The shipped bundle is tied to its build-time base path — overriding `SCREEPS_MOD_CLIENT_MOUNT_PATH` at runtime requires a rebuild with a matching base:
|
|
41
|
-
|
|
42
|
-
```sh
|
|
43
|
-
SCREEPS_MOD_CLIENT_BUILD_BASE=/play/ pnpm --filter xxscreeps-mod-client build
|
|
44
|
-
SCREEPS_MOD_CLIENT_MOUNT_PATH=/play npx xxscreeps start
|
|
45
|
-
```
|
|
36
|
+
The mod resolves the client bundle from its [`screeps-client`](../screeps-client) dependency at runtime — no separate build step is needed. The shipped bundle is built with `base=/` (absolute asset URLs at the server root), which means non-default mount paths require a custom build of `screeps-client` with a matching base.
|
|
46
37
|
|
|
47
38
|
## xxscreeps mode
|
|
48
39
|
|
package/backend.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
|
-
import {
|
|
2
|
+
import { createRequire } from 'node:module'
|
|
3
3
|
import { createReadStream, existsSync, statSync } from 'node:fs'
|
|
4
4
|
import { hooks } from 'xxscreeps/backend/index.js'
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const require = createRequire(import.meta.url)
|
|
7
|
+
const clientPkgPath = require.resolve('screeps-client/package.json')
|
|
8
|
+
const distDir = path.join(path.dirname(clientPkgPath), 'dist', 'xxscreeps-mod')
|
|
8
9
|
const indexFile = path.join(distDir, 'index.html')
|
|
9
10
|
|
|
10
11
|
const CONTENT_TYPES = {
|
|
@@ -64,7 +65,7 @@ function sendFile(ctx, filePath, stat) {
|
|
|
64
65
|
|
|
65
66
|
hooks.register('middleware', koa => {
|
|
66
67
|
if (!existsSync(indexFile)) {
|
|
67
|
-
console.error(`[xxscreeps-mod-client]
|
|
68
|
+
console.error(`[xxscreeps-mod-client] client bundle not found at ${indexFile}. Run "pnpm --filter screeps-client build:embedded:xxscreeps" first.`)
|
|
68
69
|
return
|
|
69
70
|
}
|
|
70
71
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xxscreeps-mod-client",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "xxscreeps mod that serves the screeps-client and connects it to the same server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"xxscreeps": true,
|
|
@@ -10,8 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"index.js",
|
|
13
|
-
"backend.js"
|
|
14
|
-
"dist/"
|
|
13
|
+
"backend.js"
|
|
15
14
|
],
|
|
16
15
|
"repository": {
|
|
17
16
|
"type": "git",
|
|
@@ -23,6 +22,9 @@
|
|
|
23
22
|
"engines": {
|
|
24
23
|
"node": ">=20"
|
|
25
24
|
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"screeps-client": "^0.3.0"
|
|
27
|
+
},
|
|
26
28
|
"peerDependencies": {
|
|
27
29
|
"xxscreeps": "*"
|
|
28
30
|
},
|
|
@@ -30,9 +32,5 @@
|
|
|
30
32
|
"xxscreeps": {
|
|
31
33
|
"optional": true
|
|
32
34
|
}
|
|
33
|
-
},
|
|
34
|
-
"scripts": {
|
|
35
|
-
"build": "node ./scripts/build-client.js && node ./scripts/copy-dist.js",
|
|
36
|
-
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\""
|
|
37
35
|
}
|
|
38
36
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{f as E,e as w,j as r,s as c,u as ee,g as te,t as u,h as oe}from"./index-BKZ4Y5Yn.js";import{l as f,e as ie,g as ne,c as re,r as le,h as P,f as b,j as $,F as R,S as j,n as se,E as de}from"./vendor-codemirror-BbK0dVBs.js";import"./vendor-pixi-CqiKBxHw.js";var ae=u("<span style=font-size:11px;color:#e3b341>Unsaved changes"),ce=u('<div style="padding:12px 10px;font-size:12px;color:#484f58;font-style:italic">Loading…'),fe=u("<div style=flex:1;display:flex;align-items:center;justify-content:center;color:#484f58;font-size:13px;font-style:italic>"),ue=u('<div style=position:absolute;inset:0px;background:#0d1117;z-index:100;display:flex;flex-direction:column;overflow:hidden><div style="display:flex;align-items:center;gap:12px;padding:10px 16px;border-bottom:1px solid #30363d;flex-shrink:0"><span style=font-size:15px;font-weight:600;color:#c9d1d9>Code</span><select style="background:#010409;color:#c9d1d9;border:1px solid #30363d;border-radius:4px;padding:4px 8px;font-size:12px;cursor:pointer"></select><div style=flex:1></div><button style="padding:5px 14px;border-radius:4px;border:1px solid #238636;font-size:12px;font-weight:600"></button><button style="background:transparent;border:none;color:#8b949e;font-size:18px;cursor:pointer;line-height:1;padding:2px 6px">✕</button></div><div style=flex:1;display:flex;overflow:hidden><div style="width:180px;flex-shrink:0;border-right:1px solid #21262d;display:flex;flex-direction:column;overflow:hidden"><div style="padding:6px 10px;font-size:10px;font-weight:700;color:#8b949e;text-transform:uppercase;letter-spacing:0.06em;border-bottom:1px solid #21262d;flex-shrink:0">Modules</div><div style=flex:1;overflow:auto></div></div><div style=flex:1;display:flex;flex-direction:column;overflow:hidden><div style="padding:5px 14px;font-size:12px;color:#8b949e;border-bottom:1px solid #21262d;flex-shrink:0;font-family:monospace;background:#0d1117">.js</div><div style=flex:1;overflow:hidden;flex-direction:column>'),pe=u("<option>"),xe=u('<div style="padding:7px 12px;font-size:12px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">');const{error:L}=te("code"),ve=de.theme({"&":{height:"100%"},".cm-scroller":{"font-family":"'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace","font-size":"13px","line-height":"1.6",overflow:"auto"},".cm-gutters":{background:"#0d1117","border-right":"1px solid #21262d"},".cm-lineNumbers .cm-gutterElement":{color:"#484f58","min-width":"3em"},".cm-activeLineGutter":{background:"#161b22"},".cm-activeLine":{background:"#161b22"}}),he=[re,se(),le,ve];function ye(W){const[A,G]=f([]),[k,F]=f(""),[m,S]=f({}),[s,C]=f(""),[_,M]=f(!1),[p,B]=f(!1),[x,z]=f(!1),J=()=>Object.keys(m()),{editorView:U,ref:q,createExtension:H}=ie({onValueChange:o=>{const t=s();!t||m()[t]===o||(S(n=>({...n,[t]:o})),z(!0))}});ne(U,()=>m()[s()]??""),H(he),P(()=>{const o=E();o&&o.http.user.branches().then(t=>{G(t.list);const n=t.list.find(d=>d.activeWorld)??t.list[0];n&&F(n.branch)}).catch(t=>{L("branches failed:",t),w("Failed to load branches","error")})}),P(()=>{const o=k(),t=E();!o||!t||(M(!0),S({}),C(""),z(!1),t.http.user.code.get(o).then(n=>{const d=n.modules??{};S(d),C(Object.keys(d)[0]??"")}).catch(n=>{L("get failed:",n),w("Failed to load code","error")}).finally(()=>M(!1)))});const I=()=>{const o=E(),t=k();!o||!t||(B(!0),o.http.user.code.set(t,m()).then(()=>{w("Code saved","success"),z(!1)}).catch(n=>{L("set failed:",n),w("Failed to save code","error")}).finally(()=>B(!1)))};return(()=>{var o=ue(),t=o.firstChild,n=t.firstChild,d=n.nextSibling,K=d.nextSibling,a=K.nextSibling,Q=a.nextSibling,X=t.nextSibling,V=X.firstChild,Y=V.firstChild,T=Y.nextSibling,D=V.nextSibling,y=D.firstChild,Z=y.firstChild,N=y.nextSibling;return d.addEventListener("change",e=>F(e.currentTarget.value)),r(d,b(R,{get each(){return A()},children:e=>(()=>{var i=pe();return r(i,()=>e.branch,null),r(i,()=>e.activeWorld?" ★":"",null),$(()=>i.value=e.branch),i})()})),r(t,b(j,{get when(){return x()},get children(){return ae()}}),a),a.$$click=I,r(a,()=>p()?"Saving…":"Save"),Q.$$click=()=>W.onClose(),r(T,b(j,{get when(){return _()},get children(){return ce()}}),null),r(T,b(R,{get each(){return J()},children:e=>(()=>{var i=xe();return i.$$click=()=>C(e),r(i,e),$(l=>{var v=s()===e?"#1f3158":"transparent",h=s()===e?"#58a6ff":"#c9d1d9",g=`2px solid ${s()===e?"#388bfd":"transparent"}`;return v!==l.e&&c(i,"background",l.e=v),h!==l.t&&c(i,"color",l.t=h),g!==l.a&&c(i,"border-left",l.a=g),l},{e:void 0,t:void 0,a:void 0}),i})()}),null),r(y,s,Z),ee(q,N),r(D,b(j,{get when(){return!s()},get children(){var e=fe();return r(e,()=>_()?"Loading code…":"Select a module"),e}}),null),$(e=>{var i=p()||_()||!x(),l=p()||!x()?"#161b22":"#1a3a2a",v=p()||!x()?"#484f58":"#3fb950",h=p()||!x()?"default":"pointer",g=s()?"block":"none",O=s()?"flex":"none";return i!==e.e&&(a.disabled=e.e=i),l!==e.t&&c(a,"background",e.t=l),v!==e.a&&c(a,"color",e.a=v),h!==e.o&&c(a,"cursor",e.o=h),g!==e.i&&c(y,"display",e.i=g),O!==e.n&&c(N,"display",e.n=O),e},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0,n:void 0}),$(()=>d.value=k()),o})()}oe(["click"]);export{ye as CodePanel};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var ce=Object.defineProperty;var he=(a,t,e)=>t in a?ce(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var w=(a,t,e)=>he(a,typeof t!="symbol"?t+"":t,e);import{B as de,d as me,c as fe,E as ue,O as we,a as ie,b as se,p as O,T as ge,i as U,g as oe,f as I,o as be,w as X,n as ye,m as ve,l as Re,q,u as xe,k as pe,t as Se}from"./index-BKZ4Y5Yn.js";import{l as V,h as D,q as Ce,p as H}from"./vendor-codemirror-BbK0dVBs.js";import{A as Me,a as F,G as Y,c as $,S as J,T as j}from"./vendor-pixi-CqiKBxHw.js";const ne="screeps-terrain-v1";async function Le(a,t,e){try{const o=await caches.open(ne),i=`/terrain/${a}_${t}_z${e}.webp`,s=new Request(i),n=await o.match(s);if(n)return await n.blob()}catch{}return null}async function Oe(a,t,e,o){try{const i=await caches.open(ne),s=`/terrain/${a}_${t}_z${e}.webp`,n=new Request(s),r=new Response(o);await i.put(n,r)}catch{}}async function Be(a){const t=new OffscreenCanvas(a.width,a.height),e=t.getContext("2d");if(!e)throw new Error("OffscreenCanvas 2D context not available");return e.drawImage(a,0,0),await t.convertToBlob({type:"image/webp"})}async function ke(a){return await createImageBitmap(a)}function Te(a){return new Worker("/assets/terrain.worker-D9zNeJfz.js",{name:a==null?void 0:a.name})}const{warn:De}=oe("MapRenderer"),ae=3,f=ae*50,Ee=[50,60,70,80,90,100,110],G=1,z=50,Ae=2600,_e=5,Q=.2,ee=5,Ie=ue,Ge=we,Ye=ie,Xe=se,He=4491519,$e=new Set(["w","r","pb","p","s","c","m","k"]),ze={H:13421772,O:13421772,U:5809919,L:4176208,K:10711543,Z:13801762,X:16273737},Ne=[16,24,32,40];class Ze{constructor(t){w(this,"app");w(this,"world");w(this,"boundsGraphics",null);w(this,"selectionGraphics",null);w(this,"safeModeGraphics",null);w(this,"safeModeRooms",new Set);w(this,"activeRooms",new Map);w(this,"roomPool",[]);w(this,"terrainBaked",new Set);w(this,"terrainData",new Map);w(this,"worker");w(this,"pendingBakes",new Map);w(this,"nextBakeId",0);w(this,"currentShard","shard0");w(this,"callbacks");w(this,"resizeObserver",null);w(this,"_destroyed",!1);w(this,"showRoomNames",!1);w(this,"worldBoundsSet",null);w(this,"lastVisibleBounds",null);w(this,"animTargetX",0);w(this,"animTargetY",0);w(this,"isAnimating",!1);w(this,"overlayMode","owner");w(this,"isDragging",!1);w(this,"hasDragged",!1);w(this,"dragStartX",0);w(this,"dragStartY",0);w(this,"dragWorldX",0);w(this,"dragWorldY",0);w(this,"lastVisibleKey","");w(this,"visibleDebounceTimer",null);w(this,"selectedRoom",null);w(this,"currentUserId",null);w(this,"badgeCache",new de);w(this,"lastCheckX",0);w(this,"lastCheckY",0);w(this,"lastCheckScale",0);this.app=new Me,this.callbacks=t,this.worker=new Te,this.worker.onmessage=e=>{const{id:o,bitmap:i}=e.data,s=this.pendingBakes.get(o);s&&(this.pendingBakes.delete(o),s.resolve(i))}}async init(t){const e=t.parentElement??t,{width:o,height:i}=e.getBoundingClientRect();await this.app.init({canvas:t,width:o,height:i,background:me,antialias:!1,preference:"webgl"}),this.resizeObserver=new ResizeObserver(s=>{const{width:n,height:r}=s[0].contentRect,d=this.app.screen.width,h=this.app.screen.height;this.app.renderer.resize(n,r),this.world.x+=(n-d)/2,this.world.y+=(r-h)/2}),this.resizeObserver.observe(e),this.world=new F,this.app.stage.addChild(this.world),this.boundsGraphics=new Y,this.world.addChild(this.boundsGraphics),this.selectionGraphics=new Y,this.world.addChild(this.selectionGraphics),this.safeModeGraphics=new Y,this.world.addChild(this.safeModeGraphics),this.setupInteraction(),this.app.ticker.add(()=>{if(this.isAnimating){const s=this.animTargetX-this.world.x,n=this.animTargetY-this.world.y;Math.abs(s)<.5&&Math.abs(n)<.5?(this.world.x=this.animTargetX,this.world.y=this.animTargetY,this.isAnimating=!1):(this.world.x+=s*.2,this.world.y+=n*.2)}this.checkVisibleRooms()})}get zoom(){var t;return((t=this.world)==null?void 0:t.scale.x)??1}setZoom(t){var h,y;if(!this.world)return;t=Math.max(Q,Math.min(ee,t));const e=this.world.scale.x;if(t===e)return;const o=this.app.screen.width/2,i=this.app.screen.height/2,s=(o-this.world.x)/e,n=(i-this.world.y)/e,r=this.getLOD(),d=this.zoom>=G;this.world.scale.set(t),this.world.x=o-s*t,this.world.y=i-n*t,this.getLOD()!==r&&this.applyLOD(),t>=G!==d&&this.updateAllNameLabels(),this.updateAllRoomScales(t),(y=(h=this.callbacks).onZoomChanged)==null||y.call(h,t),this.setSelectedRoom(this.selectedRoom),this.redrawSafeMode()}centerOn(t,e,o=!1){const i=t*f+f/2,s=e*f+f/2,n=this.world.scale.x,r=this.app.screen.width/2-i*n,d=this.app.screen.height/2-s*n;o?(this.animTargetX=r,this.animTargetY=d,this.isAnimating=!0):(this.isAnimating=!1,this.world.x=r,this.world.y=d)}async getTerrainBitmap(t,e,o){const i=this.currentShard;try{const s=await Le(i,t,e);if(s)return await ke(s);const n=this.nextBakeId++,r=new Promise((h,y)=>{this.pendingBakes.set(n,{roomName:t,lod:e,resolve:h,reject:y})});this.worker.postMessage({id:n,roomName:t,lod:e,raw:o});const d=await r;return Be(d).then(h=>{Oe(i,t,e,h)}).catch(h=>De("failed to save to terrainCache:",h)),d}catch{return null}}async setRoomTerrain(t,e){const o=e.raw;let i=!1;for(let h=0;h<o.length;h++)if(o[h]!==0){i=!0;break}if(!i){this.terrainBaked.add(t);return}const s=this.getOrCreate(t),n=this.getLOD();n===0&&this.terrainData.set(t,o);const r=await this.getTerrainBitmap(t,n,o);if(!r)return;if(!this.activeRooms.has(t)){r.close();return}const d=$.from(r);n===0?(s.texLo&&!s.texLo.destroyed&&s.texLo.destroy(!0),s.texLo=d,this.getLOD()===0&&s.texLo&&(s.terrainSprite.texture=s.texLo)):(s.texHi&&!s.texHi.destroyed&&s.texHi.destroy(!0),s.texHi=d,this.getLOD()===1&&s.texHi&&(s.terrainSprite.texture=s.texHi)),s.terrainSprite.width=f,s.terrainSprite.height=f,this.terrainBaked.add(t)}getLOD(){return this.zoom<G?0:1}async applyLOD(){const t=this.getLOD()===1,e=[];for(const[o,i]of this.activeRooms)if(this.terrainBaked.has(o))if(t&&!i.texHi){const s=this.terrainData.get(o);s&&(this.terrainData.delete(o),e.push(this.getTerrainBitmap(o,1,s).then(n=>{n&&this.activeRooms.has(o)?(i.texHi=$.from(n),this.getLOD()===1&&(i.terrainSprite.texture=i.texHi)):n&&n.close()})))}else{const s=t?i.texHi:i.texLo;s&&!s.destroyed&&(i.terrainSprite.texture=s)}await Promise.all(e)}setRoomMap2(t,e,o="live"){const s=this.getOrCreate(t).map2Graphics;s.alpha=o==="cache"?.6:1;const n=ae;s.clear();const r=e.r??[];for(const[R,v]of r)s.rect(R*n,v*n,n,n);r.length&&s.fill(fe);const d=e.w??[];for(const[R,v]of d)s.rect(R*n+.5,v*n+.5,n-1,n-1);d.length&&s.fill(4486980);const h=e.s??[];for(const[R,v]of h)s.circle((R+.5)*n,(v+.5)*n,2.5);h.length&&s.fill(Ie);const y=e.c??[];for(const[R,v]of y)s.circle((R+.5)*n,(v+.5)*n,2);y.length&&s.fill(Ge);const p=e.m??[];for(const[R,v]of p)s.circle((R+.5)*n,(v+.5)*n,2);p.length&&s.fill(Ye);const S=e.k??[];for(const[R,v]of S)s.circle((R+.5)*n,(v+.5)*n,2);S.length&&s.fill(Xe);const B=e.pb??[];for(const[R,v]of B)s.circle((R+.5)*n,(v+.5)*n,1.5);B.length&&s.fill(se);const k=e;for(const R in k){if($e.has(R))continue;const v=k[R];if(!Array.isArray(v)||v.length===0)continue;for(const[W,E]of v)s.circle((W+.5)*n,(E+.5)*n,1);const Z=R===this.currentUserId?He:16711680;s.fill(Z)}}clearRoomMap2(t){var e;(e=this.activeRooms.get(t))==null||e.map2Graphics.clear()}clearAllMap2(){for(const t of this.activeRooms.values())t.map2Graphics.clear()}setRoomOwned(t,e){const i=this.getOrCreate(t).ownerOverlay;i.clear(),e&&(i.rect(0,0,f,f),i.fill({color:10027008,alpha:.18}))}async setRoomBadge(t,e,o){const i=this.activeRooms.get(t);if(i){if(!e){i.badgeSprite&&(i.container.removeChild(i.badgeSprite),i.badgeSprite.destroy(),i.badgeSprite=void 0),i.badgeLevel=void 0;return}try{const s=await this.badgeCache.getOrCreate(e);if(!this.activeRooms.has(t))return;if(i.badgeSprite){if(i.badgeSprite.texture===s){i.badgeLevel=o,this.applyBadgeSize(i,this.zoom),this.applyOverlayMode(i);return}i.badgeSprite.texture=s}else{const n=new J(s);n.anchor.set(.5),n.x=f/2,n.y=f/2;const r=i.container.getChildIndex(i.nameLabel);i.container.addChildAt(n,r),i.badgeSprite=n}i.badgeLevel=o,this.applyBadgeSize(i,this.zoom),this.applyOverlayMode(i)}catch{}}}applyBadgeSize(t,e){if(!t.badgeSprite||t.badgeLevel===void 0)return;const i=(Ee[t.badgeLevel-1]??24)*Math.min(1,e);t.badgeSprite.width=i/e,t.badgeSprite.height=i/e}setOverlayMode(t){if(this.overlayMode!==t){this.overlayMode=t;for(const e of this.activeRooms.values())this.applyOverlayMode(e)}}setRoomMineral(t,e,o){const i=this.activeRooms.get(t);if(!i)return;if(!e||!o){i.mineralCircle&&(i.container.removeChild(i.mineralCircle),i.mineralCircle.destroy(),i.mineralCircle=void 0),i.mineralLabel&&(i.container.removeChild(i.mineralLabel),i.mineralLabel.destroy(),i.mineralLabel=void 0),i.mineralDensity=void 0;return}const s=ze[e]??ie;if(i.mineralDensity=o,i.mineralColor=s,!i.mineralCircle){const n=new Y;n.x=f/2,n.y=f/2;const r=i.container.getChildIndex(i.nameLabel);i.container.addChildAt(n,r),i.mineralCircle=n}if(i.mineralLabel)i.mineralLabel.text=e;else{const n=new j({text:e,style:{fontSize:36,fill:16777215,fontFamily:"ui-monospace, monospace",fontWeight:"bold"}});n.anchor.set(.5),n.x=f/2,n.y=f/2,i.container.addChild(n),i.mineralLabel=n}this.applyMineralSize(i,this.zoom),this.applyOverlayMode(i)}applyOverlayMode(t){t.badgeSprite&&(t.badgeSprite.visible=this.overlayMode==="owner"),t.mineralCircle&&(t.mineralCircle.visible=this.overlayMode==="mineral"),t.mineralLabel&&(t.mineralLabel.visible=this.overlayMode==="mineral")}applyMineralSize(t,e){if(!t.mineralCircle||!t.mineralLabel||t.mineralDensity===void 0||t.mineralColor===void 0)return;const o=Math.max(.5,Math.min(1.5,e)),i=(Ne[t.mineralDensity-1]??24)*o,s=i/2/e;t.mineralCircle.clear(),t.mineralCircle.circle(0,0,1),t.mineralCircle.fill(t.mineralColor);const r=2/e;t.mineralCircle.stroke({color:0,width:r/s}),t.mineralCircle.scale.set(s);const h=i*.55/36/e;t.mineralLabel.scale.set(h)}updateNameLabelScale(t,e){t.nameLabel.scale.set(.5/e)}updateAllRoomScales(t){for(const e of this.activeRooms.values())this.applyBadgeSize(e,t),this.updateNameLabelScale(e,t),this.applyMineralSize(e,t)}setCurrentUser(t){this.currentUserId=t}setSelectedRoom(t){if(this.selectedRoom=t,!this.selectionGraphics||(this.selectionGraphics.clear(),this.world.removeChild(this.selectionGraphics),this.world.addChild(this.selectionGraphics),!t))return;const e=O(t);if(!e)return;const o=e.x*f,i=e.y*f;this.selectionGraphics.rect(o,i,f,f);const s=Math.max(2,Math.ceil(2/this.zoom));this.selectionGraphics.stroke({color:16777215,width:s,alignment:0})}setRoomSafeMode(t,e){e?this.safeModeRooms.add(t):this.safeModeRooms.delete(t),this.redrawSafeMode()}redrawSafeMode(){if(!this.safeModeGraphics||(this.safeModeGraphics.clear(),this.safeModeRooms.size===0))return;const t=Math.max(1,Math.ceil(1/this.zoom));for(const e of this.safeModeRooms){const o=O(e);if(!o)continue;const i=o.x*f,s=o.y*f;this.safeModeGraphics.rect(i,s,f,f),this.safeModeGraphics.stroke({color:16776960,width:t,alignment:1,alpha:.5})}this.world.removeChild(this.safeModeGraphics),this.world.addChild(this.safeModeGraphics)}setBounds(t,e,o,i){if(!this.boundsGraphics)return;this.worldBoundsSet={minX:t,maxX:e,minY:o,maxY:i},this.boundsGraphics.clear();const s=t*f,n=o*f,r=(e-t+1)*f,d=(i-o+1)*f;this.boundsGraphics.rect(s,n,r,d),this.boundsGraphics.stroke({color:ge,width:6,alignment:0}),this.updateAllNameLabels()}clearBounds(){var t;this.worldBoundsSet=null,(t=this.boundsGraphics)==null||t.clear(),this.updateAllNameLabels()}setShowRoomNames(t){this.showRoomNames=t,this.updateAllNameLabels()}hasRoom(t){return this.terrainBaked.has(t)}clearRoom(t){const e=this.activeRooms.get(t);e&&(e.texLo&&!e.texLo.destroyed&&e.texLo.destroy(!0),e.texHi&&!e.texHi.destroyed&&e.texHi.destroy(!0),e.texLo=null,e.texHi=null,e.terrainSprite.texture=$.EMPTY,e.map2Graphics.clear(),e.ownerOverlay.clear(),e.badgeSprite&&(e.container.removeChild(e.badgeSprite),e.badgeSprite.destroy(),e.badgeSprite=void 0),e.mineralCircle&&(e.container.removeChild(e.mineralCircle),e.mineralCircle.destroy(),e.mineralCircle=void 0),e.mineralLabel&&(e.container.removeChild(e.mineralLabel),e.mineralLabel.destroy(),e.mineralLabel=void 0),e.mineralDensity=void 0,e.mineralColor=void 0,e.container.visible=!1,this.safeModeRooms.delete(t),this.terrainBaked.delete(t),this.terrainData.delete(t),this.activeRooms.delete(t),this.roomPool.length<Ae?this.roomPool.push(e):(this.world.removeChild(e.container),e.container.destroy({children:!0,context:!0})))}clearInvisibleRooms(t){const e=this.lastVisibleBounds;for(const o of[...this.activeRooms.keys()])if(!t.has(o)){if(e){const i=O(o);if(i&&i.x>=e.rxMin-z&&i.x<=e.rxMax+z&&i.y>=e.ryMin-z&&i.y<=e.ryMax+z)continue}this.clearRoom(o)}}destroy(){var t;if(!this._destroyed){this._destroyed=!0,(t=this.resizeObserver)==null||t.disconnect(),this.resizeObserver=null,this.visibleDebounceTimer!==null&&(clearTimeout(this.visibleDebounceTimer),this.visibleDebounceTimer=null);for(const[,e]of this.activeRooms)e.texLo&&!e.texLo.destroyed&&e.texLo.destroy(!0),e.texHi&&!e.texHi.destroyed&&e.texHi.destroy(!0);this.activeRooms.clear(),this.safeModeRooms.clear();for(const e of this.roomPool)e.texLo&&!e.texLo.destroyed&&e.texLo.destroy(!0),e.texHi&&!e.texHi.destroyed&&e.texHi.destroy(!0);this.roomPool.length=0,this.terrainBaked.clear(),this.terrainData.clear(),this.worker.terminate(),this.pendingBakes.clear(),this.badgeCache.destroy();try{this.app.destroy(!1,{children:!0,texture:!0,context:!0})}catch{}}}getOrCreate(t){const e=this.activeRooms.get(t);if(e)return e;const o=O(t);if(!o)throw new Error(`MapRenderer: invalid room "${t}"`);let i;if(this.roomPool.length>0)i=this.roomPool.pop();else{const s=new F;s.cullable=!0;const n=new J($.EMPTY),r=new Y,d=new Y;s.addChild(n),s.addChild(r),s.addChild(d);const h=new j({text:"",style:{fontSize:36,fill:9147550,fontFamily:"ui-monospace, monospace"}});h.scale.set(.25),h.x=2,h.y=2,s.addChild(h),this.world.addChild(s),i={container:s,terrainSprite:n,texLo:null,texHi:null,map2Graphics:r,ownerOverlay:d,nameLabel:h}}return i.container.x=o.x*f,i.container.y=o.y*f,i.container.visible=!0,i.nameLabel.text=t,i.nameLabel.visible=this.showRoomNames&&this.zoom>=G&&this.nameLabelShouldShow(o.x,o.y),this.updateNameLabelScale(i,this.zoom),i.badgeSprite&&(i.container.removeChild(i.badgeSprite),i.badgeSprite.destroy(),i.badgeSprite=void 0),i.mineralCircle&&(i.container.removeChild(i.mineralCircle),i.mineralCircle.destroy(),i.mineralCircle=void 0),i.mineralLabel&&(i.container.removeChild(i.mineralLabel),i.mineralLabel.destroy(),i.mineralLabel=void 0),i.mineralDensity=void 0,i.mineralColor=void 0,this.safeModeGraphics&&(this.world.removeChild(this.safeModeGraphics),this.world.addChild(this.safeModeGraphics)),this.selectionGraphics&&(this.world.removeChild(this.selectionGraphics),this.world.addChild(this.selectionGraphics)),this.activeRooms.set(t,i),i}nameLabelShouldShow(t,e){const o=this.worldBoundsSet;return!(o&&(t<o.minX||t>o.maxX||e<o.minY||e>o.maxY))}updateAllNameLabels(){const t=this.showRoomNames&&this.zoom>=G;for(const[e,o]of this.activeRooms){if(!t){o.nameLabel.visible=!1;continue}const i=O(e);i&&(o.nameLabel.visible=this.nameLabelShouldShow(i.x,i.y))}}setupInteraction(){const t=this.app.canvas;t.style.touchAction="none",t.style.userSelect="none",t.addEventListener("pointermove",e=>{if(this.isDragging)return;const o=t.getBoundingClientRect();this.emitHover(e.clientX-o.left,e.clientY-o.top)}),t.addEventListener("pointerleave",()=>{this.isDragging||this.callbacks.onRoomHover(null)}),t.addEventListener("pointerdown",e=>{e.preventDefault(),this.isAnimating=!1,this.isDragging=!0,this.hasDragged=!1,this.dragStartX=e.clientX,this.dragStartY=e.clientY,this.dragWorldX=this.world.x,this.dragWorldY=this.world.y;const o=n=>{const r=n.clientX-this.dragStartX,d=n.clientY-this.dragStartY;(Math.abs(r)>3||Math.abs(d)>3)&&(this.hasDragged=!0);const h=this.worldBoundsSet;if(h){const y=this.world.scale.x,p=50,S=p-(h.maxX+1)*f*y,B=this.app.screen.width-p-h.minX*f*y,k=p-(h.maxY+1)*f*y,R=this.app.screen.height-p-h.minY*f*y;this.world.x=this.rubberBand(this.dragWorldX+r,S,B),this.world.y=this.rubberBand(this.dragWorldY+d,k,R)}else this.world.x=this.dragWorldX+r,this.world.y=this.dragWorldY+d},i=n=>{if(!this.hasDragged){const r=t.getBoundingClientRect(),d=this.screenToRoom(n.clientX-r.left,n.clientY-r.top);d&&this.callbacks.onRoomClick(d)}s()},s=()=>{this.isDragging=!1,this.springBack(),window.removeEventListener("pointermove",o),window.removeEventListener("pointerup",i),window.removeEventListener("pointercancel",s)};window.addEventListener("pointermove",o),window.addEventListener("pointerup",i),window.addEventListener("pointercancel",s)}),t.addEventListener("wheel",e=>{var y,p;if(e.preventDefault(),this.isDragging)return;this.isAnimating=!1;const o=this.world.scale.x,i=e.deltaY<0?1.1:.9,s=Math.max(Q,Math.min(ee,o*i)),n=(e.offsetX-this.world.x)/o,r=(e.offsetY-this.world.y)/o,d=this.getLOD(),h=this.zoom>=G;this.world.scale.set(s),this.world.x=e.offsetX-n*s,this.world.y=e.offsetY-r*s,this.getLOD()!==d&&this.applyLOD(),s>=G!==h&&this.updateAllNameLabels(),this.updateAllRoomScales(s),(p=(y=this.callbacks).onZoomChanged)==null||p.call(y,s),this.setSelectedRoom(this.selectedRoom),this.redrawSafeMode()},{passive:!1})}rubberBand(t,e,o){const i=o-e;if(i<=0||t>=e&&t<=o)return t;const s=.55;if(t<e){const r=e-t;return e-(1-1/(r*s/i+1))*i*s}const n=t-o;return o+(1-1/(n*s/i+1))*i*s}springBack(){const t=this.worldBoundsSet;if(!t)return;const e=this.world.scale.x,o=this.app.screen.width,i=this.app.screen.height,s=50,n=this.world.x+t.minX*f*e,r=this.world.x+(t.maxX+1)*f*e,d=this.world.y+t.minY*f*e,h=this.world.y+(t.maxY+1)*f*e;let y=this.world.x,p=this.world.y;r<s?y+=s-r:n>o-s&&(y-=n-(o-s)),h<s?p+=s-h:d>i-s&&(p-=d-(i-s)),(y!==this.world.x||p!==this.world.y)&&(this.animTargetX=y,this.animTargetY=p,this.isAnimating=!0)}screenToRoom(t,e){const o=this.world.scale.x,i=(t-this.world.x)/o,s=(e-this.world.y)/o,n=Math.floor(i/f),r=Math.floor(s/f);return U(n,r)}emitHover(t,e){this.callbacks.onRoomHover(this.screenToRoom(t,e))}checkVisibleRooms(){const t=this.world.scale.x,e=this.world.x,o=this.world.y;if(this.lastCheckX===e&&this.lastCheckY===o&&this.lastCheckScale===t)return;this.lastCheckX=e,this.lastCheckY=o,this.lastCheckScale=t;const i=-e/t,s=-o/t,n=(this.app.screen.width-e)/t,r=(this.app.screen.height-o)/t,d=Math.floor(i/f)-1,h=Math.ceil(n/f),y=Math.floor(s/f)-1,p=Math.ceil(r/f);this.lastVisibleBounds={rxMin:d,rxMax:h,ryMin:y,ryMax:p};const S=[];for(let k=d;k<=h;k++)for(let R=y;R<=p;R++){const v=U(k,R);v&&S.push(v)}const B=`${d},${y},${h},${p}`;B!==this.lastVisibleKey&&(this.lastVisibleKey=B,this.visibleDebounceTimer!==null&&clearTimeout(this.visibleDebounceTimer),this.visibleDebounceTimer=setTimeout(()=>{this.visibleDebounceTimer=null,this.callbacks.onVisibleRoomsChanged(S)},_e))}}var We=Se("<div style=width:100%;height:100%;position:relative><canvas style=display:block>");const{log:N,error:te}=oe("map");function qe(a){let t,e=null;const[o,i]=V([]),[s,n]=V(1),r=()=>a.originRoom,[d,h]=V(r()??null);let y=null,p=null;const S=new Map,B=new Map,k=new Map,R=l=>{const c=X();if(!c)return!0;const g=O(l);return!!g&&pe(g.x,g.y,c)},v=l=>{var g;const c=B.get(l);return{room:l,owner:(c==null?void 0:c.username)??((g=c==null?void 0:c.own)!=null&&g.user?`user:${c.own.user}`:null),mineral:(c==null?void 0:c.mineral)??null,density:(c==null?void 0:c.density)??null}},Z=200,W=0;let E=[],_=null;const K=()=>{_=null;const l=I();if(!l||!e)return;const c=new Set(o());if(E=E.filter(m=>c.has(m)&&!e.hasRoom(m)),E.length===0)return;const g=E.splice(0,Z);l.stores.room.terrainBulk(g,a.shard).then(m=>{for(const[u,b]of m)e==null||e.setRoomTerrain(u,b)}).catch(m=>te("terrain fetch failed:",m)).finally(()=>{E.length>0&&(_=setTimeout(K,W))})};return D(()=>{I(),a.shard,B.clear()}),Ce(()=>{t&&(async()=>{var c,g;if(e=new Ze({onRoomHover:m=>{var u;(u=a.onHoveredRoomChanged)==null||u.call(a,m?v(m):null)},onRoomClick:m=>{var u;d()!==m?(h(m),e==null||e.setSelectedRoom(m),(u=a.onSelectedRoomChanged)==null||u.call(a,v(m))):R(m)&&setTimeout(()=>a.onNavigateToRoom(m),0)},onVisibleRoomsChanged:m=>{const u=m.length===0;p!==u&&(p=u,u||N(`zoom in — terrain loading active, ${m.length} rooms visible`)),i(m)},onZoomChanged:m=>{var u;n(m),(u=a.onZoomChanged)==null||u.call(a,m)}}),await e.init(t),!e)return;a.initialZoom!==void 0&&a.initialZoom>0&&e.setZoom(a.initialZoom),(c=a.onZoomChanged)==null||c.call(a,e.zoom);const l=X();if(l&&e.setBounds(l.minX,l.maxX,l.minY,l.maxY),a.originRoom){const m=O(a.originRoom);m&&e.centerOn(m.x,m.y),e.setSelectedRoom(a.originRoom),(g=a.onSelectedRoomChanged)==null||g.call(a,v(a.originRoom))}else{const m=I();if(m)try{const u=await m.http.user.worldStartRoom(a.shard??"shard0");if(!e)return;const b=Array.isArray(u==null?void 0:u.room)?u.room[0]:u==null?void 0:u.room;if(typeof b=="string"){const x=O(b);x&&e.centerOn(x.x,x.y)}}catch(u){te("worldStartRoom failed:",u)}}})()}),H(()=>{_!==null&&(clearTimeout(_),_=null),E=[];for(const l of S.values())l.dispose();S.clear(),e==null||e.destroy(),e=null}),D(()=>{be({currentRoom:d,worldBounds:X,onMove:(g,m)=>{var b,x;const u=U(g,m);h(u),e==null||e.setSelectedRoom(u),e==null||e.centerOn(g,m,!0),(b=a.onSelectedRoomChanged)==null||b.call(a,v(u)),(x=a.onHoveredRoomChanged)==null||x.call(a,v(u))}});const c=g=>{var b,x;const m=((b=g.target)==null?void 0:b.tagName)??"",u=((x=g.target)==null?void 0:x.isContentEditable)??!1;if(!(m==="INPUT"||m==="TEXTAREA"||u)&&g.key==="m"){const C=d();C&&R(C)&&a.onNavigateToRoom(C)}};window.addEventListener("keydown",c),H(()=>window.removeEventListener("keydown",c))}),D(()=>{var x;const l=I(),c=o(),g=a.shard;if(!l||c.length===0)return;const m=new Set(c),u=c.filter(C=>!(e!=null&&e.hasRoom(C)));if(u.length>0){const C=c.reduce((T,A)=>{var L;return T+(((L=O(A))==null?void 0:L.x)??0)},0)/c.length,M=c.reduce((T,A)=>{var L;return T+(((L=O(A))==null?void 0:L.y)??0)},0)/c.length;E=u.slice().sort((T,A)=>{const L=O(T),P=O(A),re=L?Math.abs(L.x-C)+Math.abs(L.y-M):999,le=P?Math.abs(P.x-C)+Math.abs(P.y-M):999;return re-le}),_===null&&(_=setTimeout(K,0))}l.stores.mapStats.request(c,"owner0",g??void 0);const b=s()>=.4;if(b!==y&&(y=b,(x=a.onSubscriptionStateChanged)==null||x.call(a,b),b||e==null||e.clearAllMap2()),b){const C=new Set(c.map(M=>`${M}/${g}`));for(const[M,T]of S)C.has(M)||(T.dispose(),S.delete(M),e==null||e.clearRoomMap2(M.split("/")[0]));for(const M of c){const T=`${M}/${g}`;S.has(T)||S.set(T,l.stores.map.subscribeMap2(M,g))}}else{for(const[,C]of S)C.dispose();S.clear()}e==null||e.clearInvisibleRooms(m)}),D(()=>{e==null||e.setShowRoomNames(ye()),e&&(e.currentShard=a.shard??"shard0")}),D(()=>{e==null||e.setOverlayMode(ve())}),D(()=>{const l=I(),c=a.shard;l&&l.stores.server.worldInfo(c??void 0).then(g=>{N(`worldInfo(shard=${c??"none"}) — x: [${g.minX}, ${g.maxX}] y: [${g.minY}, ${g.maxY}]`),Re(g)}).catch(g=>{})}),D(()=>{var l;e==null||e.setCurrentUser(((l=q())==null?void 0:l._id)??null)}),D(()=>{const l=X();l?(e==null||e.setBounds(l.minX,l.maxX,l.minY,l.maxY),N(`worldBounds applied — shard: ${a.shard??"none"} x: [${l.minX}, ${l.maxX}] y: [${l.minY}, ${l.maxY}] (fetched for shard: ${l.shard??"none"})`)):(e==null||e.clearBounds(),N(`worldBounds — none (shard: ${a.shard??"none"})`))}),D(()=>{const l=I();if(!l)return;const c=l.stores.map.on("room:map2update",({room:g,shard:m,data:u,source:b})=>{m===a.shard&&(e==null||e.setRoomMap2(g,u,b))});H(()=>c.dispose())}),D(()=>{var u;const l=I();if(!l)return;const c=(u=q())==null?void 0:u._id,g=new Set(o()),m=l.stores.mapStats.on("mapStats:room",({room:b,stat:x})=>{var A,L;B.set(b,x);const C=!!(x.own&&x.own.user!==c);g.has(b)&&(e==null||e.setRoomOwned(b,C),e==null||e.setRoomSafeMode(b,!!x.safeMode)),e==null||e.setRoomMineral(b,x.mineral,x.density);const M=x.badge?JSON.stringify(x.badge):"";k.get(b)!==M&&(k.set(b,M),e==null||e.setRoomBadge(b,x.badge,(A=x.own)==null?void 0:A.level)),d()===b&&((L=a.onSelectedRoomChanged)==null||L.call(a,v(b)))});H(()=>m.dispose())}),(()=>{var l=We(),c=l.firstChild;return xe(g=>t=g,c),l})()}export{qe as MapViewer};
|