xxscreeps-mod-client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/backend.js +110 -0
- package/dist/assets/BufferResource-wp05kXJi.js +185 -0
- package/dist/assets/CanvasRenderer-oAjr4VPy.js +1 -0
- package/dist/assets/Filter-DCFwFDCZ.js +1 -0
- package/dist/assets/RenderTargetSystem-BADEJjVe.js +184 -0
- package/dist/assets/WebGLRenderer-CkUVdJjj.js +156 -0
- package/dist/assets/WebGPURenderer-CDYm-Qve.js +41 -0
- package/dist/assets/browserAll-DRs0HlcT.js +14 -0
- package/dist/assets/canvasUtils--etq-uaC.js +1 -0
- package/dist/assets/index-Cf0rVPz-.js +274 -0
- package/dist/assets/terrain.worker-D9zNeJfz.js +1 -0
- package/dist/assets/webworkerAll-Bs2LlyVn.js +83 -0
- package/dist/backend.js +110 -0
- package/dist/index.html +27 -0
- package/dist/index.js +3 -0
- package/dist/package.json +7 -0
- package/index.js +3 -0
- package/package.json +33 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){"use strict";var R=(o=>(o[o.Plain=0]="Plain",o[o.Wall=1]="Wall",o[o.Swamp=2]="Swamp",o))(R||{});function v(o){const f=Math.round(o).toString(16);return f.length<2?"0"+f:f}function d(o,f,i){const e=(1-Math.abs(2*i-1))*f,l=o/60,t=e*(1-Math.abs(l%2-1));let n=0,s=0,r=0;!Number.isNaN(o)&&o!==null&&o!==void 0&&(l>=0&&l<1?(n=e,s=t,r=0):l>=1&&l<2?(n=t,s=e,r=0):l>=2&&l<3?(n=0,s=e,r=t):l>=3&&l<4?(n=0,s=t,r=e):l>=4&&l<5?(n=t,s=0,r=e):l>=5&&l<6&&(n=e,s=0,r=t));const c=i-e/2,h=(n+c)*255,m=(s+c)*255,b=(r+c)*255;return"#"+v(h)+v(m)+v(b)}function P(){const o=[];let f=0;o.push({index:f++,rgb:d(0,0,.8)});for(let i=0;i<19;i++)o.push({index:f++,rgb:d(i*360/19,.6,.8)});o.push({index:f++,rgb:d(0,0,.5)});for(let i=0;i<19;i++)o.push({index:f++,rgb:d(i*360/19,.7,.5)});o.push({index:f++,rgb:d(0,0,.3)});for(let i=0;i<19;i++)o.push({index:f++,rgb:d(i*360/19,.4,.3)});o.push({index:f++,rgb:d(0,0,.1)});for(let i=0;i<19;i++)o.push({index:f++,rgb:d(i*360/19,.5,.1)});return o}P();const A=2962235,g=856343,M=4020797,W=[128,512];function S(o){return`rgb(${o>>16&255},${o>>8&255},${o&255})`}function I(o,f,i,e){for(let l=0;l<2500;l++)if(f[l]===i){const t=l%50,n=Math.floor(l/50),s=Math.round(t*e),r=Math.round(n*e);o.fillRect(s,r,Math.round((t+1)*e)-s,Math.round((n+1)*e)-r)}}function N(o,f,i,e){const l=e/2,t=Math.PI;o.beginPath();for(let n=0;n<50;n++)for(let s=0;s<50;s++){const r=f[n*50+s]===i,c=n>0&&f[(n-1)*50+s]===i,h=n<49&&f[(n+1)*50+s]===i,m=s>0&&f[n*50+(s-1)]===i,b=s<49&&f[n*50+(s+1)]===i,a=s*e+l,u=n*e+l;r?!c&&!m&&n>0&&s>0?(o.moveTo(a,n*e),o.arc(a,u,l,-t/2,t,!0),o.lineTo(a,u)):o.rect(s*e,n*e,l,l):c&&m&&f[(n-1)*50+(s-1)]===i&&(o.moveTo(a,n*e),o.lineTo(s*e,n*e),o.lineTo(s*e,u),o.arc(a,u,l,t,-t/2,!1)),r?!c&&!b&&n>0&&s<49?(o.moveTo(a,n*e),o.arc(a,u,l,-t/2,0,!1),o.lineTo(a,u)):o.rect(a,n*e,l,l):c&&b&&f[(n-1)*50+(s+1)]===i&&(o.moveTo(a,n*e),o.lineTo(s*e+e,n*e),o.lineTo(s*e+e,u),o.arc(a,u,l,0,-t/2,!0)),r?!h&&!m&&n<49&&s>0?(o.moveTo(s*e,u),o.arc(a,u,l,t,t/2,!0),o.lineTo(a,u)):o.rect(s*e,u,l,l):h&&m&&f[(n+1)*50+(s-1)]===i&&(o.moveTo(s*e,u),o.lineTo(s*e,n*e+e),o.lineTo(a,n*e+e),o.arc(a,u,l,t/2,t,!1)),r?!h&&!b&&n<49&&s<49?(o.moveTo(a,n*e+e),o.arc(a,u,l,t/2,0,!0),o.lineTo(a,u)):o.rect(a,u,l,l):h&&b&&f[(n+1)*50+(s+1)]===i&&(o.moveTo(a,n*e+e),o.lineTo(s*e+e,n*e+e),o.lineTo(s*e+e,u),o.arc(a,u,l,0,t/2,!1))}o.fill()}self.onmessage=o=>{const{id:f,roomName:i,lod:e,raw:l}=o.data,t=W[e]||128,n=t/50,s=new OffscreenCanvas(t,t),r=s.getContext("2d",{alpha:!1});if(!r)return;r.fillStyle=S(A),r.fillRect(0,0,t,t),e>=1?(r.fillStyle=S(M),N(r,l,R.Swamp,n),r.fillStyle=S(g),N(r,l,R.Wall,n)):(r.fillStyle=S(M),I(r,l,R.Swamp,n),r.fillStyle=S(g),I(r,l,R.Wall,n));const c=s.transferToImageBitmap();self.postMessage({id:f,roomName:i,lod:e,bitmap:c},{transfer:[c]})}})();
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import{M as k,f as O,ad as A,c as P,k as b,q as M,o as U,Q as E,b as z,H as _,T as v,n as V,u as Y,ap as q,a4 as R}from"./index-Cf0rVPz-.js";import{a as X}from"./canvasUtils--etq-uaC.js";import{F as L}from"./Filter-DCFwFDCZ.js";const y=new k;function G(m,e){e.clear();const t=e.matrix;for(let r=0;r<m.length;r++){const i=m[r];if(i.globalDisplayStatus<7)continue;const n=i.renderGroup??i.parentRenderGroup;n!=null&&n.isCachedAsTexture?e.matrix=y.copyFrom(n.textureOffsetInverseTransform).append(i.worldTransform):n!=null&&n._parentCacheAsTextureRenderGroup?e.matrix=y.copyFrom(n._parentCacheAsTextureRenderGroup.inverseWorldTransform).append(i.groupTransform):e.matrix=i.worldTransform,e.addBounds(i.bounds)}return e.matrix=t,e}function S(m){return typeof m.getCanvasFilterString=="function"}class W{constructor(){this.skip=!1,this.useClip=!1,this.filters=null,this.container=null,this.bounds=new P,this.cssFilterString=""}}class C{constructor(e){this._filterStack=[],this._filterStackIndex=0,this._savedStates=[],this._alphaMultiplier=1,this._warnedFilterTypes=new Set,this.renderer=e}push(e){const t=this._pushFilterFrame(),r=e.filterEffect.filters;if(t.skip=!1,t.useClip=!1,t.filters=r,t.container=e.container,t.cssFilterString="",r.every(o=>!o.enabled)){t.skip=!0;return}const i=[],n=1;for(const o of r){if(!o.enabled)continue;if(!S(o)){this._warnUnsupportedFilter(o);continue}const l=o.getCanvasFilterString();if(l===null){this._warnUnsupportedFilter(o);continue}l&&i.push(l)}if(i.length===0&&n===1){t.skip=!0;return}t.cssFilterString=i.join(" "),this._calculateFilterArea(e,t.bounds),t.useClip=!!e.filterEffect.filterArea;const s=this.renderer.canvasContext.activeContext,a=s.filter||"none";if(this._savedStates.push({filter:a,alphaMultiplier:this._alphaMultiplier}),t.useClip&&Number.isFinite(t.bounds.width)&&Number.isFinite(t.bounds.height)&&t.bounds.width>0&&t.bounds.height>0){const o=this.renderer.canvasContext.activeResolution||1;s.save(),s.setTransform(1,0,0,1,0,0),s.beginPath(),s.rect(t.bounds.x*o,t.bounds.y*o,t.bounds.width*o,t.bounds.height*o),s.clip()}else t.useClip=!1;t.cssFilterString&&(s.filter=a!=="none"?`${a} ${t.cssFilterString}`:t.cssFilterString)}pop(){const e=this._popFilterFrame();if(e.skip)return;const t=this._savedStates.pop();if(!t)return;const r=this.renderer.canvasContext.activeContext;e.useClip?r.restore():r.filter=t.filter,this._alphaMultiplier=t.alphaMultiplier}generateFilteredTexture({texture:e,filters:t}){if(!(t!=null&&t.length)||t.every(d=>!d.enabled))return e;const r=[],i=1;for(const d of t){if(!d.enabled)continue;if(!S(d)){this._warnUnsupportedFilter(d);continue}const T=d.getCanvasFilterString();if(T===null){this._warnUnsupportedFilter(d);continue}T&&r.push(T)}if(r.length===0&&i===1)return e;const n=X.getCanvasSource(e);if(!n)return e;const s=e.frame,a=e.source._resolution??e.source.resolution??1,o=s.width,l=s.height,f=O.getOptimalCanvasAndContext(o,l,a),{canvas:c,context:u}=f;u.setTransform(1,0,0,1,0,0),u.clearRect(0,0,c.width,c.height),r.length&&(u.filter=r.join(" "));const p=s.x*a,h=s.y*a,x=o*a,F=l*a;return u.drawImage(n,p,h,x,F,0,0,x,F),u.filter="none",u.globalAlpha=1,A(c,o,l,a)}_calculateFilterArea(e,t){if(e.renderables?G(e.renderables,t):e.filterEffect.filterArea?(t.clear(),t.addRect(e.filterEffect.filterArea),t.applyMatrix(e.container.worldTransform)):e.container.getFastGlobalBounds(!0,t),e.container){const r=e.container.renderGroup||e.container.parentRenderGroup,i=r==null?void 0:r.cacheToLocalTransform;i&&t.applyMatrix(i)}}_warnUnsupportedFilter(e){var r;const t=((r=e==null?void 0:e.constructor)==null?void 0:r.name)||"Filter";this._warnedFilterTypes.has(t)||(this._warnedFilterTypes.add(t),console.warn(`CanvasRenderer: filter "${t}" is not supported in Canvas2D and will be skipped.`))}get alphaMultiplier(){return this._alphaMultiplier}_pushFilterFrame(){let e=this._filterStack[this._filterStackIndex];return e||(e=this._filterStack[this._filterStackIndex]=new W),this._filterStackIndex++,e}_popFilterFrame(){return this._filterStackIndex<=0?this._filterStack[0]:(this._filterStackIndex--,this._filterStack[this._filterStackIndex])}destroy(){this._filterStack=null,this._savedStates=null,this._warnedFilterTypes=null,this._alphaMultiplier=1}}C.extension={type:[b.CanvasSystem],name:"filter"};var j=`in vec2 aPosition;
|
|
2
|
+
out vec2 vTextureCoord;
|
|
3
|
+
|
|
4
|
+
uniform vec4 uInputSize;
|
|
5
|
+
uniform vec4 uOutputFrame;
|
|
6
|
+
uniform vec4 uOutputTexture;
|
|
7
|
+
|
|
8
|
+
vec4 filterVertexPosition( void )
|
|
9
|
+
{
|
|
10
|
+
vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;
|
|
11
|
+
|
|
12
|
+
position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;
|
|
13
|
+
position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;
|
|
14
|
+
|
|
15
|
+
return vec4(position, 0.0, 1.0);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
vec2 filterTextureCoord( void )
|
|
19
|
+
{
|
|
20
|
+
return aPosition * (uOutputFrame.zw * uInputSize.zw);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
void main(void)
|
|
24
|
+
{
|
|
25
|
+
gl_Position = filterVertexPosition();
|
|
26
|
+
vTextureCoord = filterTextureCoord();
|
|
27
|
+
}
|
|
28
|
+
`,N=`in vec2 vTextureCoord;
|
|
29
|
+
out vec4 finalColor;
|
|
30
|
+
uniform sampler2D uTexture;
|
|
31
|
+
void main() {
|
|
32
|
+
finalColor = texture(uTexture, vTextureCoord);
|
|
33
|
+
}
|
|
34
|
+
`,w=`struct GlobalFilterUniforms {
|
|
35
|
+
uInputSize: vec4<f32>,
|
|
36
|
+
uInputPixel: vec4<f32>,
|
|
37
|
+
uInputClamp: vec4<f32>,
|
|
38
|
+
uOutputFrame: vec4<f32>,
|
|
39
|
+
uGlobalFrame: vec4<f32>,
|
|
40
|
+
uOutputTexture: vec4<f32>,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
@group(0) @binding(0) var <uniform> gfu: GlobalFilterUniforms;
|
|
44
|
+
@group(0) @binding(1) var uTexture: texture_2d<f32>;
|
|
45
|
+
@group(0) @binding(2) var uSampler: sampler;
|
|
46
|
+
|
|
47
|
+
struct VSOutput {
|
|
48
|
+
@builtin(position) position: vec4<f32>,
|
|
49
|
+
@location(0) uv: vec2<f32>
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
fn filterVertexPosition(aPosition: vec2<f32>) -> vec4<f32>
|
|
53
|
+
{
|
|
54
|
+
var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;
|
|
55
|
+
|
|
56
|
+
position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;
|
|
57
|
+
position.y = position.y * (2.0 * gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;
|
|
58
|
+
|
|
59
|
+
return vec4(position, 0.0, 1.0);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
fn filterTextureCoord(aPosition: vec2<f32>) -> vec2<f32>
|
|
63
|
+
{
|
|
64
|
+
return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@vertex
|
|
68
|
+
fn mainVertex(
|
|
69
|
+
@location(0) aPosition: vec2<f32>,
|
|
70
|
+
) -> VSOutput {
|
|
71
|
+
return VSOutput(
|
|
72
|
+
filterVertexPosition(aPosition),
|
|
73
|
+
filterTextureCoord(aPosition)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@fragment
|
|
78
|
+
fn mainFragment(
|
|
79
|
+
@location(0) uv: vec2<f32>,
|
|
80
|
+
) -> @location(0) vec4<f32> {
|
|
81
|
+
return textureSample(uTexture, uSampler, uv);
|
|
82
|
+
}
|
|
83
|
+
`;class $ extends L{constructor(){const e=M.from({vertex:{source:w,entryPoint:"mainVertex"},fragment:{source:w,entryPoint:"mainFragment"},name:"passthrough-filter"}),t=U.from({vertex:j,fragment:N,name:"passthrough-filter"});super({gpuProgram:e,glProgram:t})}}class I{constructor(e){this._renderer=e}push(e,t,r){this._renderer.renderPipes.batch.break(r),r.add({renderPipeId:"filter",canBundle:!1,action:"pushFilter",container:t,filterEffect:e})}pop(e,t,r){this._renderer.renderPipes.batch.break(r),r.add({renderPipeId:"filter",action:"popFilter",canBundle:!1})}execute(e){e.action==="pushFilter"?this._renderer.filter.push(e):e.action==="popFilter"&&this._renderer.filter.pop()}destroy(){this._renderer=null}}I.extension={type:[b.WebGLPipes,b.WebGPUPipes,b.CanvasPipes],name:"filter"};const H=new V({attributes:{aPosition:{buffer:new Float32Array([0,0,1,0,1,1,0,1]),format:"float32x2",stride:8,offset:0}},indexBuffer:new Uint32Array([0,1,2,0,2,3])});class Q{constructor(){this.skip=!1,this.inputTexture=null,this.backTexture=null,this.filters=null,this.bounds=new P,this.container=null,this.blendRequired=!1,this.outputRenderSurface=null,this.globalFrame={x:0,y:0,width:0,height:0},this.firstEnabledIndex=-1,this.lastEnabledIndex=-1}}class B{constructor(e){this._filterStackIndex=0,this._filterStack=[],this._filterGlobalUniforms=new E({uInputSize:{value:new Float32Array(4),type:"vec4<f32>"},uInputPixel:{value:new Float32Array(4),type:"vec4<f32>"},uInputClamp:{value:new Float32Array(4),type:"vec4<f32>"},uOutputFrame:{value:new Float32Array(4),type:"vec4<f32>"},uGlobalFrame:{value:new Float32Array(4),type:"vec4<f32>"},uOutputTexture:{value:new Float32Array(4),type:"vec4<f32>"}}),this._globalFilterBindGroup=new z({}),this.renderer=e}get activeBackTexture(){var e;return(e=this._activeFilterData)==null?void 0:e.backTexture}push(e){const t=this.renderer,r=e.filterEffect.filters,i=this._pushFilterData();i.skip=!1,i.filters=r,i.container=e.container,i.outputRenderSurface=t.renderTarget.renderSurface;const n=t.renderTarget.renderTarget.colorTexture.source,s=n.resolution,a=n.antialias;if(r.every(p=>!p.enabled)){i.skip=!0;return}const o=i.bounds;if(this._calculateFilterArea(e,o),this._calculateFilterBounds(i,t.renderTarget.rootViewPort,a,s,1),i.skip)return;const l=this._getPreviousFilterData(),f=this._findFilterResolution(s);let c=0,u=0;l&&(c=l.bounds.minX,u=l.bounds.minY),this._calculateGlobalFrame(i,c,u,f,n.width,n.height),this._setupFilterTextures(i,o,t,l)}generateFilteredTexture({texture:e,filters:t}){const r=this._pushFilterData();this._activeFilterData=r,r.skip=!1,r.filters=t;const i=e.source,n=i.resolution,s=i.antialias;if(t.every(p=>!p.enabled))return r.skip=!0,e;const a=r.bounds;if(a.addRect(e.frame),this._calculateFilterBounds(r,a.rectangle,s,n,0),r.skip)return e;const o=n;this._calculateGlobalFrame(r,0,0,o,i.width,i.height),r.outputRenderSurface=_.getOptimalTexture(a.width,a.height,r.resolution,r.antialias),r.backTexture=v.EMPTY,r.inputTexture=e,this.renderer.renderTarget.finishRenderPass(),this._applyFiltersToTexture(r,!0);const u=r.outputRenderSurface;return u.source.alphaMode="premultiplied-alpha",u}pop(){const e=this.renderer,t=this._popFilterData();t.skip||(e.globalUniforms.pop(),e.renderTarget.finishRenderPass(),this._activeFilterData=t,this._applyFiltersToTexture(t,!1),t.blendRequired&&_.returnTexture(t.backTexture),_.returnTexture(t.inputTexture))}getBackTexture(e,t,r){const i=e.colorTexture.source._resolution,n=_.getOptimalTexture(t.width,t.height,i,!1);let s=t.minX,a=t.minY;r&&(s-=r.minX,a-=r.minY),s=Math.floor(s*i),a=Math.floor(a*i);const o=Math.ceil(t.width*i),l=Math.ceil(t.height*i);return this.renderer.renderTarget.copyToTexture(e,n,{x:s,y:a},{width:o,height:l},{x:0,y:0}),n}applyFilter(e,t,r,i){const n=this.renderer,s=this._activeFilterData,o=s.outputRenderSurface===r,l=n.renderTarget.rootRenderTarget.colorTexture.source._resolution,f=this._findFilterResolution(l);let c=0,u=0;if(o){const h=this._findPreviousFilterOffset();c=h.x,u=h.y}this._updateFilterUniforms(t,r,s,c,u,f,o,i);const p=e.enabled?e:this._getPassthroughFilter();this._setupBindGroupsAndRender(p,t,n)}calculateSpriteMatrix(e,t){const r=this._activeFilterData,i=e.set(r.inputTexture._source.width,0,0,r.inputTexture._source.height,r.bounds.minX,r.bounds.minY),n=t.worldTransform.copyTo(k.shared),s=t.renderGroup||t.parentRenderGroup;return s&&s.cacheToLocalTransform&&n.prepend(s.cacheToLocalTransform),n.invert(),i.prepend(n),i.scale(1/t.texture.orig.width,1/t.texture.orig.height),i.translate(t.anchor.x,t.anchor.y),i}destroy(){var e;(e=this._passthroughFilter)==null||e.destroy(!0),this._passthroughFilter=null}_getPassthroughFilter(){return this._passthroughFilter??(this._passthroughFilter=new $),this._passthroughFilter}_setupBindGroupsAndRender(e,t,r){if(r.renderPipes.uniformBatch){const i=r.renderPipes.uniformBatch.getUboResource(this._filterGlobalUniforms);this._globalFilterBindGroup.setResource(i,0)}else this._globalFilterBindGroup.setResource(this._filterGlobalUniforms,0);this._globalFilterBindGroup.setResource(t.source,1),this._globalFilterBindGroup.setResource(t.source.style,2),e.groups[0]=this._globalFilterBindGroup,r.encoder.draw({geometry:H,shader:e,state:e._state,topology:"triangle-list"}),r.type===Y.WEBGL&&r.renderTarget.finishRenderPass()}_setupFilterTextures(e,t,r,i){if(e.backTexture=v.EMPTY,e.inputTexture=_.getOptimalTexture(t.width,t.height,e.resolution,e.antialias),e.blendRequired){r.renderTarget.finishRenderPass();const n=r.renderTarget.getRenderTarget(e.outputRenderSurface);e.backTexture=this.getBackTexture(n,t,i==null?void 0:i.bounds)}r.renderTarget.bind(e.inputTexture,!0),r.globalUniforms.push({offset:t})}_calculateGlobalFrame(e,t,r,i,n,s){const a=e.globalFrame;a.x=t*i,a.y=r*i,a.width=n*i,a.height=s*i}_updateFilterUniforms(e,t,r,i,n,s,a,o){const l=this._filterGlobalUniforms.uniforms,f=l.uOutputFrame,c=l.uInputSize,u=l.uInputPixel,p=l.uInputClamp,h=l.uGlobalFrame,x=l.uOutputTexture;a?(f[0]=r.bounds.minX-i,f[1]=r.bounds.minY-n):(f[0]=0,f[1]=0),f[2]=e.frame.width,f[3]=e.frame.height,c[0]=e.source.width,c[1]=e.source.height,c[2]=1/c[0],c[3]=1/c[1],u[0]=e.source.pixelWidth,u[1]=e.source.pixelHeight,u[2]=1/u[0],u[3]=1/u[1],p[0]=.5*u[2],p[1]=.5*u[3],p[2]=e.frame.width*c[2]-.5*u[2],p[3]=e.frame.height*c[3]-.5*u[3];const F=this.renderer.renderTarget.rootRenderTarget.colorTexture;h[0]=i*s,h[1]=n*s,h[2]=F.source.width*s,h[3]=F.source.height*s,t instanceof v&&(t.source.resource=null);const d=this.renderer.renderTarget.getRenderTarget(t);this.renderer.renderTarget.bind(t,!!o),t instanceof v?(x[0]=t.frame.width,x[1]=t.frame.height):(x[0]=d.width,x[1]=d.height),x[2]=d.isRoot?-1:1,this._filterGlobalUniforms.update()}_findFilterResolution(e){let t=this._filterStackIndex-1;for(;t>0&&this._filterStack[t].skip;)--t;return t>0&&this._filterStack[t].inputTexture?this._filterStack[t].inputTexture.source._resolution:e}_findPreviousFilterOffset(){let e=0,t=0,r=this._filterStackIndex;for(;r>0;){r--;const i=this._filterStack[r];if(!i.skip){e=i.bounds.minX,t=i.bounds.minY;break}}return{x:e,y:t}}_calculateFilterArea(e,t){if(e.renderables?G(e.renderables,t):e.filterEffect.filterArea?(t.clear(),t.addRect(e.filterEffect.filterArea),t.applyMatrix(e.container.worldTransform)):e.container.getFastGlobalBounds(!0,t),e.container){const i=(e.container.renderGroup||e.container.parentRenderGroup).cacheToLocalTransform;i&&t.applyMatrix(i)}}_applyFiltersToTexture(e,t){const r=e.inputTexture,i=e.bounds,n=e.filters,s=e.firstEnabledIndex,a=e.lastEnabledIndex;if(this._globalFilterBindGroup.setResource(r.source.style,2),this._globalFilterBindGroup.setResource(e.backTexture.source,3),s===a)n[s].apply(this,r,e.outputRenderSurface,t);else{let o=e.inputTexture;const l=_.getOptimalTexture(i.width,i.height,o.source._resolution,!1);let f=l;for(let c=s;c<a;c++){const u=n[c];if(!u.enabled)continue;u.apply(this,o,f,!0);const p=o;o=f,f=p}n[a].apply(this,o,e.outputRenderSurface,t),_.returnTexture(l)}}_calculateFilterBounds(e,t,r,i,n){var d;const s=this.renderer,a=e.bounds,o=e.filters;let l=1/0,f=0,c=!0,u=!1,p=!1,h=!0,x=-1,F=-1;for(let T=0;T<o.length;T++){const g=o[T];if(!g.enabled)continue;if(x===-1&&(x=T),F=T,l=Math.min(l,g.resolution==="inherit"?i:g.resolution),f+=g.padding,g.antialias==="off"?c=!1:g.antialias==="inherit"&&c&&(c=r),g.clipToViewport||(h=!1),!!!(g.compatibleRenderers&s.type)){p=!1;break}if(g.blendRequired&&!(((d=s.backBuffer)==null?void 0:d.useBackBuffer)??!0)){q("Blend filter requires backBuffer on WebGL renderer to be enabled. Set `useBackBuffer: true` in the renderer options."),p=!1;break}p=!0,u||(u=g.blendRequired)}if(!p){e.skip=!0;return}if(h&&a.fitBounds(0,t.width/i,0,t.height/i),a.scale(l).ceil().scale(1/l).pad((f|0)*n),!a.isPositive){e.skip=!0;return}e.antialias=c,e.resolution=l,e.blendRequired=u,e.firstEnabledIndex=x,e.lastEnabledIndex=F}_popFilterData(){return this._filterStackIndex--,this._filterStack[this._filterStackIndex]}_getPreviousFilterData(){let e,t=this._filterStackIndex-1;for(;t>0&&(t--,e=this._filterStack[t],!!e.skip););return e}_pushFilterData(){let e=this._filterStack[this._filterStackIndex];return e||(e=this._filterStack[this._filterStackIndex]=new Q),this._filterStackIndex++,e}}B.extension={type:[b.WebGLSystem,b.WebGPUSystem],name:"filter"};R.add(B,C);R.add(I);
|
package/dist/backend.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { createReadStream, existsSync, statSync } from 'node:fs'
|
|
4
|
+
import { hooks } from 'xxscreeps/backend/index.js'
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
const distDir = __dirname
|
|
8
|
+
const indexFile = path.join(distDir, 'index.html')
|
|
9
|
+
|
|
10
|
+
const CONTENT_TYPES = {
|
|
11
|
+
'.css': 'text/css',
|
|
12
|
+
'.html': 'text/html',
|
|
13
|
+
'.js': 'text/javascript',
|
|
14
|
+
'.json': 'application/json',
|
|
15
|
+
'.map': 'application/json',
|
|
16
|
+
'.png': 'image/png',
|
|
17
|
+
'.svg': 'image/svg+xml',
|
|
18
|
+
'.ico': 'image/x-icon',
|
|
19
|
+
'.gif': 'image/gif',
|
|
20
|
+
'.jpg': 'image/jpeg',
|
|
21
|
+
'.jpeg': 'image/jpeg',
|
|
22
|
+
'.webp': 'image/webp',
|
|
23
|
+
'.ttf': 'font/ttf',
|
|
24
|
+
'.woff': 'font/woff',
|
|
25
|
+
'.woff2': 'font/woff2',
|
|
26
|
+
'.txt': 'text/plain',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function readBool(envName, fallback) {
|
|
30
|
+
const env = process.env[envName]
|
|
31
|
+
if (env === undefined) return fallback
|
|
32
|
+
const v = env.toLowerCase()
|
|
33
|
+
return v === '1' || v === 'true' || v === 'yes'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function normalizeMount(input) {
|
|
37
|
+
let p = input ?? '/'
|
|
38
|
+
if (!p.startsWith('/')) p = '/' + p
|
|
39
|
+
p = p.replace(/\/+$/, '')
|
|
40
|
+
return p === '' ? '/' : p
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const mountPath = normalizeMount(process.env.SCREEPS_MOD_CLIENT_MOUNT_PATH ?? '/')
|
|
44
|
+
const rootRedirect = readBool('SCREEPS_MOD_CLIENT_ROOT_REDIRECT', mountPath !== '/')
|
|
45
|
+
|
|
46
|
+
function resolveFile(relPath) {
|
|
47
|
+
const rel = relPath.replace(/^\/+/, '')
|
|
48
|
+
const target = rel === '' ? indexFile : path.join(distDir, rel)
|
|
49
|
+
const normalized = path.normalize(target)
|
|
50
|
+
if (!normalized.startsWith(distDir)) return null
|
|
51
|
+
if (!existsSync(normalized)) return null
|
|
52
|
+
const stat = statSync(normalized)
|
|
53
|
+
if (!stat.isFile()) return null
|
|
54
|
+
return { filePath: normalized, stat }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function sendFile(ctx, filePath, stat) {
|
|
58
|
+
const ext = path.extname(filePath).toLowerCase()
|
|
59
|
+
ctx.type = CONTENT_TYPES[ext] ?? 'application/octet-stream'
|
|
60
|
+
ctx.lastModified = stat.mtime
|
|
61
|
+
ctx.set('Content-Length', String(stat.size))
|
|
62
|
+
ctx.body = createReadStream(filePath)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
hooks.register('middleware', koa => {
|
|
66
|
+
if (!existsSync(indexFile)) {
|
|
67
|
+
console.error(`[xxscreeps-mod-client] dist/index.html not found at ${indexFile}. Run "pnpm --filter xxscreeps-mod-client build" first.`)
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(`[xxscreeps-mod-client] serving client at ${mountPath === '/' ? '/' : mountPath + '/'} (rootRedirect=${rootRedirect})`)
|
|
72
|
+
|
|
73
|
+
koa.use(async (ctx, next) => {
|
|
74
|
+
if (ctx.method !== 'GET' && ctx.method !== 'HEAD') return next()
|
|
75
|
+
|
|
76
|
+
if (mountPath !== '/' && ctx.path === '/' && rootRedirect) {
|
|
77
|
+
ctx.redirect(mountPath + '/')
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let relPath
|
|
82
|
+
if (mountPath === '/') {
|
|
83
|
+
relPath = ctx.path
|
|
84
|
+
} else if (ctx.path === mountPath || ctx.path === mountPath + '/') {
|
|
85
|
+
relPath = '/'
|
|
86
|
+
} else if (ctx.path.startsWith(mountPath + '/')) {
|
|
87
|
+
relPath = ctx.path.slice(mountPath.length)
|
|
88
|
+
} else {
|
|
89
|
+
return next()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Serve a real file from dist if it exists.
|
|
93
|
+
const found = resolveFile(relPath)
|
|
94
|
+
if (found) {
|
|
95
|
+
sendFile(ctx, found.filePath, found.stat)
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Otherwise let xxscreeps handle the request. If it 404s and the path
|
|
100
|
+
// looks like an SPA route (no file extension on the last segment),
|
|
101
|
+
// fall back to index.html so client-side routing can take over.
|
|
102
|
+
await next()
|
|
103
|
+
if (ctx.status !== 404) return
|
|
104
|
+
const last = relPath.split('/').pop() ?? ''
|
|
105
|
+
if (last.includes('.')) return
|
|
106
|
+
const indexStat = statSync(indexFile)
|
|
107
|
+
ctx.status = 200
|
|
108
|
+
sendFile(ctx, indexFile, indexStat)
|
|
109
|
+
})
|
|
110
|
+
})
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Screeps Client</title>
|
|
7
|
+
<style>
|
|
8
|
+
*, *::before, *::after {
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
}
|
|
11
|
+
html, body, #root {
|
|
12
|
+
margin: 0;
|
|
13
|
+
padding: 0;
|
|
14
|
+
width: 100%;
|
|
15
|
+
height: 100%;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
background: #0d1117;
|
|
18
|
+
color: #c9d1d9;
|
|
19
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
20
|
+
}
|
|
21
|
+
</style>
|
|
22
|
+
<script type="module" crossorigin src="/assets/index-Cf0rVPz-.js"></script>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
<div id="root"></div>
|
|
26
|
+
</body>
|
|
27
|
+
</html>
|
package/dist/index.js
ADDED
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "xxscreeps-mod-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "xxscreeps mod that serves the screeps-client and connects it to the same server.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"xxscreeps": true,
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.js",
|
|
9
|
+
"./*": "./*"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"index.js",
|
|
13
|
+
"backend.js",
|
|
14
|
+
"dist/"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/bastianh/screeps-client.git"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"registry": "https://registry.npmjs.org"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=20"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"xxscreeps": "*"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "node ./scripts/build-client.js && node ./scripts/copy-dist.js",
|
|
31
|
+
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\""
|
|
32
|
+
}
|
|
33
|
+
}
|