@utsp/runtime-client 0.16.1 → 0.17.0-nightly.20260120215017.712755a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.mjs +1 -1
- package/package.json +7 -7
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var D=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var ve=Object.prototype.hasOwnProperty;var Ce=(R,e,t)=>e in R?D(R,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):R[e]=t;var S=(R,e)=>D(R,"name",{value:e,configurable:!0});var Se=(R,e)=>{for(var t in e)D(R,t,{get:e[t],enumerable:!0})},Re=(R,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of be(e))!ve.call(R,r)&&r!==t&&D(R,r,{get:()=>e[r],enumerable:!(i=ye(e,r))||i.enumerable});return R};var Ie=R=>Re(D({},"__esModule",{value:!0}),R);var d=(R,e,t)=>(Ce(R,typeof e!="symbol"?e+"":e,t),t);var Me={};Se(Me,{AudioFeature:()=>Q,AudioManager:()=>fe.AudioManager,BaseClientRuntime:()=>O,ClientRuntime:()=>z,DEFAULT_ATLAS_CONFIG:()=>A,InputFeature:()=>q,NetworkTransportType:()=>me.NetworkTransportType,PostProcessFeature:()=>K,RendererManager:()=>E,RendererType:()=>Y,ScalingMode:()=>ge.ScalingMode,decodeDefaultAtlas:()=>$});module.exports=Ie(Me);var de=require("@utsp/core"),V=require("@utsp/render");var Y=(t=>(t.TerminalGL="webgl",t.Terminal2D="terminal2d",t))(Y||{});var j=class j{constructor(e=60){d(this,"frameCount",0);d(this,"fps",0);d(this,"fpsUpdateTime",0);d(this,"lastCoreTime",0);d(this,"lastRenderTime",0);d(this,"lastTotalTime",0);d(this,"coreTimeSamples",[]);d(this,"renderTimeSamples",[]);d(this,"totalTimeSamples",[]);d(this,"maxSamples");if(e<=0)throw new Error("maxSamples must be positive");this.maxSamples=e}startTracking(e){this.fpsUpdateTime=e,this.frameCount=0,this.fps=0}updateFPS(e){this.frameCount++,e-this.fpsUpdateTime>=1e3&&(this.fps=Math.round(this.frameCount*1e3/(e-this.fpsUpdateTime)),this.frameCount=0,this.fpsUpdateTime=e)}recordFrameTiming(e,t){let i=e+t;this.lastCoreTime=e,this.lastRenderTime=t,this.lastTotalTime=i,this.coreTimeSamples.push(e),this.renderTimeSamples.push(t),this.totalTimeSamples.push(i),this.coreTimeSamples.length>this.maxSamples&&(this.coreTimeSamples.shift(),this.renderTimeSamples.shift(),this.totalTimeSamples.shift())}getFPS(){return this.fps}getLastFrameTiming(){if(!(this.lastCoreTime===0&&this.lastRenderTime===0))return{coreTime:this.lastCoreTime,renderTime:this.lastRenderTime,totalTime:this.lastTotalTime}}getAverageFrameTiming(){if(this.coreTimeSamples.length!==0)return{coreTime:this.average(this.coreTimeSamples),renderTime:this.average(this.renderTimeSamples),totalTime:this.average(this.totalTimeSamples)}}getStats(){return{fps:this.fps,lastFrame:this.getLastFrameTiming(),avgFrame:this.getAverageFrameTiming(),sampleCount:this.coreTimeSamples.length,maxSamples:this.maxSamples}}reset(){this.frameCount=0,this.fps=0,this.fpsUpdateTime=0,this.lastCoreTime=0,this.lastRenderTime=0,this.lastTotalTime=0,this.coreTimeSamples=[],this.renderTimeSamples=[],this.totalTimeSamples=[]}average(e){return e.length===0?0:e.reduce((t,i)=>t+i,0)/e.length}};S(j,"PerformanceMonitor");var L=j;var we="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",A={glyphWidth:8,glyphHeight:8,cellWidth:8,cellHeight:8,atlasBlocks:1,atlasWidth:128,atlasHeight:128};function $(){let R=atob(we),e=new Uint8Array(R.length);for(let t=0;t<R.length;t++)e[t]=R.charCodeAt(t);return e}S($,"decodeDefaultAtlas");var N=class N{constructor(e,t={}){d(this,"renderer");d(this,"options");d(this,"layerFilter",null);this.renderer=e,this.options={debug:t.debug??!1,useImageDataRendering:t.useImageDataRendering??!1}}setLayerFilter(e){this.layerFilter=e}getLayerFilter(){return this.layerFilter}async initialize(e){if("setImageDataRendering"in this.renderer&&this.options.useImageDataRendering&&(this.renderer.setImageDataRendering(!0),this.log("ImageData rendering enabled")),"setImageFont"in this.renderer&&typeof this.renderer.setImageFont=="function"){this.log("Loading default 8x8 font atlas...");let t=$();await this.renderer.setImageFont(t,A.glyphWidth,A.glyphHeight,A.cellWidth,A.cellHeight,A.atlasBlocks),this.log("Default 8x8 font atlas loaded")}await this.waitForReady(),this.log("Initialized and ready")}async waitForReady(e=100,t=50){this.log("Waiting for renderer to be ready");let i=0;return new Promise((r,s)=>{let n=S(()=>{if(i++,this.renderer.isReady())this.log(`Renderer ready after ${i*t}ms`),r();else if(i>=e){let a=`Renderer failed to be ready after ${e*t}ms`;this.log(a),s(new Error(a))}else setTimeout(n,t)},"check");n()})}async loadDefaultFont(e){console.warn("[RendererManager] loadDefaultFont() is deprecated. Use ImageFont instead.")}renderDisplay(e){return this.renderer.isReady()?e?(this.renderer.renderDisplayData(e),!0):(console.warn("[RENDERER MANAGER] No display provided"),!1):(console.warn("[RENDERER MANAGER] Renderer not ready"),!1)}render(e,t){let i=this.layerFilter?e.getRenderState(t,this.layerFilter):e.getRenderState(t);return!i||i.displays.length===0?(console.warn("[RENDERER MANAGER] No render state or no displays"),!1):this.renderDisplay(i.displays[0])}getRenderer(){return this.renderer}getCanvas(){return this.renderer.getCanvas()}getAvailableSize(){if(this.renderer.getAvailableSize)return this.renderer.getAvailableSize();let e=this.getCanvas();return{width:e?.clientWidth||e?.width||0,height:e?.clientHeight||e?.height||0}}isReady(){return this.renderer.isReady()}destroy(){this.log("Destroying renderer"),this.renderer.destroy()}log(e){this.options.debug&&console.warn(`[RendererManager] ${e}`)}};S(N,"RendererManager");var E=N;var J=class J{constructor(e){d(this,"core");d(this,"rendererManagers",new Map);d(this,"rendererInitPromises",new Map);d(this,"rendererManager");d(this,"rendererType");d(this,"primaryDisplayId",0);d(this,"displayConfigs");d(this,"options");d(this,"running",!1);d(this,"startTime",0);d(this,"lastTimestamp",0);d(this,"userId","");d(this,"visibilityChangeHandler");d(this,"tickRate",30);d(this,"accumulatedTime",0);d(this,"FRAME_TIME_MIN",1e3/60);d(this,"lastRenderTimestamp",0);d(this,"rafId",0);d(this,"firstTickDone",!1);d(this,"performanceMonitor");d(this,"renderMode","continuous");d(this,"renderRequested",!1);if(this.options={application:e.application,container:e.container,displayContainers:e.displayContainers,debug:e.debug??!1,width:e.width??80,height:e.height??25,renderer:e.renderer??"webgl",useImageDataRendering:e.useImageDataRendering??!0,renderMode:e.renderMode??"continuous"},this.log("Initializing BaseClientRuntime"),this.core=new de.Core({mode:"client",maxUsers:1}),this.core.onPaletteChanged(t=>{this.onCorePaletteChanged(t)}),this.core.onBitmapFontChanged(t=>{this.onCoreBitmapFontChanged(t)}),this.core.onImageFontChanged(t=>{this.onCoreImageFontChanged(t)}),this.visibilityChangeHandler=()=>{!document.hidden&&this.running&&(this.lastTimestamp=performance.now(),this.accumulatedTime=0,this.log("Tab visible: Reset timing"))},document.addEventListener("visibilitychange",this.visibilityChangeHandler),this.rendererType=this.options.renderer,this.options.displayContainers&&this.options.displayContainers.length>0){this.displayConfigs=new Map([[0,{container:this.options.container,renderer:this.options.renderer}]]);for(let t of this.options.displayContainers){let i=t.renderer;this.displayConfigs.set(t.id,{container:t.container,renderer:i})}this.primaryDisplayId=0}else this.displayConfigs=new Map([[0,{container:this.options.container,renderer:this.options.renderer}]]),this.primaryDisplayId=0;this.createRendererManagers(),this.performanceMonitor=new L(60),this.tickRate=20,this.renderMode=e.renderMode??"continuous",this.log(`Configured: tickRate=${this.tickRate}, renderMode=${this.renderMode}`),this.log("BaseClientRuntime initialized")}createRenderer(e,t){if(t==="terminal2d"){this.log("Creating Terminal 2D renderer");let n=new V.Terminal2D(e,{fixedCols:this.options.width,fixedRows:this.options.height,cellAspectRatio:1});return this.options.useImageDataRendering&&(this.log("Enabling ImageData rendering (pixel-perfect, optimized)"),n.setImageDataRendering(!0)),this.log("Canvas 2D renderer created successfully"),n}this.log("Creating TerminalGL renderer");let r=document.createElement("canvas").getContext("webgl");if(!r)throw new Error("WebGL not supported. TerminalGL requires WebGL 1.0.");if(!r.getExtension("OES_element_index_uint"))throw new Error("OES_element_index_uint extension not supported. TerminalGL requires this extension for large terminals (256x256).");if(!(e instanceof HTMLDivElement))throw new Error(`TerminalGL requires container to be an HTMLDivElement. Received: ${e.tagName}`);let s=new V.TerminalGL(e,{cols:this.options.width,rows:this.options.height,charWidth:8,charHeight:8});return this.log("TerminalGL created successfully"),s}createRendererManagers(){let e=this.displayConfigs.size>=3;this.rendererManagers.clear();for(let[i,r]of this.displayConfigs.entries()){let s=e?"terminal2d":r.renderer??this.options.renderer,n=this.createRenderer(r.container,s??"webgl"),o=new E(n,{debug:this.options.debug,useImageDataRendering:this.options.useImageDataRendering});this.rendererManagers.set(i,o)}let t=this.rendererManagers.get(this.primaryDisplayId);if(!t)throw new Error(`Primary display ${this.primaryDisplayId} has no renderer. Check displayContainers configuration.`);this.rendererManager=t}ensureRendererManager(e){let t=this.rendererManagers.get(e);if(t)return t;let i=document.createElement("div");i.dataset.displayId=String(e),i.style.cssText="position:relative;display:inline-block;margin:4px;background:#000;overflow:hidden;",(this.options.container?.parentElement??document.body).appendChild(i),this.displayConfigs.set(e,{container:i});let o=this.displayConfigs.size>=3?"terminal2d":this.options.renderer??"webgl",a=this.createRenderer(i,o),l=new E(a,{debug:this.options.debug,useImageDataRendering:this.options.useImageDataRendering});if(this.rendererManagers.set(e,l),!this.rendererInitPromises.has(e)){let c=l.initialize(this.core).then(()=>{this.onCorePaletteChanged(this.core.getPalette());let h=this.core.getImageFontIds,u=typeof h=="function"?h.call(this.core):[];u.length>0&&this.onCoreImageFontChanged(u[0]);let m=this.rebuildPostProcessOverlays;typeof m=="function"&&m.call(this)}).catch(h=>{console.warn(`[BaseClientRuntime] Failed to init renderer for display ${e}:`,h)});this.rendererInitPromises.set(e,c)}return l}getRendererType(){return this.rendererType}isRunning(){return this.running}setTickRate(e){if(e<0||e>1e3)throw new Error(`Invalid tick rate: ${e}. Must be between 0 and 1000.`);if(this.tickRate=e,this.userId){let t=this.core.getUser(this.userId);t&&t.setBytesTickRate(e>0?e:20)}e===0&&this.renderMode==="continuous"?(this.renderMode="on-demand",this.log("Tick rate set to 0, switched to on-demand render mode")):this.log(`Tick rate set to ${e} TPS`)}setRenderMode(e){this.renderMode=e,this.log(`Render mode set to ${e}`)}setMaxFPS(e){if(e<=0||e>240)throw new Error(`Invalid FPS: ${e}. Must be between 1 and 240.`);this.FRAME_TIME_MIN=1e3/e,this.log(`Max FPS set to ${e}`)}getTickRate(){return this.tickRate}requestRender(){this.renderMode==="on-demand"&&(this.renderRequested=!0,this.log("Render requested"))}async start(){if(this.running){this.log("Already running");return}this.log("Starting BaseClientRuntime"),await this.onBeforeStart();for(let[e,t]of this.rendererManagers.entries())await t.initialize(this.core),this.log(`Renderer for display ${e} is ready`);this.onCorePaletteChanged(this.core.getPalette()),this.log("Initial palette sent to renderers"),this.options.application&&(this.log("Calling application.init()"),await this.options.application.init(this.core,this)),await this.onAfterInit(),await this.createLocalUser(),this.running=!0,this.startTime=performance.now(),this.lastTimestamp=this.startTime,this.lastRenderTimestamp=this.startTime,this.accumulatedTime=0,this.firstTickDone=!1,this.performanceMonitor.reset(),this.performanceMonitor.startTracking(this.startTime),this.log("Starting main loop"),this.mainLoop(this.lastTimestamp)}async onBeforeStart(){}async onAfterInit(){}async stop(){if(!this.running)return;this.log("Stopping BaseClientRuntime"),this.running=!1,this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0),await this.onStop();let e=this.core.getUser(this.userId);e&&this.options.application?.destroyUser&&this.options.application.destroyUser(this.core,e,"Runtime stopped"),this.log("BaseClientRuntime stopped")}async onStop(){}getStats(){let e=this.performanceMonitor.getStats();return{running:this.running,userCount:this.core.getUsers().length,fps:e.fps,uptime:this.running?performance.now()-this.startTime:0,totalFrames:0,lastFrameTiming:e.lastFrame,avgFrameTiming:e.avgFrame}}getTotalBytesReceived(){return this.core.getUser(this.userId)?.getTotalBytesReceived()??0}getBytesReceivedPerSecond(){return this.core.getUser(this.userId)?.getBytesReceivedPerSecond()??0}resetBytesReceived(){let e=this.core.getUser(this.userId);e&&e.resetByteCounters()}async destroy(){await this.stop(),this.log("Destroying BaseClientRuntime"),this.visibilityChangeHandler&&(document.removeEventListener("visibilitychange",this.visibilityChangeHandler),this.visibilityChangeHandler=void 0),await this.onDestroy();for(let e of this.rendererManagers.values()){let t=e.getRenderer();t&&"clearOnResizeCallback"in t&&t.clearOnResizeCallback()}this.options.application?.destroy&&this.options.application.destroy();for(let e of this.rendererManagers.values())e.destroy();this.log("BaseClientRuntime destroyed")}async onDestroy(){}async createLocalUser(){this.userId="local",this.log(`Creating local user: ${this.userId}`);let e=this.core.createUser(this.userId,"User");e.setBytesTickRate(this.tickRate>0?this.tickRate:20),this.onUserCreated(e),this.options.application?.initUser&&(this.log("Calling application.initUser()"),this.options.application.initUser(this.core,e,{username:"User"})),this.processInitialOrders(e);let t=this.core.generateAllLoadPackets();t.forEach(n=>{e.recordBytesReceived(n.length)});let i=this.core.generateMacroLoadPackets(this.userId);i.forEach(n=>{e.recordBytesReceived(n.length)});let r=e.getInputBindingsLoadPacket();r&&e.recordBytesReceived(r.length),this.log(`Simulated ${t.length} load packets, ${i.length} macro packets for byte counting`),this.log("Performing initial render"),this.core.endTick().forEach(({static:n,dynamic:o},a)=>{let l=this.core.getUser(a);l&&(n&&l.recordBytesReceived(n.length),o&&l.recordBytesReceived(o.length))})}processInitialOrders(e){if(e.hasPendingMacroOrders()){this.log("Applying macro orders from initUser()");let t=e.flushMacroOrders();e.applyMacroOrders(t)}}onUserCreated(e){}mainLoop(e){if(!this.running){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0);return}if(this.renderMode==="on-demand"){this.renderRequested&&(this.renderRequested=!1,this.performanceMonitor.updateFPS(e),this.render()),this.rafId=requestAnimationFrame(l=>this.mainLoop(l));return}let t=e-this.lastRenderTimestamp;if(this.lastRenderTimestamp>0&&t<this.FRAME_TIME_MIN-1){this.rafId=requestAnimationFrame(l=>this.mainLoop(l));return}this.lastRenderTimestamp=e;let i=(e-this.lastTimestamp)/1e3,r=Math.min(i,.1);this.lastTimestamp=e,this.performanceMonitor.updateFPS(e);let s=this.core.getUser(this.userId);if(!s){this.rafId=requestAnimationFrame(l=>this.mainLoop(l));return}if(this.tickRate===0){let l=performance.now();this.render();let c=performance.now()-l;this.performanceMonitor.recordFrameTiming(0,c),this.rafId=requestAnimationFrame(h=>this.mainLoop(h));return}if(!this.firstTickDone){this.firstTickDone=!0,this.lastTimestamp=e,this.accumulatedTime=0,this.rafId=requestAnimationFrame(l=>this.mainLoop(l));return}this.accumulatedTime+=r;let n=1/this.tickRate;this.accumulatedTime>.5&&(this.accumulatedTime=n);let o=0,a=0;for(;this.accumulatedTime>=n&&o<5;){let l=performance.now();this.collectAndApplyInput(s),this.options.application&&(this.options.application.update?.(this.core,n),this.options.application.updateUser?.(this.core,s,n)),this.processTickOrders(s);let c=s.updateMacros();s.processMacroEvents(c),this.core.endTick().forEach(({static:u,dynamic:m})=>{let v=(u?.length??0)+(m?.length??0);s.recordBytesReceived(v)}),a+=performance.now()-l,this.accumulatedTime-=n,o++}if(o>0){let l=performance.now();this.render();let c=performance.now()-l;this.performanceMonitor.recordFrameTiming(a,c)}this.rafId=requestAnimationFrame(l=>this.mainLoop(l))}collectAndApplyInput(e){}processTickOrders(e){if(e.clearTextInputs(),e.hasPendingMacroOrders()){let t=e.flushMacroOrders();e.applyMacroOrders(t)}}render(){let e=this.core.getUser(this.userId);if(e){let i=e.getMacroRenderOrders();for(let[r,s]of i){let n=e.getLayerById(r);n&&s.length>0&&n.addTemporaryOrders(s)}}let t=this.core.getRenderState(this.userId);if(!t||t.displays.length===0){console.warn("[BaseClientRuntime] No render state or displays");return}for(let i of t.displays){let r=this.rendererManagers.get(i.id)??this.ensureRendererManager(i.id);if(!r){console.warn(`[BaseClientRuntime] No renderer manager for display ${i.id}, skipping render`);continue}let s=r.getLayerFilter(),n=s?this.core.getRenderState(this.userId,s):t;if(!n){this.options.debug&&this.log(`Render state unavailable for display ${i.id} with filter`);continue}let o=n.displays.find(a=>a.id===i.id);if(!o){this.options.debug&&this.log(`Render state missing display ${i.id} after filtering`);continue}if(!r.isReady()){this.options.debug&&this.log(`Renderer for display ${i.id} not ready yet`);continue}r.renderDisplay(o)}}onCorePaletteChanged(e){this.log(`Palette changed, updating renderer (${e.size} colors)`);let t=[];for(let s=0;s<256;s++){let n=e.get(s);n?t.push({r:n.r,g:n.g,b:n.b,a:n.a}):t.push({r:0,g:0,b:0,a:0})}let i=S(s=>{s&&"setPalette"in s&&typeof s.setPalette=="function"&&s.setPalette(t)},"applyPalette"),r=0;for(let s of this.rendererManagers.values()){let n=s.getRenderer();n&&(i(n),r++)}r===0?console.warn("[BaseClientRuntime] Cannot update palette: no renderer available"):this.log(`\u2713 Palette updated on ${r} renderer(s)`)}onCoreBitmapFontChanged(e){this.log(`Bitmap font ${e} changed, updating renderer`);let t=this.core.getBitmapFont(e);if(!t){console.warn(`[BaseClientRuntime] Font ${e} not found in registry`);return}let i=new Map,r=0;for(let o=0;o<256;o++){let a=t.getGlyph(o);a&&(i.set(o,a),r++)}this.log(`Built bitmap font map with ${r} glyphs, dimensions: ${t.getCharWidth()}x${t.getCharHeight()}`);let s=S(o=>{o&&"setBitmapFont"in o&&typeof o.setBitmapFont=="function"&&o.setBitmapFont(i,t.getCharWidth(),t.getCharHeight(),t.getCellWidth(),t.getCellHeight())},"applyBitmapFont"),n=0;for(let[o,a]of this.rendererManagers.entries()){let l=a.getRenderer();l&&(s(l),n++,this.onFontChanged(l,o))}n===0?console.warn("[BaseClientRuntime] Cannot update font: no renderer available"):this.log(`\u2713 Renderer bitmap font updated successfully on ${n} renderer(s)`)}onCoreImageFontChanged(e){this.log(`Image font ${e} changed, updating renderer`);let t=this.core.getImageFont(e);if(!t){console.warn(`[BaseClientRuntime] Image font ${e} not found in registry`);return}this.log(`Loading image font with ${t.getAtlasBlocks()} blocks, glyph: ${t.getGlyphWidth()}x${t.getGlyphHeight()}`);let i=S(s=>{s&&"setImageFont"in s&&typeof s.setImageFont=="function"&&s.setImageFont(t.getImageData(),t.getGlyphWidth(),t.getGlyphHeight(),t.getCellWidth(),t.getCellHeight(),t.getAtlasBlocks())},"applyImageFont"),r=0;for(let[s,n]of this.rendererManagers.entries()){let o=n.getRenderer();o&&(i(o),r++,this.onFontChanged(o,s))}r===0?console.warn("[BaseClientRuntime] Cannot update image font: no renderer available"):this.log(`\u2713 Renderer image font updated successfully on ${r} renderer(s)`)}onFontChanged(e,t){}log(e){this.options.debug&&console.warn(`[BaseClientRuntime] ${e}`)}getCore(){return this.core}getRendererManager(e=this.primaryDisplayId){let t=this.rendererManagers.get(e);if(!t)throw new Error(`Renderer manager for display ${e} not found`);return t}setDisplayContainers(e){this.displayConfigs=new Map(e.map(i=>[i.id,{container:i.container}]));let t=Array.from(this.displayConfigs.keys());this.primaryDisplayId=t.length>0?Math.min(...t):0;for(let i of this.rendererManagers.values())i.destroy();this.rendererManagers.clear(),this.createRendererManagers()}getUserId(){return this.userId}};S(J,"BaseClientRuntime");var O=J;var w=require("@utsp/core"),W=require("@utsp/render"),x=require("@utsp/types"),M=require("@utsp/input"),H=require("@utsp/network-client"),ce=require("@utsp/audio");var le=require("@utsp/core"),B=require("@utsp/input");var P=1e3,Z=class Z{constructor(e,t,i,r,s,n,o){d(this,"network");d(this,"core");d(this,"rendererManagers");d(this,"primaryDisplayId");d(this,"performanceMonitor");d(this,"options");d(this,"layerTraffic",new Map);d(this,"miscTraffic",new Map);d(this,"displayTraffic",new Map);d(this,"audioManager",null);d(this,"postProcessCallback",null);d(this,"soundHandlersSetup",!1);d(this,"userId","");d(this,"lastReceivedTick",-1);d(this,"connected",!1);d(this,"totalBytesReceived",0);d(this,"lastSentViewports",new Map);d(this,"lastCollectedTouches",[]);d(this,"touchZonesCallback",null);d(this,"audioLoadingState",{totalExpected:0,loadedSounds:new Set,errors:new Map});d(this,"ensureRendererManager");this.network=e,this.core=t,this.rendererManagers=i,this.primaryDisplayId=n,this.performanceMonitor=r,this.ensureRendererManager=o,this.options={serverUrl:s.serverUrl,username:s.username,token:s.token??"",debug:s.debug??!1,autoReconnect:s.autoReconnect??!0,canvasWidth:s.canvasWidth,canvasHeight:s.canvasHeight}}getRendererManager(e){return this.rendererManagers.get(e)}getPrimaryRendererManager(){return this.rendererManagers.get(this.primaryDisplayId)??Array.from(this.rendererManagers.values())[0]}renderDisplays(){let e=this.core.getRenderState(this.userId);if(!e||e.displays.length===0){this.options.debug&&this.log("Render skipped: no render state or displays");return}for(let t of e.displays){let i=this.getRendererManager(t.id)??this.ensureRendererManager?.(t.id);if(!i){console.warn(`[NetworkSync] No renderer manager for display ${t.id}, skipping render`);continue}let r=i.getLayerFilter?.(),s=r?this.core.getRenderState(this.userId,r):e;if(!s){this.options.debug&&this.log(`Render state unavailable for display ${t.id} with filter`);continue}let n=s.displays.find(o=>o.id===t.id);if(!n){this.options.debug&&this.log(`Render state missing display ${t.id} after filtering`);continue}if(!i.isReady()){this.options.debug&&this.log(`Renderer for display ${t.id} not ready yet`);continue}i.renderDisplay(n)}}async connect(){this.log(`Connecting to ${this.options.serverUrl}`),await this.network.connect(),this.connected=!0,this.log("Connected to server"),this.setupNetworkHandlers()}async joinGame(e){return new Promise((t,i)=>{this.network.send("join",{username:this.options.username,token:this.options.token}),this.network.on("join_response",r=>{if(r.success){this.userId=r.userId,this.log(`Joined game as ${this.userId}`);let s=this.core.createUser(this.userId,this.options.username);s.setBytesTickRate(20),this.audioManager&&s.setAudioProcessor(this.audioManager),e?.initUser&&e.initUser(this.core,s,{username:this.options.username,token:this.options.token}),t(this.userId)}else i(new Error(r.error||"Failed to join game"))}),setTimeout(()=>i(new Error("Join timeout")),5e3)})}sendInput(e){let t=this.core.getUser(this.userId);if(!t)return;let i=this.getPrimaryRendererManager(),r=i?.getCanvas();if(r){let g=t.getDisplays(),ie=(g.find(F=>F.getId&&F.getId()===this.primaryDisplayId)??g[0])?.getSize()??{x:this.options.canvasWidth,y:this.options.canvasHeight},re=ie.x,ne=ie.y,se=i?.getRenderer()?.getOffsets?.(),oe={offsetX:se?.offsetX??0,offsetY:se?.offsetY??0},U=B.InputCollector.collectMousePosition(e,r,re,ne,oe);t.setMousePosition(U.x,U.y,U.over),t.updateMacroMouse(U.x,U.y,U.isLeftDown);let ae=B.InputCollector.collectTouchPositions(e,r,re,ne,10,oe);ae.forEach(F=>{t.setTouchPosition(F.id,F.x,F.y,F.over)}),this.lastCollectedTouches=ae}else this.lastCollectedTouches=[];let s=t.getInputBindingRegistry(),n=s.getAllAxes(),o=s.getAllButtons(),a=B.InputCollector.collectAxisSources(n,e),l=B.InputCollector.collectButtonSources(o,e),c=B.InputCollector.collectTextInputs(e);c.length>0&&t.setTextInputs(c);let h=n.sort((g,I)=>g.bindingId-I.bindingId),u=new Map;for(let g of h){let I=s.evaluateAxis(g.bindingId,a);u.set(g.bindingId,I),t.setAxis(g.name,I)}let m=o.sort((g,I)=>g.bindingId-I.bindingId),v=new Map;for(let g of m){let I=s.evaluateButton(g.bindingId,l);v.set(g.bindingId,I),t.setButton(g.name,I)}let f=t.getMouseDisplayInfo(),C=t.getIsMouseOnADisplay(),b=this.collectChangedViewports(),p=this.lastCollectedTouches.map(g=>({id:g.id,x:g.x,y:g.y,over:g.over})),y=(0,le.encodeCompressedInput)(0n,u,v,f?.displayId??0,f?.localX??0,f?.localY??0,C,c,[],b,p);this.network.send("input",y)}collectChangedViewports(){let e=[];for(let[t,i]of this.rendererManagers.entries()){let{width:r,height:s}=i.getAvailableSize();if(r===0||s===0)continue;let n=this.lastSentViewports.get(t);(!n||n.pixelWidth!==r||n.pixelHeight!==s)&&(e.push({displayId:t,pixelWidth:r,pixelHeight:s}),this.lastSentViewports.set(t,{pixelWidth:r,pixelHeight:s}),this.log(`Viewport changed: display ${t} = ${r}x${s}px`))}return e}disconnect(){this.connected&&(this.network.send("leave",{}),this.network.disconnect(),this.connected=!1,this.soundHandlersSetup=!1,this.log("Disconnected from server"))}getUserId(){return this.userId}isConnected(){return this.connected}getTotalBytesReceived(){return this.totalBytesReceived}getAudioLoadingState(){let e=this.audioLoadingState.loadedSounds.size,t=this.audioLoadingState.totalExpected,i=this.audioLoadingState.errors.size,r=t>0&&e>=t,s=Array.from(this.audioLoadingState.errors.keys());return{loadedCount:e,totalExpected:t,errorCount:i,isComplete:r,errors:s}}destroy(){this.disconnect(),this.network.destroy(),this.log("NetworkSync destroyed")}setupNetworkHandlers(){this.network.on("update",e=>{try{let t=this.convertToUint8Array(e,"update");if(!t)return;this.recordBytesReceived(t.length);let i=this.core.applyUpdatePacketBuffer(this.userId,t);i?(this.postProcessCallback&&i.postProcessOrders&&i.postProcessOrders.length>0&&this.postProcessCallback(i.postProcessOrders),this.renderDisplays()):this.log("Failed to apply update packet")}catch(t){this.log(`Error applying update packet: ${t}`)}}),this.network.on("update-static",e=>{this.handleUpdatePacket(e,"update-static")}),this.network.on("update-dynamic",e=>{this.handleUpdatePacket(e,"update-dynamic")}),this.network.on("load",e=>{try{let t=this.convertToUint8Array(e,"load");if(!t)return;this.recordBytesReceived(t.length),this.core.applyLoadPacket(t)?this.log("Load packet applied successfully"):this.log("Failed to apply load packet")}catch(t){this.log(`Error applying load packet: ${t}`)}}),this.network.on("input-bindings",e=>{if(this.recordBytesReceived(e.length),this.core.applyInputBindingsLoadPacket(this.userId,e)){this.log("Input bindings configured");try{let i=JSON.parse(e);if(this.log(`Touch zones in packet: ${i.touchZones?.length??0}, callback defined: ${!!this.touchZonesCallback}`),i.touchZones&&i.touchZones.length>0&&this.touchZonesCallback){let r=i.touchZones.map(s=>({id:s.zoneId,x:s.x,y:s.y,width:s.width,height:s.height}));this.touchZonesCallback(r),this.log(`Touch zones configured: ${r.length} zones`)}}catch{}}else this.log("Failed to apply input bindings")}),this.audioManager&&this.setupSoundHandlers(),this.network.on("disconnect",()=>{this.connected=!1,this.soundHandlersSetup=!1,this.log("Disconnected from server")})}handleUpdatePacket(e,t){try{let i=this.convertToUint8Array(e,t);if(!i)return;this.recordBytesReceived(i.length);let r=new DataView(i.buffer,i.byteOffset,i.byteLength),s=Number(r.getBigUint64(0,!1));if(t==="update-dynamic"&&s<this.lastReceivedTick)return;s>this.lastReceivedTick&&(this.lastReceivedTick=s);let n=this.core.applyUpdatePacketBuffer(this.userId,i);if(n){let o=performance.now(),a=S((b,p)=>{if(p<=0)return;let y=this.miscTraffic.get(b)??{total:0,windowSum:0,samples:[]};y.total+=p,y.windowSum+=p,y.samples.push({time:o,bytes:p}),this.miscTraffic.set(b,y)},"recordMisc"),l=S(b=>{try{return JSON.stringify(b).length}catch{return 0}},"safeLen"),c=n.__byteSizes,h=c?.audioOrders;typeof h=="number"?a("update.audioOrders",h):n.audioOrders&&n.audioOrders.length&&a("update.audioOrders",l(n.audioOrders));let u=c?.vibrationOrders;typeof u=="number"?a("update.vibrationOrders",u):n.vibrationOrders&&n.vibrationOrders.length&&a("update.vibrationOrders",l(n.vibrationOrders));let m=c?.macroOrders;typeof m=="number"?a("update.macroOrders",m):n.macroOrders&&n.macroOrders.length&&a("update.macroOrders",l(n.macroOrders));let v=c?.postProcessOrders;if(typeof v=="number"?a("update.postProcessOrders",v):n.postProcessOrders&&n.postProcessOrders.length&&a("update.postProcessOrders",l(n.postProcessOrders)),n.displays&&n.displays.length)for(let b of n.displays){let p=b.id;if(typeof p!="number")continue;let y=this.displayTraffic.get(p)??{total:0,windowSum:0,samples:[]},g=7;y.total+=g,y.windowSum+=g,y.samples.push({time:o,bytes:g}),this.displayTraffic.set(p,y)}for(let b of n.layers){let p=b.byteSize??0,y=this.layerTraffic.get(b.id)??{total:0,windowSum:0,samples:[]};y.total+=p,y.windowSum+=p,y.samples.push({time:o,bytes:p});let g=o-P;for(;y.samples.length&&y.samples[0].time<g;){let I=y.samples.shift();I&&(y.windowSum-=I.bytes)}this.layerTraffic.set(b.id,y)}{let b=o-P;this.miscTraffic.forEach((p,y)=>{for(;p.samples.length&&p.samples[0].time<b;){let g=p.samples.shift();g&&(p.windowSum-=g.bytes)}p.windowSum<0&&(p.windowSum=0),this.miscTraffic.set(y,p)})}{let b=o-P;this.displayTraffic.forEach((p,y)=>{for(;p.samples.length&&p.samples[0].time<b;){let g=p.samples.shift();g&&(p.windowSum-=g.bytes)}p.windowSum<0&&(p.windowSum=0),this.displayTraffic.set(y,p)})}this.postProcessCallback&&n.postProcessOrders&&n.postProcessOrders.length>0&&this.postProcessCallback(n.postProcessOrders),this.options.debug&&this.debugRenderState();let f=performance.now();this.renderDisplays();let C=performance.now()-f;this.performanceMonitor.recordFrameTiming(0,C),this.options.debug&&console.warn(`[CLIENT] render() completed for ${t} (${C.toFixed(2)}ms)`)}else this.options.debug&&this.log(`Failed to apply ${t} packet (tick ${s})`)}catch(i){this.log(`Error applying ${t} update packet: ${i}`),console.error(i)}}convertToUint8Array(e,t){return e instanceof Uint8Array?e:e instanceof ArrayBuffer?new Uint8Array(e):Array.isArray(e)?new Uint8Array(e):e.data&&Array.isArray(e.data)?new Uint8Array(e.data):typeof e=="object"&&e.type==="Buffer"?new Uint8Array(e.data):(this.log(`Unknown data type for ${t} packet: ${typeof e}`),null)}debugRenderState(){let e=this.core.getUser(this.userId);if(e){let r=e.getLayers();console.warn(`[CLIENT] User has ${r.length} layers`),r.forEach((s,n)=>{let o=s.getOrders(),a=s.getStatic();(o.length>0||a)&&console.warn(` Layer ${n}: ${o.length} orders, static=${a}, z=${s.getZOrder()}`)})}let i=this.getPrimaryRendererManager()?.isReady()??!1;console.warn(`[CLIENT] Renderer ready: ${i}`)}log(e){this.options.debug&&console.warn(`[NetworkSync] ${e}`)}recordBytesReceived(e){this.totalBytesReceived+=e;let t=this.core.getUser(this.userId);t&&t.recordBytesReceived(e)}getLayerTrafficStats(){let e={},i=performance.now()-P;return this.layerTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),e[s]={total:r.total,bytesPerSec1s:r.windowSum/(P/1e3)}}),e}getMiscTrafficStats(){let e={},i=performance.now()-P;return this.miscTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),e[s]={total:r.total,bytesPerSec1s:r.windowSum/(P/1e3)}}),e}getDisplayTrafficStats(){let e={},i=performance.now()-P;return this.displayTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),e[s]={total:r.total,bytesPerSec1s:r.windowSum/(P/1e3)}}),e}getSoundPacketSize(e){return e.mode==="file"?e.sounds.reduce((i,r)=>i+this.getSoundDataLength(r.data)+r.name.length+10,0):e.sounds.reduce((i,r)=>i+r.url.length+r.name.length+10,0)}getSoundDataLength(e){if(e instanceof Uint8Array)return e.length;if(e instanceof ArrayBuffer||ArrayBuffer.isView(e))return e.byteLength;let t=globalThis.Buffer;return t&&e instanceof t?e.length:e&&typeof e=="object"&&Array.isArray(e.data)?e.data.length:Array.isArray(e)?e.length:0}setAudioManager(e){if(this.audioManager=e,e&&this.userId){let t=this.core.getUser(this.userId);t&&t.setAudioProcessor(e)}this.connected&&e&&this.setupSoundHandlers()}setPostProcessCallback(e){this.postProcessCallback=e}setTouchZonesCallback(e){this.touchZonesCallback=e}setupSoundHandlers(){if(this.audioManager){if(this.soundHandlersSetup){this.log("Sound handlers already registered, skipping");return}this.soundHandlersSetup=!0,this.network.on("sound-load",async e=>{this.recordBytesReceived(this.getSoundPacketSize(e)),e.totalSounds!==void 0&&e.totalSounds>this.audioLoadingState.totalExpected&&(this.audioLoadingState.totalExpected=e.totalSounds,this.log(`Audio loading: expecting ${e.totalSounds} total sounds`)),e.mode==="file"?await this.handleSoundLoad(e):e.mode==="external"&&await this.handleSoundExternalLoad(e)}),this.log("Sound handlers registered")}}async handleSoundLoad(e){if(!this.audioManager){this.log("Cannot load sounds: AudioManager not initialized");return}let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load sounds: SoundBank not initialized");return}for(let i of e.sounds)try{let r=this.normalizeSoundData(i.data);await t.loadFromData(i.soundId,i.name,r),this.log(`Loaded sound: ${i.name} (${r.length} bytes)`),this.audioLoadingState.loadedSounds.add(i.name),this.audioLoadingState.errors.delete(i.name),this.sendAudioAck({type:"sound-loaded",soundId:i.soundId,name:i.name})}catch(r){console.error(`[NetworkSync] Failed to load sound "${i.name}":`,r),this.audioLoadingState.errors.set(i.name,String(r)),this.sendAudioAck({type:"sound-error",soundId:i.soundId,name:i.name,error:String(r)})}}normalizeSoundData(e){if(e instanceof Uint8Array)return e;if(e instanceof ArrayBuffer)return new Uint8Array(e);if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength));let t=globalThis.Buffer;if(t&&e instanceof t)return new Uint8Array(e);if(e&&typeof e=="object"&&Array.isArray(e.data))return new Uint8Array(e.data);if(Array.isArray(e))return new Uint8Array(e);if(typeof e=="string")try{let i=atob(e),r=i.length,s=new Uint8Array(r);for(let n=0;n<r;n++)s[n]=i.charCodeAt(n);return s}catch{}throw new Error("Invalid sound data payload")}async handleSoundExternalLoad(e){if(!this.audioManager){this.log("Cannot load external sounds: AudioManager not initialized");return}let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load external sounds: SoundBank not initialized");return}for(let i of e.sounds)try{await t.loadFromUrl(i.soundId,i.name,i.url),this.log(`Loaded external sound: ${i.name} from ${i.url}`),this.audioLoadingState.loadedSounds.add(i.name),this.audioLoadingState.errors.delete(i.name),this.sendAudioAck({type:"sound-loaded",soundId:i.soundId,name:i.name})}catch(r){console.error(`[NetworkSync] Failed to load external sound "${i.name}":`,r),this.audioLoadingState.errors.set(i.name,String(r)),this.sendAudioAck({type:"sound-error",soundId:i.soundId,name:i.name,error:String(r)})}}sendAudioAck(e){this.network.send("audio-ack",e),this.log(`Sent audio-ack: ${e.type}`)}sendBridge(e,t){this.network.sendBridge?.(e,t),this.log(`Bridge sent on channel '${e}'`)}onBridge(e,t){this.network.onBridge?.(e,t),this.log(`Bridge handler registered for channel '${e}'`)}offBridge(e,t){this.network.offBridge?.(e,t),this.log(`Bridge handler removed for channel '${e}'`)}removeAllBridgeHandlers(e){this.network.removeAllBridgeHandlers?.(e),this.log(e?`All bridge handlers removed for '${e}'`:"All bridge handlers removed")}};S(Z,"NetworkSync");var G=Z;var X=class X extends O{constructor(t){let i=t.mode;if(i!=="standalone"&&i!=="socketio"&&i!=="webrtc")throw new Error(`Invalid ClientRuntime mode: "${i}". Expected 'standalone', 'socketio', or 'webrtc'.`);let r;if(t.mode==="standalone"&&(r=t.standalone.application),!r&&t.mode==="standalone")throw new Error("Application instance required for standalone mode");super({application:r,container:t.container,displayContainers:t.displayContainers,debug:t.debug,width:t.width,height:t.height,renderer:t.renderer,useImageDataRendering:t.useImageDataRendering,renderMode:t.renderMode});d(this,"input",null);d(this,"networkSync",null);d(this,"mode");d(this,"localOptions",null);d(this,"autoplayOverlay",null);d(this,"autoplay",!0);d(this,"audioManager",null);d(this,"mobileVibration",null);d(this,"postProcessOverlay",null);d(this,"postProcessOverlays",new Map);d(this,"postProcessOrderCollector",new w.PostProcessOrderCollector);d(this,"pendingPaletteSlotByDisplay",new Map);d(this,"localBridgeHandlers",new Map);d(this,"localBridgeWildcardHandlers",new Set);this.mode=t.mode,this.autoplay=t.autoplay??!0,t.mode==="standalone"?(this.localOptions=t,this.userId=t.standalone.userId??"local"):this.localOptions=null,this.mode==="standalone"?(this.log("Initializing in STANDALONE mode"),this.initLocalMode()):(this.log(`Initializing in ${this.mode.toUpperCase()} mode`),this.initConnectedMode(t))}initLocalMode(){let t=this.localOptions;if(!t)return;this.log("Initializing ClientRuntime (standalone mode)"),t.inputEnabled??!0?this.initInput(t):this.log("Input disabled (inputEnabled: false)")}initConnectedMode(t){this.log(`Initializing ClientRuntime (${this.mode} mode)`),this.core=new w.Core({mode:"client",maxUsers:100}),this.core.onPaletteChanged(n=>{this.onCorePaletteChanged(n),this.retryPendingPaletteSelections()}),this.core.onBitmapFontChanged(n=>{this.onCoreBitmapFontChanged(n)}),this.core.onImageFontChanged(n=>{this.onCoreImageFontChanged(n)});let i;if(t.mode==="webrtc"){let n=t.webrtc;i=new H.WebRTCClient({url:n.signalUrl??"",sessionId:n.sessionId,signalingPath:n.signalingPath,iceServers:n.iceServers,autoReconnect:n.autoReconnect,auth:n.auth??{username:n.username},debug:t.debug})}else{let n=t.socketio;if(!n)throw new Error(`SocketIO configuration missing. Mode is '${t.mode}' but 'socketio' options are undefined.`);i=new H.SocketIOClient({url:n.url??"",path:n.path,autoReconnect:n.autoReconnect,auth:n.auth??{username:n.username},debug:t.debug})}let r=t.mode==="socketio"?t.socketio:t.webrtc;this.networkSync=new G(i,this.core,this.rendererManagers,this.performanceMonitor,{serverUrl:t.mode==="socketio"?t.socketio.url:t.webrtc.signalUrl||"WebRTC",username:r.username??"User",debug:t.debug,autoReconnect:r.autoReconnect,canvasWidth:t.width??80,canvasHeight:t.height??25},this.primaryDisplayId,n=>this.ensureRendererManager(n)),(t.inputEnabled??!0)&&(this.input||this.initInput(t))}initInput(t){this.input=new M.UnifiedInputRouter({enableKeyboardMouse:!0,enableGamepad:!0,enableMobile:!0,targetElement:window,mobileTargetElement:t.touchZones?.targetElement??void 0,debug:t.debug,keyboardConfig:{preventDefault:t.captureInput??!1,stopPropagation:t.captureInput??!1},mouseConfig:{preventDefault:t.captureInput??!1,stopPropagation:t.captureInput??!1},mobileConfig:{preventDefault:t.mobileInputConfig?.preventDefault??!1,passive:t.mobileInputConfig?.passive??!0,maxTouches:t.mobileInputConfig?.maxTouches??10},enableTouchZones:t.touchZones?.enable??!1,touchZoneConfig:{targetElement:t.touchZones?.targetElement,gridWidth:t.touchZones?.gridWidth??t.width??0,gridHeight:t.touchZones?.gridHeight??t.height??0,rendererOffsets:t.touchZones?.rendererOffsets,zones:t.touchZones?.zones}})}rebuildPostProcessOverlays(){for(let t of this.postProcessOverlays.values())t.destroy();this.postProcessOverlays.clear(),this.postProcessOverlay=null;for(let[t,i]of this.displayConfigs.entries()){let r=new W.PostProcessOverlay(i.container);this.postProcessOverlays.set(t,r),t===this.primaryDisplayId&&(this.postProcessOverlay=r)}!this.postProcessOverlay&&this.postProcessOverlays.size>0&&(this.postProcessOverlay=Array.from(this.postProcessOverlays.values())[0]??null)}getMode(){return this.mode}setTickRate(t){if(this.mode!=="standalone"){this.log("setTickRate() has no effect in connected mode");return}super.setTickRate(t)}async onBeforeStart(){this.audioManager=new ce.AudioManager({debug:this.options.debug}),this.mobileVibration=new M.MobileVibration({debug:this.options.debug}),this.autoplay?(this.log("Autoplay enabled, initializing AudioManager..."),this.audioManager.initialize()):(this.log("Autoplay disabled, showing overlay..."),await new Promise(t=>{this.autoplayOverlay=new W.AutoplayOverlay(this.options.container,{...this.localOptions?.autoplayOptions,onStart:()=>{this.log("User clicked start button"),this.audioManager&&(this.audioManager.initialize(),this.audioManager.playStartSound()),this.mobileVibration&&this.mobileVibration.vibrate(50),this.autoplayOverlay&&(this.autoplayOverlay.destroy(),this.autoplayOverlay=null),t()}})}),this.log("Autoplay overlay dismissed, continuing startup..."))}async start(){if(this.running){this.log("Already running");return}this.log("Starting ClientRuntime"),await this.onBeforeStart();for(let[r,s]of this.rendererManagers.entries())await s.initialize(this.core),this.log(`Renderer for display ${r} is ready`);this.rebuildPostProcessOverlays(),this.log("PostProcessOverlays created"),this.onCorePaletteChanged(this.core.getPalette()),this.log("Initial palette sent to renderer"),this.options.application&&(this.log("Calling application.init()"),await this.options.application.init(this.core,this));let t=this.rendererManager.getCanvas();if(t&&this.input&&this.input.setMobileTarget(t),this.mode!=="standalone"&&this.networkSync){if(this.audioManager&&this.networkSync.setAudioManager(this.audioManager),this.networkSync.setPostProcessCallback(s=>{this.applyPostProcessOrders(s)}),this.input){let s=this.input,n=this.rendererManager;this.networkSync.setTouchZonesCallback(o=>{this.log(`[start] Touch zones callback called with ${o.length} zones`);let a=n.getCanvas();if(this.log(`[start] Canvas available: ${!!a}`),a){let l=o.reduce((u,m)=>Math.max(u,m.x+m.width),0),c=o.reduce((u,m)=>Math.max(u,m.y+m.height),0);this.log(`[start] Grid from zones: ${l}x${c}`);let h=s.enableTouchZonesDevice(a,l,c,o);this.log(`[start] enableTouchZonesDevice returned: ${h}`),h&&this.log(`Touch zones configured from server: ${o.length} zones`)}})}await this.networkSync.connect(),this.userId=await this.networkSync.joinGame(this.options.application);let r=this.core.getUser(this.userId);r&&this.configureUserProcessors(r)}else await this.createLocalUser();let i=this.core.getUser(this.userId);if(i){let r=i.getDisplays();if(r.length>0){let n=r[0].getSize(),o=n.x,a=n.y,l=this.rendererManager.getRenderer(),c,h;if(this.rendererType==="webgl"){let m=l.getGridSize();c=m.cols,h=m.rows}else{let u=l;c=u.getCols(),h=u.getRows()}(c!==o||h!==a)&&(this.log(`Adjusting renderer from ${c}\xD7${h} to match display ${o}\xD7${a}`),l.resize(o,a))}}this.input&&this.input.start(),this.running=!0,this.startTime=performance.now(),this.lastTimestamp=this.startTime,this.lastRenderTimestamp=this.startTime,this.accumulatedTime=0,this.firstTickDone=!1,this.performanceMonitor.reset(),this.performanceMonitor.startTracking(this.startTime),this.log("Starting main loop"),this.mainLoop(this.lastTimestamp)}async onStop(){this.audioManager&&this.audioManager.stopAll(),this.input&&this.input.stop(),this.mode!=="standalone"&&this.networkSync&&this.networkSync.disconnect()}getStats(){let t=super.getStats(),r=this.core.getUser(this.userId)?.getTotalBytesReceived();return{...t,mode:this.mode,latency:void 0,totalBytesReceived:r}}getAudioLoadingState(){if(this.mode!=="standalone"&&this.networkSync)return this.networkSync.getAudioLoadingState();if(this.audioManager){let t=this.audioManager.getSoundBank();if(t){let i=t.getStats();return{loadedCount:i.totalSounds,totalExpected:i.totalSounds,errorCount:0,isComplete:!0,errors:[]}}}return{loadedCount:0,totalExpected:0,errorCount:0,isComplete:!0,errors:[]}}async onDestroy(){this.autoplayOverlay&&(this.autoplayOverlay.destroy(),this.autoplayOverlay=null),this.audioManager&&(this.audioManager.destroy(),this.audioManager=null),this.postProcessOverlay&&(this.postProcessOverlay.destroy(),this.postProcessOverlay=null);for(let t of this.postProcessOverlays.values())t.destroy();this.postProcessOverlays.clear(),this.input&&this.input.destroy(),this.networkSync&&this.networkSync.destroy()}configureUserProcessors(t){if(this.audioManager&&t.setAudioProcessor(this.audioManager),this.mobileVibration&&t.setMobileVibrationProcessor(this.mobileVibration),this.input){let i=this.input.getGamepad();i&&t.setGamepadVibrationProcessor(i)}}async createLocalUser(){let t=this.localOptions;this.userId=t?.standalone.userId??"local",this.log(`Creating local user: ${this.userId}`);let i=this.core.createUser(this.userId,t?.standalone.username??"User");if(i.setBytesTickRate(this.tickRate>0?this.tickRate:20),this.configureUserProcessors(i),this.options.application?.initUser&&(this.log("Calling application.initUser()"),this.options.application.initUser(this.core,i,{username:t?.standalone.username??"User"})),i.hasAudioConfigCommands()&&(this.log("Applying audio config commands from initUser()"),i.applyAudioConfigCommands(i.flushAudioConfigCommands())),i.hasPendingMacroOrders()){this.log("Applying macro orders from initUser()");let a=i.flushMacroOrders();i.applyMacroOrders(a)}if(i.hasPostProcessCommands()){this.log("Applying post-process commands from initUser()");let a=i.flushPostProcessCommands(),l=this.postProcessOrderCollector.convertCommands(a);this.applyPostProcessOrders(l)}i.needsSendSounds()&&(await this.loadSoundsFromRegistry(),i.clearSendSounds());let r=this.core.generateAllLoadPackets();r.forEach(a=>{i.recordBytesReceived(a.length)});let s=this.core.generateMacroLoadPackets(this.userId);s.forEach(a=>{i.recordBytesReceived(a.length)});let n=i.getInputBindingsLoadPacket();if(n&&(i.recordBytesReceived(n.length),this.input)){let l=i.getInputBindingRegistry().getAllTouchZones();if(l.length>0){let c=this.rendererManager.getCanvas();if(c){let h=i.getDisplays(),u=h.length>0?h[0].getSize():{x:this.options.width??80,y:this.options.height??25},m=l.map(f=>({id:f.zoneId,x:f.x,y:f.y,width:f.width,height:f.height}));this.input.enableTouchZonesDevice(c,u.x,u.y,m)?this.log(`Touch zones synchronized from registry: ${l.length} zones`):this.log("Failed to enable touch zones - mobile input may not be initialized")}}}this.log(`Simulated ${r.length} load packets, ${s.length} macro packets for byte counting`),this.log("Performing initial render"),this.core.endTick().forEach(({static:a,dynamic:l},c)=>{let h=this.core.getUser(c);h&&(a&&h.recordBytesReceived(a.length),l&&h.recordBytesReceived(l.length))}),this.render(),this.log("Initial render complete")}async loadSoundsFromRegistry(){if(!this.audioManager){this.log("Cannot load sounds: AudioManager not initialized");return}let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load sounds: SoundBank not initialized");return}let r=this.core.getSoundRegistry().getAll();if(r.length===0){this.log("No sounds to load from registry");return}this.log(`Loading ${r.length} sounds from Core registry into AudioManager...`);let s=this.core.getUser(this.userId),n=0;for(let o of r)try{if(o.loadType==="file"&&o.data){await t.loadFromData(o.soundId,o.name,o.data);let a=o.data.length+o.name.length+10;n+=a,this.log(`\u{1F50A} Loaded sound: ${o.name} (${o.data.length} bytes)`)}else if(o.loadType==="external"&&o.url){await t.loadFromUrl(o.soundId,o.name,o.url);let a=o.url.length+o.name.length+10;n+=a,this.log(`\u{1F50A} Loaded external sound: ${o.name} from ${o.url}`)}}catch(a){console.error(`[ClientRuntime] Failed to load sound "${o.name}":`,a)}s&&n>0&&(s.recordBytesReceived(n),this.log(`Simulated ${n} bytes for ${r.length} sound(s)`)),this.log(`\u2713 ${t.size} sounds loaded into AudioManager`)}mainLoop(t){if(!this.running){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0);return}if(this.renderMode==="on-demand"){this.renderRequested&&(this.renderRequested=!1,this.performanceMonitor.updateFPS(t),this.render()),this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}let i=t-this.lastRenderTimestamp;if(this.lastRenderTimestamp>0&&i<this.FRAME_TIME_MIN-1){this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}this.lastRenderTimestamp=t;let r=(t-this.lastTimestamp)/1e3,s=Math.min(r,.1);this.lastTimestamp=t,this.performanceMonitor.updateFPS(t);let n=this.core.getUser(this.userId);if(!n){this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}if(this.mode==="standalone"){if(this.tickRate===0){let c=performance.now();this.render();let h=performance.now()-c;this.performanceMonitor.recordFrameTiming(0,h),this.rafId=requestAnimationFrame(u=>this.mainLoop(u));return}if(!this.firstTickDone){this.firstTickDone=!0,this.lastTimestamp=t,this.accumulatedTime=0,this.rafId=requestAnimationFrame(c=>this.mainLoop(c));return}this.accumulatedTime+=s;let o=1/this.tickRate;this.accumulatedTime>.5&&(this.accumulatedTime=o);let a=0,l=0;for(;this.accumulatedTime>=o&&a<5;){let c=performance.now();if(this.collectAndApplyInput(n),this.options.application&&(this.options.application.update?.(this.core,o),this.options.application.updateUser?.(this.core,n,o)),n.clearTextInputs(),n.hasAudioConfigCommands()&&n.applyAudioConfigCommands(n.flushAudioConfigCommands()),n.hasSoundCommands()&&n.applyAudioCommands(n.flushSoundCommands()),n.hasMobileVibrationCommands()&&n.applyMobileVibrationCommands(n.flushMobileVibrationCommands()),n.hasGamepadVibrationCommands()&&n.applyGamepadVibrationCommands(n.flushGamepadVibrationCommands()),n.hasPostProcessCommands()){let m=n.flushPostProcessCommands(),v=this.postProcessOrderCollector.convertCommands(m);this.applyPostProcessOrders(v)}if(n.hasPendingMacroOrders()){let m=n.flushMacroOrders();n.applyMacroOrders(m)}let h=n.updateMacros();if(n.processMacroEvents(h),n.hasBridgeMessages()){let m=n.getBridgeMessages();this.dispatchLocalBridgeMessages(m)}this.core.endTick().forEach(({static:m,dynamic:v})=>{let f=(m?.length??0)+(v?.length??0);n.recordBytesReceived(f)}),l+=performance.now()-c,this.accumulatedTime-=o,a++}if(a>0){let c=performance.now();this.render();let h=performance.now()-c;this.performanceMonitor.recordFrameTiming(l,h)}}else{let o=n.updateMacros();n.processMacroEvents(o),this.collectAndSendInput()}this.rafId=requestAnimationFrame(o=>this.mainLoop(o))}collectAndApplyInput(t){if(!this.input)return;let i=this.rendererManager.getCanvas();if(i){let a=t.getDisplays(),c=(a.find(g=>g.getId&&g.getId()===this.primaryDisplayId)??a[0])?.getSize()??{x:this.options.width,y:this.options.height},h=c.x,u=c.y,v=this.rendererManager.getRenderer()?.getOffsets?.(),f={offsetX:v?.offsetX??0,offsetY:v?.offsetY??0};this.input.updateTouchZoneLayout(h,u,f);let C=M.InputCollector.collectMousePosition(this.input,i,h,u,f);t.setMousePosition(C.x,C.y,C.over),t.updateMacroMouse(C.x,C.y,C.isLeftDown),M.InputCollector.collectTouchPositions(this.input,i,h,u,10,f).forEach(g=>{t.setTouchPosition(g.id,g.x,g.y,g.over)});let y=this.rendererManagers.get(this.primaryDisplayId)?.getAvailableSize();y&&t.setDisplayViewport(this.primaryDisplayId,y.width,y.height)}let r=M.InputCollector.collectTextInputs(this.input);r.length>0&&t.setTextInputs(r);let s=t.getInputBindingRegistry(),n=s.getAllAxes(),o=s.getAllButtons();if(n.length>0||o.length>0){let a=M.InputCollector.collectAxisSources(n,this.input),l=M.InputCollector.collectButtonSourcesWithTransitions(o,this.input);n.forEach(c=>{let h=s.evaluateAxis(c.bindingId,a);t.setAxis(c.name,h)}),o.forEach(c=>{let h=new Map,u=new Map,m=new Map;for(let[b,p]of l)h.set(b,p.pressed),u.set(b,p.justPressed),m.set(b,p.justReleased);let v=s.evaluateButton(c.bindingId,h),f=s.evaluateButton(c.bindingId,u),C=s.evaluateButton(c.bindingId,m);t.setButton(c.name,v),t.setButton(`${c.name}_justPressed`,f),t.setButton(`${c.name}_justReleased`,C)})}this.input.poll?.()}collectAndSendInput(){!this.networkSync||!this.input||this.networkSync.sendInput(this.input)}render(){let t=this.core.getUser(this.userId);if(t){let i=t.getDisplays();for(let r of i){let s=r.getId(),n=this.rendererManagers.get(s);if(!n){console.warn(`[ClientRuntime] No renderer for display ${s}, skipping resize`);continue}let o=n.getRenderer();if(!o)continue;let a=r.getSize(),l,c,h,u,m=null;if("getGridSize"in o){let f=o,C=f.getGridSize();l=C.cols,c=C.rows,h=f.getCellWidth(),u=f.getCellHeight(),m=f.getScalingMode()}else if("getCols"in o){let f=o;l=f.getCols(),c=f.getRows(),h=f.getCellWidth(),u=f.getCellHeight(),m=f.getScalingMode()}else continue;if(m===x.ScalingMode.Responsive){let f=n.getAvailableSize(),C=256*256;"getMaxCells"in o&&(C=Math.min(C,o.getMaxCells()));let b=Math.floor(f.width/h),p=Math.floor(f.height/u);if(b=Math.min(256,Math.max(1,b)),p=Math.min(256,Math.max(1,p)),b*p>C){let y=Math.sqrt(C/(b*p));b=Math.max(1,Math.floor(b*y)),p=Math.max(1,Math.floor(p*y)),this.log(`\u26A0\uFE0F [Display ${s}] Device limit: max ${C} cells, clamping to ${b}\xD7${p}`)}(a.x!==b||a.y!==p)&&(this.log(`\u{1F4D0} [Display ${s}] Resizing display from ${a.x}\xD7${a.y} to ${b}\xD7${p} (available: ${f.width}\xD7${f.height}px, cell: ${h}\xD7${u}px)`),r.setSize(new x.Vector2(b,p)))}let v=r.getSize();(l!==v.x||c!==v.y)&&(this.log(`\u{1F4D0} [Display ${s}] Resizing renderer from ${l}\xD7${c} to ${v.x}\xD7${v.y}`),o.resize(v.x,v.y))}}super.render()}onFontChanged(t,i){let r=i??this.primaryDisplayId,s=this.postProcessOverlays.get(r)??this.postProcessOverlay;s&&"syncWithRenderer"in s&&"getCellWidth"in t&&"getCellHeight"in t&&"getCurrentScale"in t&&"getGridSize"in t&&(s.syncWithRenderer(t),this.log(`\u2713 PostProcessOverlay synced with renderer dimensions (display ${r})`))}getAudioManager(){return this.audioManager}getLayerTrafficStats(){return this.networkSync?.getLayerTrafficStats()??{}}getMiscTrafficStats(){return this.networkSync?.getMiscTrafficStats?.()??{}}getDisplayTrafficStats(){return this.networkSync?.getDisplayTrafficStats?.()??{}}getAudioContext(){return this.audioManager?.getContext()??null}getPostProcessOverlay(){return this.postProcessOverlay}applyAmbientEffectConfig(t,i){let r=this.rendererManagers.get(t)?.getRenderer();r&&"setAmbientEffect"in r&&(i.enabled?r.setAmbientEffect({blur:i.blur,scale:i.scale}):r.setAmbientEffect(!1),this.log(`[Display ${t}] Ambient effect ${i.enabled?"enabled":"disabled"}`))}applyPostProcessOrders(t){for(let i of t){let r=i.displayId??this.primaryDisplayId,s=this.postProcessOverlays.get(r)??this.postProcessOverlay,n=this.rendererManagers.get(r)?.getRenderer();switch(i.type){case w.PostProcessOrderType.SetConfig:{if(!s){console.warn(`[ClientRuntime] No PostProcessOverlay for display ${r}`);break}let o={};i.scanlines&&(o.scanlines={enabled:i.scanlines.enabled,opacity:i.scanlines.opacity,pattern:this.patternFromType(i.scanlines.pattern),color:{r:i.scanlines.colorR,g:i.scanlines.colorG,b:i.scanlines.colorB}}),i.ambientEffect&&(o.ambientEffect={enabled:i.ambientEffect.enabled,blur:i.ambientEffect.blur,scale:i.ambientEffect.scale}),s.setConfig(Object.keys(o).length>0?o:null),o.ambientEffect&&n&&this.applyAmbientEffectConfig(r,o.ambientEffect),this.log(`[Display ${r}] SetConfig applied`);break}case w.PostProcessOrderType.SetScanlines:{if(!s){console.warn(`[ClientRuntime] No PostProcessOverlay for display ${r}`);break}s.setScanlines({enabled:i.enabled,opacity:i.opacity,pattern:this.patternFromType(i.pattern),color:{r:i.colorR,g:i.colorG,b:i.colorB}}),this.log(`[Display ${r}] Scanlines ${i.enabled?"enabled":"disabled"}`);break}case w.PostProcessOrderType.SetAmbientEffect:{this.applyAmbientEffectConfig(r,{enabled:i.enabled,blur:i.blur,scale:i.scale}),this.log(`[Display ${r}] Ambient effect ${i.enabled?"enabled":"disabled"}`);break}case w.PostProcessOrderType.SetScalingMode:{this.applyScalingMode(r,i.mode);break}case w.PostProcessOrderType.SetGrid:{this.applyGridConfig(r,i);break}case w.PostProcessOrderType.SwitchPalette:{this.applySwitchPalette(r,i);break}case w.PostProcessOrderType.SetCellSize:{this.applyCellSize(r,i.cellWidth,i.cellHeight);break}}}}applyScalingMode(t,i){let r=this.rendererManagers.get(t)?.getRenderer();if(r&&"setScalingMode"in r){let s=(0,x.valueToScalingMode)(i);r.setScalingMode(s),this.log(`[Display ${t}] Scaling mode set to ${s}`)}}applyGridConfig(t,i){let r=this.rendererManagers.get(t)?.getRenderer();if(r&&"setGrid"in r){let s=i.colorA/255;r.setGrid({enabled:i.enabled,color:`rgba(${i.colorR},${i.colorG},${i.colorB},${s})`,lineWidth:i.lineWidth}),this.log(`[Display ${t}] Grid ${i.enabled?"enabled":"disabled"}`)}}applySwitchPalette(t,i){let r=this.core.getPaletteFromSlot(i.slotId);if(!r){this.pendingPaletteSlotByDisplay.set(t,i.slotId),console.warn(`[ClientRuntime] Palette slot ${i.slotId} not found (display ${t}); will retry when available`);return}let s=[];for(let o=0;o<256;o++){let a=r.get(o);a?s.push({r:a.r,g:a.g,b:a.b,a:a.a}):s.push({r:0,g:0,b:0,a:0})}let n=this.rendererManagers.get(t)?.getRenderer();n&&"setPalette"in n&&(n.setPalette(s),this.log(`[Display ${t}] Switched to palette slot ${i.slotId}`)),this.pendingPaletteSlotByDisplay.get(t)===i.slotId&&this.pendingPaletteSlotByDisplay.delete(t)}retryPendingPaletteSelections(){if(this.pendingPaletteSlotByDisplay.size!==0)for(let[t,i]of this.pendingPaletteSlotByDisplay.entries()){let r=this.core.getPaletteFromSlot(i);if(!r)continue;let s=[];for(let o=0;o<256;o++){let a=r.get(o);a?s.push({r:a.r,g:a.g,b:a.b,a:a.a}):s.push({r:0,g:0,b:0,a:0})}let n=this.rendererManagers.get(t)?.getRenderer();n&&"setPalette"in n&&(n.setPalette(s),this.log(`[Display ${t}] Applied pending palette slot ${i}`),this.pendingPaletteSlotByDisplay.delete(t))}}applyCellSize(t,i,r){let s=this.rendererManagers.get(t)?.getRenderer();s&&"setCellSize"in s&&(s.setCellSize(i,r),this.log(`[Display ${t}] Cell size set to ${i}\xD7${r}px`))}patternFromType(t){switch(t){case 0:return"horizontal";case 1:return"vertical";case 2:return"grid";default:return"horizontal"}}dispatchLocalBridgeMessages(t){for(let i of t){let{channel:r,data:s}=i,n=this.localBridgeHandlers.get(r);if(n)for(let o of n)try{o(s)}catch(a){console.error(`[ClientRuntime] Bridge handler error on '${r}':`,a)}for(let o of this.localBridgeWildcardHandlers)try{o(r,s)}catch(a){console.error("[ClientRuntime] Bridge wildcard handler error:",a)}this.log(`Bridge message dispatched on channel '${r}'`)}}sendBridge(t,i){if(this.mode!=="standalone"&&this.networkSync)this.networkSync.sendBridge(t,i);else if(this.mode==="standalone"){let r=this.core.getUser(this.userId);r&&this.options.application?.onBridgeMessage&&(this.options.application.onBridgeMessage(this.core,r,t,i),this.log(`Bridge message sent to application on channel '${t}'`))}}onBridge(t,i){this.mode!=="standalone"&&this.networkSync?this.networkSync.onBridge(t,i):this.mode==="standalone"&&(t==="*"?this.localBridgeWildcardHandlers.add(i):(this.localBridgeHandlers.has(t)||this.localBridgeHandlers.set(t,new Set),this.localBridgeHandlers.get(t).add(i)),this.log(`Bridge handler registered for channel '${t}'`))}offBridge(t,i){this.mode!=="standalone"&&this.networkSync?this.networkSync.offBridge(t,i):this.mode==="standalone"&&(t==="*"?this.localBridgeWildcardHandlers.delete(i):this.localBridgeHandlers.get(t)?.delete(i))}removeAllBridgeHandlers(t){this.mode!=="standalone"&&this.networkSync?this.networkSync.removeAllBridgeHandlers(t):this.mode==="standalone"&&(t===void 0?(this.localBridgeHandlers.clear(),this.localBridgeWildcardHandlers.clear()):t==="*"?this.localBridgeWildcardHandlers.clear():this.localBridgeHandlers.delete(t))}log(t){this.options.debug&&console.warn(`[ClientRuntime/${this.mode}] ${t}`)}};S(X,"ClientRuntime");var z=X;var T=require("@utsp/input");var _=class _{constructor(e={}){d(this,"input");d(this,"mobileVibration");this.input=new T.UnifiedInputRouter({enableKeyboardMouse:!0,enableGamepad:!0,enableMobile:!0,targetElement:window,mobileTargetElement:void 0,debug:e.debug,keyboardConfig:{preventDefault:e.captureInput??!1,stopPropagation:e.captureInput??!1},mouseConfig:{preventDefault:e.captureInput??!1,stopPropagation:e.captureInput??!1},mobileConfig:{preventDefault:e.mobileInputConfig?.preventDefault??!1,passive:e.mobileInputConfig?.passive??!0,maxTouches:e.mobileInputConfig?.maxTouches??10}}),this.mobileVibration=new T.MobileVibration({debug:e.debug})}setMobileTarget(e){this.input.setMobileTarget(e)}start(){this.input.start()}stop(){this.input.stop()}destroy(){this.input.destroy()}getRouter(){return this.input}getGamepad(){return this.input.getGamepad()}getMobileVibration(){return this.mobileVibration}collectAndApply(e,t,i,r,s){if(t){let c=T.InputCollector.collectMousePosition(this.input,t,i,r,s);e.setMousePosition(c.x,c.y,c.over),e.updateMacroMouse(c.x,c.y,c.isLeftDown),T.InputCollector.collectTouchPositions(this.input,t,i,r,10,s).forEach(u=>{e.setTouchPosition(u.id,u.x,u.y,u.over)})}let n=T.InputCollector.collectTextInputs(this.input);n.length>0&&e.setTextInputs(n);let o=e.getInputBindingRegistry(),a=o.getAllAxes(),l=o.getAllButtons();if(a.length>0||l.length>0){let c=T.InputCollector.collectAxisSources(a,this.input),h=T.InputCollector.collectButtonSourcesWithTransitions(l,this.input);a.forEach(u=>{let m=o.evaluateAxis(u.bindingId,c);e.setAxis(u.name,m)}),l.forEach(u=>{let m=new Map,v=new Map,f=new Map;for(let[y,g]of h)m.set(y,g.pressed),v.set(y,g.justPressed),f.set(y,g.justReleased);let C=o.evaluateButton(u.bindingId,m),b=o.evaluateButton(u.bindingId,v),p=o.evaluateButton(u.bindingId,f);e.setButton(u.name,C),e.setButton(`${u.name}_justPressed`,b),e.setButton(`${u.name}_justReleased`,p)})}this.input.poll?.()}processVibrationCommands(e){e.hasMobileVibrationCommands()&&e.applyMobileVibrationCommands(e.flushMobileVibrationCommands()),e.hasGamepadVibrationCommands()&&e.applyGamepadVibrationCommands(e.flushGamepadVibrationCommands())}};S(_,"InputFeature");var q=_;var ue=require("@utsp/audio");var ee=class ee{constructor(e={}){d(this,"audioManager");d(this,"debug");this.debug=e.debug??!1,this.audioManager=new ue.AudioManager({debug:e.debug})}initialize(){this.audioManager.initialize()}playStartSound(){this.audioManager.playStartSound()}stopAll(){this.audioManager.stopAll()}destroy(){this.audioManager.destroy()}getManager(){return this.audioManager}getContext(){return this.audioManager.getContext()}injectIntoUser(e){e.setAudioProcessor(this.audioManager)}processAudioCommands(e){e.hasAudioConfigCommands()&&e.applyAudioConfigCommands(e.flushAudioConfigCommands()),e.hasSoundCommands()&&e.applyAudioCommands(e.flushSoundCommands())}async loadSoundsFromRegistry(e){let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load sounds: SoundBank not initialized");return}let r=e.getSoundRegistry().getAll();if(r.length===0){this.log("No sounds to load from registry");return}this.log(`Loading ${r.length} sounds from Core registry...`);for(let s of r)try{s.loadType==="file"&&s.data?(await t.loadFromData(s.soundId,s.name,s.data),this.log(`Loaded sound: ${s.name} (${s.data.length} bytes)`)):s.loadType==="external"&&s.url&&(await t.loadFromUrl(s.soundId,s.name,s.url),this.log(`Loaded external sound: ${s.name} from ${s.url}`))}catch(n){console.error(`[AudioFeature] Failed to load sound "${s.name}":`,n)}this.log(`${t.size} sounds loaded`)}log(e){this.debug&&console.warn(`[AudioFeature] ${e}`)}};S(ee,"AudioFeature");var Q=ee;var k=require("@utsp/core"),he=require("@utsp/render"),pe=require("@utsp/types");var te=class te{constructor(e,t={}){d(this,"overlay");d(this,"orderCollector");d(this,"debug");this.debug=t.debug??!1,this.overlay=new he.PostProcessOverlay(e),this.orderCollector=new k.PostProcessOrderCollector}destroy(){this.overlay.destroy()}getOverlay(){return this.overlay}syncWithRenderer(e){this.overlay.syncWithRenderer(e),this.log("Overlay synced with renderer dimensions")}processCommands(e,t){if(!e.hasPostProcessCommands())return;let i=e.flushPostProcessCommands(),r=this.orderCollector.convertCommands(i);this.applyOrders(r,t)}applyOrders(e,t){for(let i of e){let r=i.displayId;switch(i.type){case k.PostProcessOrderType.SetConfig:{let s={};i.scanlines&&(s.scanlines={enabled:i.scanlines.enabled,opacity:i.scanlines.opacity,pattern:this.patternFromType(i.scanlines.pattern),color:{r:i.scanlines.colorR,g:i.scanlines.colorG,b:i.scanlines.colorB}}),i.ambientEffect&&(s.ambientEffect={enabled:i.ambientEffect.enabled,blur:i.ambientEffect.blur,scale:i.ambientEffect.scale}),this.overlay.setConfig(Object.keys(s).length>0?s:null),s.ambientEffect&&this.applyAmbientEffect(t,s.ambientEffect),this.log(`[Display ${r}] SetConfig applied`);break}case k.PostProcessOrderType.SetScanlines:{this.overlay.setScanlines({enabled:i.enabled,opacity:i.opacity,pattern:this.patternFromType(i.pattern),color:{r:i.colorR,g:i.colorG,b:i.colorB}}),this.log(`[Display ${r}] Scanlines ${i.enabled?"enabled":"disabled"}`);break}case k.PostProcessOrderType.SetAmbientEffect:{this.applyAmbientEffect(t,{enabled:i.enabled,blur:i.blur,scale:i.scale}),this.log(`[Display ${r}] Ambient effect ${i.enabled?"enabled":"disabled"}`);break}case k.PostProcessOrderType.SetScalingMode:{this.applyScalingMode(t,r,i.mode);break}case k.PostProcessOrderType.SetGrid:{this.applyGridConfig(t,r,i);break}}}}applyAmbientEffect(e,t){e&&"setAmbientEffect"in e&&(t.enabled?e.setAmbientEffect({blur:t.blur,scale:t.scale}):e.setAmbientEffect(!1))}applyScalingMode(e,t,i){if(e&&"setScalingMode"in e){let r=(0,pe.valueToScalingMode)(i);e.setScalingMode(r),this.log(`[Display ${t}] Scaling mode set to ${r}`)}}applyGridConfig(e,t,i){if(e&&"setGrid"in e){let r=i.colorA/255;e.setGrid({enabled:i.enabled,color:`rgba(${i.colorR},${i.colorG},${i.colorB},${r})`,lineWidth:i.lineWidth}),this.log(`[Display ${t}] Grid ${i.enabled?"enabled":"disabled"}`)}}patternFromType(e){switch(e){case 0:return"horizontal";case 1:return"vertical";case 2:return"grid";default:return"horizontal"}}log(e){this.debug&&console.warn(`[PostProcessFeature] ${e}`)}};S(te,"PostProcessFeature");var K=te;var ge=require("@utsp/render"),me=require("@utsp/types"),fe=require("@utsp/audio");
|
|
1
|
+
"use strict";var V=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var Ce=Object.prototype.hasOwnProperty;var Se=(v,e,t)=>e in v?V(v,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):v[e]=t;var R=(v,e)=>V(v,"name",{value:e,configurable:!0});var Re=(v,e)=>{for(var t in e)V(v,t,{get:e[t],enumerable:!0})},ve=(v,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of be(e))!Ce.call(v,r)&&r!==t&&V(v,r,{get:()=>e[r],enumerable:!(i=ye(e,r))||i.enumerable});return v};var Ie=v=>ve(V({},"__esModule",{value:!0}),v);var l=(v,e,t)=>(Se(v,typeof e!="symbol"?e+"":e,t),t);var Me={};Re(Me,{AudioFeature:()=>W,AudioManager:()=>fe.AudioManager,BaseClientRuntime:()=>B,ClientRuntime:()=>Q,DEFAULT_ATLAS_CONFIG:()=>U,InputFeature:()=>H,NetworkTransportType:()=>me.NetworkTransportType,PostProcessFeature:()=>Y,RendererManager:()=>A,RendererType:()=>z,ScalingMode:()=>ge.ScalingMode,decodeDefaultAtlas:()=>K});module.exports=Ie(Me);var le=require("@utsp/core"),L=require("@utsp/render");var z=(t=>(t.TerminalGL="webgl",t.Terminal2D="terminal2d",t))(z||{});var j=class j{constructor(e=60){l(this,"frameCount",0);l(this,"fps",0);l(this,"fpsUpdateTime",0);l(this,"lastCoreTime",0);l(this,"lastRenderTime",0);l(this,"lastTotalTime",0);l(this,"coreTimeSamples",[]);l(this,"renderTimeSamples",[]);l(this,"totalTimeSamples",[]);l(this,"maxSamples");if(e<=0)throw new Error("maxSamples must be positive");this.maxSamples=e}startTracking(e){this.fpsUpdateTime=e,this.frameCount=0,this.fps=0}updateFPS(e){this.frameCount++,e-this.fpsUpdateTime>=1e3&&(this.fps=Math.round(this.frameCount*1e3/(e-this.fpsUpdateTime)),this.frameCount=0,this.fpsUpdateTime=e)}recordFrameTiming(e,t){let i=e+t;this.lastCoreTime=e,this.lastRenderTime=t,this.lastTotalTime=i,this.coreTimeSamples.push(e),this.renderTimeSamples.push(t),this.totalTimeSamples.push(i),this.coreTimeSamples.length>this.maxSamples&&(this.coreTimeSamples.shift(),this.renderTimeSamples.shift(),this.totalTimeSamples.shift())}getFPS(){return this.fps}getLastFrameTiming(){if(!(this.lastCoreTime===0&&this.lastRenderTime===0))return{coreTime:this.lastCoreTime,renderTime:this.lastRenderTime,totalTime:this.lastTotalTime}}getAverageFrameTiming(){if(this.coreTimeSamples.length!==0)return{coreTime:this.average(this.coreTimeSamples),renderTime:this.average(this.renderTimeSamples),totalTime:this.average(this.totalTimeSamples)}}getStats(){return{fps:this.fps,lastFrame:this.getLastFrameTiming(),avgFrame:this.getAverageFrameTiming(),sampleCount:this.coreTimeSamples.length,maxSamples:this.maxSamples}}reset(){this.frameCount=0,this.fps=0,this.fpsUpdateTime=0,this.lastCoreTime=0,this.lastRenderTime=0,this.lastTotalTime=0,this.coreTimeSamples=[],this.renderTimeSamples=[],this.totalTimeSamples=[]}average(e){return e.length===0?0:e.reduce((t,i)=>t+i,0)/e.length}};R(j,"PerformanceMonitor");var D=j;var we="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",U={glyphWidth:8,glyphHeight:8,cellWidth:8,cellHeight:8,atlasBlocks:1,atlasWidth:128,atlasHeight:128};function K(){if(typeof atob=="function"){let v=atob(we),e=new Uint8Array(v.length);for(let t=0;t<v.length;t++)e[t]=v.charCodeAt(t);return e}throw new Error("[UTSP] decodeDefaultAtlas: atob() is not available in this environment")}R(K,"decodeDefaultAtlas");var J=class J{constructor(e,t={}){l(this,"renderer");l(this,"options");l(this,"layerFilter",null);this.renderer=e,this.options={debug:t.debug??!1,useImageDataRendering:t.useImageDataRendering??!1}}setLayerFilter(e){this.layerFilter=e}getLayerFilter(){return this.layerFilter}async initialize(e){if("setImageDataRendering"in this.renderer&&this.options.useImageDataRendering&&(this.renderer.setImageDataRendering(!0),this.log("ImageData rendering enabled")),"setImageFont"in this.renderer&&typeof this.renderer.setImageFont=="function"){this.log("Loading default 8x8 font atlas...");let t=K();await this.renderer.setImageFont(t,U.glyphWidth,U.glyphHeight,U.cellWidth,U.cellHeight,U.atlasBlocks),this.log("Default 8x8 font atlas loaded")}await this.waitForReady(),this.log("Initialized and ready")}async waitForReady(e=100,t=50){this.log("Waiting for renderer to be ready");let i=0;return new Promise((r,s)=>{let n=R(()=>{if(i++,this.renderer.isReady())this.log(`Renderer ready after ${i*t}ms`),r();else if(i>=e){let a=`Renderer failed to be ready after ${e*t}ms`;this.log(a),s(new Error(a))}else setTimeout(n,t)},"check");n()})}async loadDefaultFont(e){console.warn("[RendererManager] loadDefaultFont() is deprecated. Use ImageFont instead.")}renderDisplay(e){return this.renderer.isReady()?e?(this.renderer.renderDisplayData(e),!0):(console.warn("[RENDERER MANAGER] No display provided"),!1):(console.warn("[RENDERER MANAGER] Renderer not ready"),!1)}render(e,t){let i=this.layerFilter?e.getRenderState(t,this.layerFilter):e.getRenderState(t);return!i||i.displays.length===0?(console.warn("[RENDERER MANAGER] No render state or no displays"),!1):this.renderDisplay(i.displays[0])}getRenderer(){return this.renderer}getCanvas(){return this.renderer.getCanvas()}getAvailableSize(){if(this.renderer.getAvailableSize)return this.renderer.getAvailableSize();let e=this.getCanvas();return{width:e?.clientWidth||e?.width||0,height:e?.clientHeight||e?.height||0}}isReady(){return this.renderer.isReady()}destroy(){this.log("Destroying renderer"),this.renderer.destroy()}log(e){this.options.debug&&console.warn(`[RendererManager] ${e}`)}};R(J,"RendererManager");var A=J;var N=class N{constructor(e){l(this,"core");l(this,"rendererManagers",new Map);l(this,"rendererInitPromises",new Map);l(this,"rendererManager");l(this,"rendererType");l(this,"primaryDisplayId",0);l(this,"displayConfigs");l(this,"options");l(this,"running",!1);l(this,"startTime",0);l(this,"lastTimestamp",0);l(this,"userId","");l(this,"visibilityChangeHandler");l(this,"tickRate",30);l(this,"accumulatedTime",0);l(this,"FRAME_TIME_MIN",1e3/60);l(this,"lastRenderTimestamp",0);l(this,"rafId",0);l(this,"firstTickDone",!1);l(this,"performanceMonitor");l(this,"renderMode","continuous");l(this,"renderRequested",!1);if(this.options={application:e.application,container:e.container,displayContainers:e.displayContainers,debug:e.debug??!1,width:e.width??80,height:e.height??25,renderer:e.renderer??"webgl",useImageDataRendering:e.useImageDataRendering??!0,renderMode:e.renderMode??"continuous"},this.log("Initializing BaseClientRuntime"),this.core=new le.Core({mode:"client",maxUsers:1}),this.core.onPaletteChanged(t=>{this.onCorePaletteChanged(t)}),this.core.onFontAllocated(()=>{this.onCoreImageFontAllocated(0)}),this.core.onFontBlockAdded(t=>{this.onCoreImageFontBlockAdded(0,t)}),this.core.onImageFontChanged(t=>{this.onCoreImageFontChanged(t)}),this.visibilityChangeHandler=()=>{!document.hidden&&this.running&&(this.lastTimestamp=performance.now(),this.accumulatedTime=0,this.log("Tab visible: Reset timing"))},document.addEventListener("visibilitychange",this.visibilityChangeHandler),this.rendererType=this.options.renderer,this.options.displayContainers&&this.options.displayContainers.length>0){this.displayConfigs=new Map([[0,{container:this.options.container,renderer:this.options.renderer}]]);for(let t of this.options.displayContainers){let i=t.renderer;this.displayConfigs.set(t.id,{container:t.container,renderer:i})}this.primaryDisplayId=0}else this.displayConfigs=new Map([[0,{container:this.options.container,renderer:this.options.renderer}]]),this.primaryDisplayId=0;this.createRendererManagers(),this.performanceMonitor=new D(60),this.tickRate=20,this.renderMode=e.renderMode??"continuous",this.log(`Configured: tickRate=${this.tickRate}, renderMode=${this.renderMode}`),this.log("BaseClientRuntime initialized")}createRenderer(e,t){if(t==="terminal2d"){this.log("Creating Terminal 2D renderer");let n=new L.Terminal2D(e,{fixedCols:this.options.width,fixedRows:this.options.height,cellAspectRatio:1});return this.log("Canvas 2D renderer created successfully"),n}this.log("Creating TerminalGL renderer");let r=document.createElement("canvas").getContext("webgl");if(!r)throw new Error("WebGL not supported. TerminalGL requires WebGL 1.0.");if(!r.getExtension("OES_element_index_uint"))throw new Error("OES_element_index_uint extension not supported. TerminalGL requires this extension for large terminals (256x256).");if(!(e instanceof HTMLDivElement))throw new Error(`TerminalGL requires container to be an HTMLDivElement. Received: ${e.tagName}`);let s=new L.TerminalGL(e,{cols:this.options.width,rows:this.options.height,charWidth:8,charHeight:8});return this.log("TerminalGL created successfully"),s}createRendererManagers(){let e=this.displayConfigs.size>=3;this.rendererManagers.clear();for(let[i,r]of this.displayConfigs.entries()){let s=e?"terminal2d":r.renderer??this.options.renderer,n=this.createRenderer(r.container,s??"webgl"),o=new A(n,{debug:this.options.debug,useImageDataRendering:this.options.useImageDataRendering});this.rendererManagers.set(i,o)}let t=this.rendererManagers.get(this.primaryDisplayId);if(!t)throw new Error(`Primary display ${this.primaryDisplayId} has no renderer. Check displayContainers configuration.`);this.rendererManager=t}ensureRendererManager(e){let t=this.rendererManagers.get(e);if(t)return t;let i=document.createElement("div");i.dataset.displayId=String(e),i.style.cssText="position:relative;display:inline-block;margin:4px;background:#000;overflow:hidden;",(this.options.container?.parentElement??document.body).appendChild(i),this.displayConfigs.set(e,{container:i});let o=this.displayConfigs.size>=3?"terminal2d":this.options.renderer??"webgl",a=this.createRenderer(i,o),c=new A(a,{debug:this.options.debug,useImageDataRendering:this.options.useImageDataRendering});if(this.rendererManagers.set(e,c),!this.rendererInitPromises.has(e)){let d=c.initialize(this.core).then(()=>{this.onCorePaletteChanged(this.core.getPalette());let u=this.core.getImageFontIds,h=typeof u=="function"?u.call(this.core):[];h.length>0&&this.onCoreImageFontChanged(h[0]);let m=this.rebuildPostProcessOverlays;typeof m=="function"&&m.call(this)}).catch(u=>{console.warn(`[BaseClientRuntime] Failed to init renderer for display ${e}:`,u)});this.rendererInitPromises.set(e,d)}return c}getRendererType(){return this.rendererType}isRunning(){return this.running}setTickRate(e){if(e<0||e>1e3)throw new Error(`Invalid tick rate: ${e}. Must be between 0 and 1000.`);if(this.tickRate=e,this.userId){let t=this.core.getUser(this.userId);t&&t.setBytesTickRate(e>0?e:20)}e===0&&this.renderMode==="continuous"?(this.renderMode="on-demand",this.log("Tick rate set to 0, switched to on-demand render mode")):this.log(`Tick rate set to ${e} TPS`)}setRenderMode(e){this.renderMode=e,this.log(`Render mode set to ${e}`)}setMaxFPS(e){if(e<=0||e>240)throw new Error(`Invalid FPS: ${e}. Must be between 1 and 240.`);this.FRAME_TIME_MIN=1e3/e,this.log(`Max FPS set to ${e}`)}getTickRate(){return this.tickRate}requestRender(){this.renderMode==="on-demand"&&(this.renderRequested=!0,this.log("Render requested"))}async start(){if(this.running){this.log("Already running");return}this.log("Starting BaseClientRuntime"),await this.onBeforeStart();for(let[e,t]of this.rendererManagers.entries())await t.initialize(this.core),this.log(`Renderer for display ${e} is ready`);this.onCorePaletteChanged(this.core.getPalette()),this.log("Initial palette sent to renderers"),this.options.application&&(this.log("Calling application.init()"),await this.options.application.init(this.core,this)),await this.onAfterInit(),await this.createLocalUser(),this.running=!0,this.startTime=performance.now(),this.lastTimestamp=this.startTime,this.lastRenderTimestamp=this.startTime,this.accumulatedTime=0,this.firstTickDone=!1,this.performanceMonitor.reset(),this.performanceMonitor.startTracking(this.startTime),this.log("Starting main loop"),this.mainLoop(this.lastTimestamp)}async onBeforeStart(){}async onAfterInit(){}async stop(){if(!this.running)return;this.log("Stopping BaseClientRuntime"),this.running=!1,this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0),await this.onStop();let e=this.core.getUser(this.userId);e&&this.options.application?.destroyUser&&this.options.application.destroyUser(this.core,e,"Runtime stopped"),this.log("BaseClientRuntime stopped")}async onStop(){}getStats(){let e=this.performanceMonitor.getStats();return{running:this.running,userCount:this.core.getUsers().length,fps:e.fps,uptime:this.running?performance.now()-this.startTime:0,totalFrames:0,lastFrameTiming:e.lastFrame,avgFrameTiming:e.avgFrame}}getTotalBytesReceived(){return this.core.getUser(this.userId)?.getTotalBytesReceived()??0}getBytesReceivedPerSecond(){return this.core.getUser(this.userId)?.getBytesReceivedPerSecond()??0}resetBytesReceived(){let e=this.core.getUser(this.userId);e&&e.resetByteCounters()}async destroy(){await this.stop(),this.log("Destroying BaseClientRuntime"),this.visibilityChangeHandler&&(document.removeEventListener("visibilitychange",this.visibilityChangeHandler),this.visibilityChangeHandler=void 0),await this.onDestroy();for(let e of this.rendererManagers.values()){let t=e.getRenderer();t&&"clearOnResizeCallback"in t&&t.clearOnResizeCallback()}this.options.application?.destroy&&this.options.application.destroy();for(let e of this.rendererManagers.values())e.destroy();this.log("BaseClientRuntime destroyed")}async onDestroy(){}async createLocalUser(){this.userId="local",this.log(`Creating local user: ${this.userId}`);let e=this.core.createUser(this.userId,"User");e.setBytesTickRate(this.tickRate>0?this.tickRate:20),this.onUserCreated(e),this.options.application?.initUser&&(this.log("Calling application.initUser()"),this.options.application.initUser(this.core,e,{username:"User"})),this.processInitialOrders(e);let t=this.core.generateAllLoadPackets();t.forEach(n=>{e.recordBytesReceived(n.length)});let i=this.core.generateMacroLoadPackets(this.userId);i.forEach(n=>{e.recordBytesReceived(n.length)});let r=e.getInputBindingsLoadPacket();r&&e.recordBytesReceived(r.length),this.log(`Simulated ${t.length} load packets, ${i.length} macro packets for byte counting`),this.log("Performing initial render"),this.core.endTick().forEach(({static:n,dynamic:o},a)=>{let c=this.core.getUser(a);c&&(n&&c.recordBytesReceived(n.length),o&&c.recordBytesReceived(o.length))})}processInitialOrders(e){if(e.hasPendingMacroOrders()){this.log("Applying macro orders from initUser()");let t=e.flushMacroOrders();e.applyMacroOrders(t)}}onUserCreated(e){}mainLoop(e){if(!this.running){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0);return}if(this.renderMode==="on-demand"){this.renderRequested&&(this.renderRequested=!1,this.performanceMonitor.updateFPS(e),this.render()),this.rafId=requestAnimationFrame(c=>this.mainLoop(c));return}let t=e-this.lastRenderTimestamp;if(this.lastRenderTimestamp>0&&t<this.FRAME_TIME_MIN-1){this.rafId=requestAnimationFrame(c=>this.mainLoop(c));return}this.lastRenderTimestamp=e;let i=(e-this.lastTimestamp)/1e3,r=Math.min(i,.1);this.lastTimestamp=e,this.performanceMonitor.updateFPS(e);let s=this.core.getUser(this.userId);if(!s){this.rafId=requestAnimationFrame(c=>this.mainLoop(c));return}if(this.tickRate===0){let c=performance.now();this.render();let d=performance.now()-c;this.performanceMonitor.recordFrameTiming(0,d),this.rafId=requestAnimationFrame(u=>this.mainLoop(u));return}if(!this.firstTickDone){this.firstTickDone=!0,this.lastTimestamp=e,this.accumulatedTime=0,this.rafId=requestAnimationFrame(c=>this.mainLoop(c));return}this.accumulatedTime+=r;let n=1/this.tickRate;this.accumulatedTime>.5&&(this.accumulatedTime=n);let o=0,a=0;for(;this.accumulatedTime>=n&&o<5;){let c=performance.now();this.collectAndApplyInput(s),this.options.application&&(this.options.application.update?.(this.core,n),this.options.application.updateUser?.(this.core,s,n)),this.processTickOrders(s);let d=s.updateMacros();s.processMacroEvents(d),this.core.endTick().forEach(({static:h,dynamic:m})=>{let C=(h?.length??0)+(m?.length??0);s.recordBytesReceived(C)}),a+=performance.now()-c,this.accumulatedTime-=n,o++}if(o>0){let c=performance.now();this.render();let d=performance.now()-c;this.performanceMonitor.recordFrameTiming(a,d)}this.rafId=requestAnimationFrame(c=>this.mainLoop(c))}collectAndApplyInput(e){}processTickOrders(e){if(e.clearTextInputs(),e.hasPendingMacroOrders()){let t=e.flushMacroOrders();e.applyMacroOrders(t)}}render(){let e=this.core.getUser(this.userId);if(e){let i=e.getMacroRenderOrders();for(let[r,s]of i){let n=e.getLayerById(r);n&&s.length>0&&n.addTemporaryOrders(s)}}let t=this.core.getRenderState(this.userId);if(!t||t.displays.length===0){console.warn("[BaseClientRuntime] No render state or displays");return}for(let i of t.displays){let r=this.rendererManagers.get(i.id)??this.ensureRendererManager(i.id);if(!r){console.warn(`[BaseClientRuntime] No renderer manager for display ${i.id}, skipping render`);continue}let s=r.getLayerFilter(),n=s?this.core.getRenderState(this.userId,s):t;if(!n){this.options.debug&&this.log(`Render state unavailable for display ${i.id} with filter`);continue}let o=n.displays.find(a=>a.id===i.id);if(!o){this.options.debug&&this.log(`Render state missing display ${i.id} after filtering`);continue}if(!r.isReady()){this.options.debug&&this.log(`Renderer for display ${i.id} not ready yet`);continue}r.renderDisplay(o)}}onCorePaletteChanged(e){this.log(`Palette changed, updating renderer (${e.size} colors)`);let t=[];for(let s=0;s<256;s++){let n=e.get(s);n?t.push({r:n.r,g:n.g,b:n.b,a:n.a}):t.push({r:0,g:0,b:0,a:0})}let i=R(s=>{s&&"setPalette"in s&&typeof s.setPalette=="function"&&s.setPalette(t)},"applyPalette"),r=0;for(let s of this.rendererManagers.values()){let n=s.getRenderer();n&&(i(n),r++)}r===0?console.warn("[BaseClientRuntime] Cannot update palette: no renderer available"):this.log(`\u2713 Palette updated on ${r} renderer(s)`)}onCoreImageFontAllocated(e){let t=this.core.getImageFont(e);if(!t)return;this.log(`Allocating image font ${e} structure: blocks=${t.getAtlasBlocks()}, size=${t.getGlyphWidth()}x${t.getGlyphHeight()}`);let i=R(r=>{r&&typeof r.setImageFontStructure=="function"&&r.setImageFontStructure(t.getGlyphWidth(),t.getGlyphHeight(),t.getCellWidth(),t.getCellHeight(),t.getAtlasBlocks())},"applyStruct");for(let r of this.rendererManagers.values()){let s=r.getRenderer();s&&i(s)}}onCoreImageFontBlockAdded(e,t){let i=this.core.getImageFont(e);if(!i)return;let r=i.getBlock(t);if(!r)return;let s=R(n=>{n&&typeof n.setImageFontBlock=="function"&&n.setImageFontBlock(t,r)},"applyBlock");for(let n of this.rendererManagers.values()){let o=n.getRenderer();o&&s(o)}}onCoreImageFontChanged(e){this.log(`Image font ${e} changed (legacy event), updating renderer`),this.onCoreImageFontAllocated(e);let t=this.core.getImageFont(e);if(!t)return;let i=t.getAtlasBlocks();for(let r=0;r<i;r++)t.getBlock(r)&&this.onCoreImageFontBlockAdded(e,r);for(let[r,s]of this.rendererManagers.entries()){let n=s.getRenderer();n&&this.onFontChanged(n,r)}}onFontChanged(e,t){}log(e){this.options.debug&&console.warn(`[BaseClientRuntime] ${e}`)}getCore(){return this.core}getRendererManager(e=this.primaryDisplayId){let t=this.rendererManagers.get(e);if(!t)throw new Error(`Renderer manager for display ${e} not found`);return t}setDisplayContainers(e){this.displayConfigs=new Map(e.map(i=>[i.id,{container:i.container}]));let t=Array.from(this.displayConfigs.keys());this.primaryDisplayId=t.length>0?Math.min(...t):0;for(let i of this.rendererManagers.values())i.destroy();this.rendererManagers.clear(),this.createRendererManagers()}getUserId(){return this.userId}};R(N,"BaseClientRuntime");var B=N;var w=require("@utsp/core"),G=require("@utsp/render"),O=require("@utsp/types"),M=require("@utsp/input"),$=require("@utsp/network-client"),ce=require("@utsp/audio");var de=require("@utsp/core"),x=require("@utsp/input");var F=1e3,X=class X{constructor(e,t,i,r,s,n,o){l(this,"network");l(this,"core");l(this,"rendererManagers");l(this,"primaryDisplayId");l(this,"performanceMonitor");l(this,"options");l(this,"layerTraffic",new Map);l(this,"miscTraffic",new Map);l(this,"displayTraffic",new Map);l(this,"audioManager",null);l(this,"postProcessCallback",null);l(this,"soundHandlersSetup",!1);l(this,"userId","");l(this,"lastReceivedTick",-1);l(this,"connected",!1);l(this,"totalBytesReceived",0);l(this,"lastSentViewports",new Map);l(this,"lastCollectedTouches",[]);l(this,"touchZonesCallback",null);l(this,"audioLoadingState",{totalExpected:0,loadedSounds:new Set,errors:new Map});l(this,"ensureRendererManager");this.network=e,this.core=t,this.rendererManagers=i,this.primaryDisplayId=n,this.performanceMonitor=r,this.ensureRendererManager=o,this.options={serverUrl:s.serverUrl,username:s.username,token:s.token??"",debug:s.debug??!1,autoReconnect:s.autoReconnect??!0,canvasWidth:s.canvasWidth,canvasHeight:s.canvasHeight}}getRendererManager(e){return this.rendererManagers.get(e)}getPrimaryRendererManager(){return this.rendererManagers.get(this.primaryDisplayId)??Array.from(this.rendererManagers.values())[0]}renderDisplays(){let e=this.core.getRenderState(this.userId);if(!e||e.displays.length===0){this.options.debug&&this.log("Render skipped: no render state or displays");return}for(let t of e.displays){let i=this.getRendererManager(t.id)??this.ensureRendererManager?.(t.id);if(!i){console.warn(`[NetworkSync] No renderer manager for display ${t.id}, skipping render`);continue}let r=i.getLayerFilter?.(),s=r?this.core.getRenderState(this.userId,r):e;if(!s){this.options.debug&&this.log(`Render state unavailable for display ${t.id} with filter`);continue}let n=s.displays.find(o=>o.id===t.id);if(!n){this.options.debug&&this.log(`Render state missing display ${t.id} after filtering`);continue}if(!i.isReady()){this.options.debug&&this.log(`Renderer for display ${t.id} not ready yet`);continue}i.renderDisplay(n)}}async connect(){this.log(`Connecting to ${this.options.serverUrl}`),await this.network.connect(),this.connected=!0,this.log("Connected to server"),this.setupNetworkHandlers()}async joinGame(e){return new Promise((t,i)=>{this.network.send("join",{username:this.options.username,token:this.options.token}),this.network.on("join_response",r=>{if(r.success){this.userId=r.userId,this.log(`Joined game as ${this.userId}`);let s=this.core.createUser(this.userId,this.options.username);s.setBytesTickRate(20),this.audioManager&&s.setAudioProcessor(this.audioManager),e?.initUser&&e.initUser(this.core,s,{username:this.options.username,token:this.options.token}),t(this.userId)}else i(new Error(r.error||"Failed to join game"))}),setTimeout(()=>i(new Error("Join timeout")),5e3)})}sendInput(e){let t=this.core.getUser(this.userId);if(!t)return;let i=this.getPrimaryRendererManager(),r=i?.getCanvas();if(r){let g=t.getDisplays(),ie=(g.find(k=>k.getId&&k.getId()===this.primaryDisplayId)??g[0])?.getSize()??{x:this.options.canvasWidth,y:this.options.canvasHeight},re=ie.x,ne=ie.y,se=i?.getRenderer()?.getOffsets?.(),oe={offsetX:se?.offsetX??0,offsetY:se?.offsetY??0},P=x.InputCollector.collectMousePosition(e,r,re,ne,oe);t.setMousePosition(P.x,P.y,P.over),t.updateMacroMouse(P.x,P.y,P.isLeftDown);let ae=x.InputCollector.collectTouchPositions(e,r,re,ne,10,oe);ae.forEach(k=>{t.setTouchPosition(k.id,k.x,k.y,k.over)}),this.lastCollectedTouches=ae}else this.lastCollectedTouches=[];let s=t.getInputBindingRegistry(),n=s.getAllAxes(),o=s.getAllButtons(),a=x.InputCollector.collectAxisSources(n,e),c=x.InputCollector.collectButtonSources(o,e),d=x.InputCollector.collectTextInputs(e);d.length>0&&t.setTextInputs(d);let u=n.sort((g,I)=>g.bindingId-I.bindingId),h=new Map;for(let g of u){let I=s.evaluateAxis(g.bindingId,a);h.set(g.bindingId,I),t.setAxis(g.name,I)}let m=o.sort((g,I)=>g.bindingId-I.bindingId),C=new Map;for(let g of m){let I=s.evaluateButton(g.bindingId,c);C.set(g.bindingId,I),t.setButton(g.name,I)}let f=t.getMouseDisplayInfo(),S=t.getIsMouseOnADisplay(),b=this.collectChangedViewports(),p=this.lastCollectedTouches.map(g=>({id:g.id,x:g.x,y:g.y,over:g.over})),y=(0,de.encodeCompressedInput)(0n,h,C,f?.displayId??0,f?.localX??0,f?.localY??0,S,d,[],b,p);this.network.send("input",y)}collectChangedViewports(){let e=[];for(let[t,i]of this.rendererManagers.entries()){let{width:r,height:s}=i.getAvailableSize();if(r===0||s===0)continue;let n=this.lastSentViewports.get(t);(!n||n.pixelWidth!==r||n.pixelHeight!==s)&&(e.push({displayId:t,pixelWidth:r,pixelHeight:s}),this.lastSentViewports.set(t,{pixelWidth:r,pixelHeight:s}),this.log(`Viewport changed: display ${t} = ${r}x${s}px`))}return e}disconnect(){this.connected&&(this.network.send("leave",{}),this.network.disconnect(),this.connected=!1,this.soundHandlersSetup=!1,this.log("Disconnected from server"))}getUserId(){return this.userId}isConnected(){return this.connected}getTotalBytesReceived(){return this.totalBytesReceived}getAudioLoadingState(){let e=this.audioLoadingState.loadedSounds.size,t=this.audioLoadingState.totalExpected,i=this.audioLoadingState.errors.size,r=t>0&&e>=t,s=Array.from(this.audioLoadingState.errors.keys());return{loadedCount:e,totalExpected:t,errorCount:i,isComplete:r,errors:s}}destroy(){this.disconnect(),this.network.destroy(),this.log("NetworkSync destroyed")}setupNetworkHandlers(){this.network.on("update",e=>{try{let t=this.convertToUint8Array(e,"update");if(!t)return;this.recordBytesReceived(t.length);let i=this.core.applyUpdatePacketBuffer(this.userId,t);i?(this.postProcessCallback&&i.postProcessOrders&&i.postProcessOrders.length>0&&this.postProcessCallback(i.postProcessOrders),this.renderDisplays()):this.log("Failed to apply update packet")}catch(t){this.log(`Error applying update packet: ${t}`)}}),this.network.on("update-static",e=>{this.handleUpdatePacket(e,"update-static")}),this.network.on("update-dynamic",e=>{this.handleUpdatePacket(e,"update-dynamic")}),this.network.on("load",e=>{try{let t=this.convertToUint8Array(e,"load");if(!t)return;this.recordBytesReceived(t.length),this.core.applyLoadPacket(t)?this.log("Load packet applied successfully"):this.log("Failed to apply load packet")}catch(t){this.log(`Error applying load packet: ${t}`)}}),this.network.on("input-bindings",e=>{if(this.recordBytesReceived(e.length),this.core.applyInputBindingsLoadPacket(this.userId,e)){this.log("Input bindings configured");try{let i=JSON.parse(e);if(this.log(`Touch zones in packet: ${i.touchZones?.length??0}, callback defined: ${!!this.touchZonesCallback}`),i.touchZones&&i.touchZones.length>0&&this.touchZonesCallback){let r=i.touchZones.map(s=>({id:s.zoneId,x:s.x,y:s.y,width:s.width,height:s.height}));this.touchZonesCallback(r),this.log(`Touch zones configured: ${r.length} zones`)}}catch{}}else this.log("Failed to apply input bindings")}),this.audioManager&&this.setupSoundHandlers(),this.network.on("disconnect",()=>{this.connected=!1,this.soundHandlersSetup=!1,this.log("Disconnected from server")})}handleUpdatePacket(e,t){try{let i=this.convertToUint8Array(e,t);if(!i)return;this.recordBytesReceived(i.length);let r=new DataView(i.buffer,i.byteOffset,i.byteLength),s=Number(r.getBigUint64(0,!1));if(t==="update-dynamic"&&s<this.lastReceivedTick)return;s>this.lastReceivedTick&&(this.lastReceivedTick=s);let n=this.core.applyUpdatePacketBuffer(this.userId,i);if(n){let o=performance.now(),a=R((b,p)=>{if(p<=0)return;let y=this.miscTraffic.get(b)??{total:0,windowSum:0,samples:[]};y.total+=p,y.windowSum+=p,y.samples.push({time:o,bytes:p}),this.miscTraffic.set(b,y)},"recordMisc"),c=R(b=>{try{return JSON.stringify(b).length}catch{return 0}},"safeLen"),d=n.__byteSizes,u=d?.audioOrders;typeof u=="number"?a("update.audioOrders",u):n.audioOrders&&n.audioOrders.length&&a("update.audioOrders",c(n.audioOrders));let h=d?.vibrationOrders;typeof h=="number"?a("update.vibrationOrders",h):n.vibrationOrders&&n.vibrationOrders.length&&a("update.vibrationOrders",c(n.vibrationOrders));let m=d?.macroOrders;typeof m=="number"?a("update.macroOrders",m):n.macroOrders&&n.macroOrders.length&&a("update.macroOrders",c(n.macroOrders));let C=d?.postProcessOrders;if(typeof C=="number"?a("update.postProcessOrders",C):n.postProcessOrders&&n.postProcessOrders.length&&a("update.postProcessOrders",c(n.postProcessOrders)),n.displays&&n.displays.length)for(let b of n.displays){let p=b.id;if(typeof p!="number")continue;let y=this.displayTraffic.get(p)??{total:0,windowSum:0,samples:[]},g=7;y.total+=g,y.windowSum+=g,y.samples.push({time:o,bytes:g}),this.displayTraffic.set(p,y)}for(let b of n.layers){let p=b.byteSize??0,y=this.layerTraffic.get(b.id)??{total:0,windowSum:0,samples:[]};y.total+=p,y.windowSum+=p,y.samples.push({time:o,bytes:p});let g=o-F;for(;y.samples.length&&y.samples[0].time<g;){let I=y.samples.shift();I&&(y.windowSum-=I.bytes)}this.layerTraffic.set(b.id,y)}{let b=o-F;this.miscTraffic.forEach((p,y)=>{for(;p.samples.length&&p.samples[0].time<b;){let g=p.samples.shift();g&&(p.windowSum-=g.bytes)}p.windowSum<0&&(p.windowSum=0),this.miscTraffic.set(y,p)})}{let b=o-F;this.displayTraffic.forEach((p,y)=>{for(;p.samples.length&&p.samples[0].time<b;){let g=p.samples.shift();g&&(p.windowSum-=g.bytes)}p.windowSum<0&&(p.windowSum=0),this.displayTraffic.set(y,p)})}this.postProcessCallback&&n.postProcessOrders&&n.postProcessOrders.length>0&&this.postProcessCallback(n.postProcessOrders),this.options.debug&&this.debugRenderState();let f=performance.now();this.renderDisplays();let S=performance.now()-f;this.performanceMonitor.recordFrameTiming(0,S),this.options.debug&&console.warn(`[CLIENT] render() completed for ${t} (${S.toFixed(2)}ms)`)}else this.options.debug&&this.log(`Failed to apply ${t} packet (tick ${s})`)}catch(i){this.log(`Error applying ${t} update packet: ${i}`),console.error(i)}}convertToUint8Array(e,t){return e instanceof Uint8Array?e:e instanceof ArrayBuffer?new Uint8Array(e):Array.isArray(e)?new Uint8Array(e):e.data&&Array.isArray(e.data)?new Uint8Array(e.data):typeof e=="object"&&e.type==="Buffer"?new Uint8Array(e.data):(this.log(`Unknown data type for ${t} packet: ${typeof e}`),null)}debugRenderState(){let e=this.core.getUser(this.userId);if(e){let r=e.getLayers();console.warn(`[CLIENT] User has ${r.length} layers`),r.forEach((s,n)=>{let o=s.getOrders(),a=s.getMustBeReliable();(o.length>0||a)&&console.warn(` Layer ${n}: ${o.length} orders, reliable=${a}, z=${s.getZOrder()}`)})}let i=this.getPrimaryRendererManager()?.isReady()??!1;console.warn(`[CLIENT] Renderer ready: ${i}`)}log(e){this.options.debug&&console.warn(`[NetworkSync] ${e}`)}recordBytesReceived(e){this.totalBytesReceived+=e;let t=this.core.getUser(this.userId);t&&t.recordBytesReceived(e)}getLayerTrafficStats(){let e={},i=performance.now()-F;return this.layerTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),e[s]={total:r.total,bytesPerSec1s:r.windowSum/(F/1e3)}}),e}getMiscTrafficStats(){let e={},i=performance.now()-F;return this.miscTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),e[s]={total:r.total,bytesPerSec1s:r.windowSum/(F/1e3)}}),e}getDisplayTrafficStats(){let e={},i=performance.now()-F;return this.displayTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),e[s]={total:r.total,bytesPerSec1s:r.windowSum/(F/1e3)}}),e}getSoundPacketSize(e){return e.mode==="file"?e.sounds.reduce((i,r)=>i+this.getSoundDataLength(r.data)+r.name.length+10,0):e.sounds.reduce((i,r)=>i+r.url.length+r.name.length+10,0)}getSoundDataLength(e){if(e instanceof Uint8Array)return e.length;if(e instanceof ArrayBuffer||ArrayBuffer.isView(e))return e.byteLength;let t=globalThis.Buffer;return t&&e instanceof t?e.length:e&&typeof e=="object"&&Array.isArray(e.data)?e.data.length:Array.isArray(e)?e.length:0}setAudioManager(e){if(this.audioManager=e,e&&this.userId){let t=this.core.getUser(this.userId);t&&t.setAudioProcessor(e)}this.connected&&e&&this.setupSoundHandlers()}setPostProcessCallback(e){this.postProcessCallback=e}setTouchZonesCallback(e){this.touchZonesCallback=e}setupSoundHandlers(){if(this.audioManager){if(this.soundHandlersSetup){this.log("Sound handlers already registered, skipping");return}this.soundHandlersSetup=!0,this.network.on("sound-load",async e=>{this.recordBytesReceived(this.getSoundPacketSize(e)),e.totalSounds!==void 0&&e.totalSounds>this.audioLoadingState.totalExpected&&(this.audioLoadingState.totalExpected=e.totalSounds,this.log(`Audio loading: expecting ${e.totalSounds} total sounds`)),e.mode==="file"?await this.handleSoundLoad(e):e.mode==="external"&&await this.handleSoundExternalLoad(e)}),this.log("Sound handlers registered")}}async handleSoundLoad(e){if(!this.audioManager){this.log("Cannot load sounds: AudioManager not initialized");return}let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load sounds: SoundBank not initialized");return}for(let i of e.sounds)try{let r=this.normalizeSoundData(i.data);await t.loadFromData(i.soundId,i.name,r),this.log(`Loaded sound: ${i.name} (${r.length} bytes)`),this.audioLoadingState.loadedSounds.add(i.name),this.audioLoadingState.errors.delete(i.name),this.sendAudioAck({type:"sound-loaded",soundId:i.soundId,name:i.name})}catch(r){console.error(`[NetworkSync] Failed to load sound "${i.name}":`,r),this.audioLoadingState.errors.set(i.name,String(r)),this.sendAudioAck({type:"sound-error",soundId:i.soundId,name:i.name,error:String(r)})}}normalizeSoundData(e){if(e instanceof Uint8Array)return e;if(e instanceof ArrayBuffer)return new Uint8Array(e);if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength));let t=globalThis.Buffer;if(t&&e instanceof t)return new Uint8Array(e);if(e&&typeof e=="object"&&Array.isArray(e.data))return new Uint8Array(e.data);if(Array.isArray(e))return new Uint8Array(e);if(typeof e=="string")try{let i=atob(e),r=i.length,s=new Uint8Array(r);for(let n=0;n<r;n++)s[n]=i.charCodeAt(n);return s}catch{}throw new Error("Invalid sound data payload")}async handleSoundExternalLoad(e){if(!this.audioManager){this.log("Cannot load external sounds: AudioManager not initialized");return}let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load external sounds: SoundBank not initialized");return}for(let i of e.sounds)try{await t.loadFromUrl(i.soundId,i.name,i.url),this.log(`Loaded external sound: ${i.name} from ${i.url}`),this.audioLoadingState.loadedSounds.add(i.name),this.audioLoadingState.errors.delete(i.name),this.sendAudioAck({type:"sound-loaded",soundId:i.soundId,name:i.name})}catch(r){console.error(`[NetworkSync] Failed to load external sound "${i.name}":`,r),this.audioLoadingState.errors.set(i.name,String(r)),this.sendAudioAck({type:"sound-error",soundId:i.soundId,name:i.name,error:String(r)})}}sendAudioAck(e){this.network.send("audio-ack",e),this.log(`Sent audio-ack: ${e.type}`)}sendBridge(e,t){this.network.sendBridge?.(e,t),this.log(`Bridge sent on channel '${e}'`)}onBridge(e,t){this.network.onBridge?.(e,t),this.log(`Bridge handler registered for channel '${e}'`)}offBridge(e,t){this.network.offBridge?.(e,t),this.log(`Bridge handler removed for channel '${e}'`)}removeAllBridgeHandlers(e){this.network.removeAllBridgeHandlers?.(e),this.log(e?`All bridge handlers removed for '${e}'`:"All bridge handlers removed")}};R(X,"NetworkSync");var q=X;var Z=class Z extends B{constructor(t){let i=t.mode;if(i!=="standalone"&&i!=="socketio"&&i!=="webrtc")throw new Error(`Invalid ClientRuntime mode: "${i}". Expected 'standalone', 'socketio', or 'webrtc'.`);let r;if(t.mode==="standalone"&&(r=t.standalone.application),!r&&t.mode==="standalone")throw new Error("Application instance required for standalone mode");super({application:r,container:t.container,displayContainers:t.displayContainers,debug:t.debug,width:t.width,height:t.height,renderer:t.renderer,useImageDataRendering:t.useImageDataRendering,renderMode:t.renderMode});l(this,"input",null);l(this,"networkSync",null);l(this,"mode");l(this,"localOptions",null);l(this,"autoplayOverlay",null);l(this,"autoplay",!0);l(this,"audioManager",null);l(this,"mobileVibration",null);l(this,"postProcessOverlay",null);l(this,"postProcessOverlays",new Map);l(this,"postProcessOrderCollector",new w.PostProcessOrderCollector);l(this,"pendingPaletteSlotByDisplay",new Map);l(this,"localBridgeHandlers",new Map);l(this,"localBridgeWildcardHandlers",new Set);this.mode=t.mode,this.autoplay=t.autoplay??!0,t.mode==="standalone"?(this.localOptions=t,this.userId=t.standalone.userId??"local"):this.localOptions=null,this.mode==="standalone"?(this.log("Initializing in STANDALONE mode"),this.initLocalMode()):(this.log(`Initializing in ${this.mode.toUpperCase()} mode`),this.initConnectedMode(t))}initLocalMode(){let t=this.localOptions;if(!t)return;this.log("Initializing ClientRuntime (standalone mode)"),t.inputEnabled??!0?this.initInput(t):this.log("Input disabled (inputEnabled: false)")}initConnectedMode(t){this.log(`Initializing ClientRuntime (${this.mode} mode)`),this.core=new w.Core({mode:"client",maxUsers:100}),this.core.onPaletteChanged(n=>{this.onCorePaletteChanged(n),this.retryPendingPaletteSelections()}),this.core.onImageFontChanged(n=>{this.onCoreImageFontChanged(n)});let i;if(t.mode==="webrtc"){let n=t.webrtc;i=new $.WebRTCClient({url:n.signalUrl??"",sessionId:n.sessionId,signalingPath:n.signalingPath,iceServers:n.iceServers,autoReconnect:n.autoReconnect,auth:n.auth??{username:n.username},debug:t.debug})}else{let n=t.socketio;if(!n)throw new Error(`SocketIO configuration missing. Mode is '${t.mode}' but 'socketio' options are undefined.`);i=new $.SocketIOClient({url:n.url??"",path:n.path,autoReconnect:n.autoReconnect,auth:n.auth??{username:n.username},debug:t.debug})}let r=t.mode==="socketio"?t.socketio:t.webrtc;this.networkSync=new q(i,this.core,this.rendererManagers,this.performanceMonitor,{serverUrl:t.mode==="socketio"?t.socketio.url:t.webrtc.signalUrl||"WebRTC",username:r.username??"User",debug:t.debug,autoReconnect:r.autoReconnect,canvasWidth:t.width??80,canvasHeight:t.height??25},this.primaryDisplayId,n=>this.ensureRendererManager(n)),(t.inputEnabled??!0)&&(this.input||this.initInput(t))}initInput(t){this.input=new M.UnifiedInputRouter({enableKeyboardMouse:!0,enableGamepad:!0,enableMobile:!0,targetElement:window,mobileTargetElement:t.touchZones?.targetElement??void 0,debug:t.debug,keyboardConfig:{preventDefault:t.captureInput??!1,stopPropagation:t.captureInput??!1},mouseConfig:{preventDefault:t.captureInput??!1,stopPropagation:t.captureInput??!1},mobileConfig:{preventDefault:t.mobileInputConfig?.preventDefault??!1,passive:t.mobileInputConfig?.passive??!0,maxTouches:t.mobileInputConfig?.maxTouches??10},enableTouchZones:t.touchZones?.enable??!1,touchZoneConfig:{targetElement:t.touchZones?.targetElement,gridWidth:t.touchZones?.gridWidth??t.width??0,gridHeight:t.touchZones?.gridHeight??t.height??0,rendererOffsets:t.touchZones?.rendererOffsets,zones:t.touchZones?.zones}})}rebuildPostProcessOverlays(){for(let t of this.postProcessOverlays.values())t.destroy();this.postProcessOverlays.clear(),this.postProcessOverlay=null;for(let[t,i]of this.displayConfigs.entries()){let r=new G.PostProcessOverlay(i.container);this.postProcessOverlays.set(t,r),t===this.primaryDisplayId&&(this.postProcessOverlay=r)}!this.postProcessOverlay&&this.postProcessOverlays.size>0&&(this.postProcessOverlay=Array.from(this.postProcessOverlays.values())[0]??null)}getMode(){return this.mode}setTickRate(t){if(this.mode!=="standalone"){this.log("setTickRate() has no effect in connected mode");return}super.setTickRate(t)}async onBeforeStart(){this.audioManager=new ce.AudioManager({debug:this.options.debug}),this.mobileVibration=new M.MobileVibration({debug:this.options.debug}),this.autoplay?(this.log("Autoplay enabled, initializing AudioManager..."),this.audioManager.initialize()):(this.log("Autoplay disabled, showing overlay..."),await new Promise(t=>{this.autoplayOverlay=new G.AutoplayOverlay(this.options.container,{...this.localOptions?.autoplayOptions,onStart:()=>{this.log("User clicked start button"),this.audioManager&&(this.audioManager.initialize(),this.audioManager.playStartSound()),this.mobileVibration&&this.mobileVibration.vibrate(50),this.autoplayOverlay&&(this.autoplayOverlay.destroy(),this.autoplayOverlay=null),t()}})}),this.log("Autoplay overlay dismissed, continuing startup..."))}async start(){if(this.running){this.log("Already running");return}this.log("Starting ClientRuntime"),await this.onBeforeStart();for(let[r,s]of this.rendererManagers.entries())await s.initialize(this.core),this.log(`Renderer for display ${r} is ready`);this.rebuildPostProcessOverlays(),this.log("PostProcessOverlays created"),this.onCorePaletteChanged(this.core.getPalette()),this.log("Initial palette sent to renderer"),this.options.application&&(this.log("Calling application.init()"),await this.options.application.init(this.core,this));let t=this.rendererManager.getCanvas();if(t&&this.input&&this.input.setMobileTarget(t),this.mode!=="standalone"&&this.networkSync){if(this.audioManager&&this.networkSync.setAudioManager(this.audioManager),this.networkSync.setPostProcessCallback(s=>{this.applyPostProcessOrders(s)}),this.input){let s=this.input,n=this.rendererManager;this.networkSync.setTouchZonesCallback(o=>{this.log(`[start] Touch zones callback called with ${o.length} zones`);let a=n.getCanvas();if(this.log(`[start] Canvas available: ${!!a}`),a){let c=o.reduce((h,m)=>Math.max(h,m.x+m.width),0),d=o.reduce((h,m)=>Math.max(h,m.y+m.height),0);this.log(`[start] Grid from zones: ${c}x${d}`);let u=s.enableTouchZonesDevice(a,c,d,o);this.log(`[start] enableTouchZonesDevice returned: ${u}`),u&&this.log(`Touch zones configured from server: ${o.length} zones`)}})}await this.networkSync.connect(),this.userId=await this.networkSync.joinGame(this.options.application);let r=this.core.getUser(this.userId);r&&this.configureUserProcessors(r)}else await this.createLocalUser();let i=this.core.getUser(this.userId);if(i){let r=i.getDisplays();if(r.length>0){let n=r[0].getSize(),o=n.x,a=n.y,c=this.rendererManager.getRenderer(),d,u;if(this.rendererType==="webgl"){let m=c.getGridSize();d=m.cols,u=m.rows}else{let h=c;d=h.getCols(),u=h.getRows()}(d!==o||u!==a)&&(this.log(`Adjusting renderer from ${d}\xD7${u} to match display ${o}\xD7${a}`),c.resize(o,a))}}this.input&&this.input.start(),this.running=!0,this.startTime=performance.now(),this.lastTimestamp=this.startTime,this.lastRenderTimestamp=this.startTime,this.accumulatedTime=0,this.firstTickDone=!1,this.performanceMonitor.reset(),this.performanceMonitor.startTracking(this.startTime),this.log("Starting main loop"),this.mainLoop(this.lastTimestamp)}async onStop(){this.audioManager&&this.audioManager.stopAll(),this.input&&this.input.stop(),this.mode!=="standalone"&&this.networkSync&&this.networkSync.disconnect()}getStats(){let t=super.getStats(),r=this.core.getUser(this.userId)?.getTotalBytesReceived();return{...t,mode:this.mode,latency:void 0,totalBytesReceived:r}}getAudioLoadingState(){if(this.mode!=="standalone"&&this.networkSync)return this.networkSync.getAudioLoadingState();if(this.audioManager){let t=this.audioManager.getSoundBank();if(t){let i=t.getStats();return{loadedCount:i.totalSounds,totalExpected:i.totalSounds,errorCount:0,isComplete:!0,errors:[]}}}return{loadedCount:0,totalExpected:0,errorCount:0,isComplete:!0,errors:[]}}async onDestroy(){this.autoplayOverlay&&(this.autoplayOverlay.destroy(),this.autoplayOverlay=null),this.audioManager&&(this.audioManager.destroy(),this.audioManager=null),this.postProcessOverlay&&(this.postProcessOverlay.destroy(),this.postProcessOverlay=null);for(let t of this.postProcessOverlays.values())t.destroy();this.postProcessOverlays.clear(),this.input&&this.input.destroy(),this.networkSync&&this.networkSync.destroy()}configureUserProcessors(t){if(this.audioManager&&t.setAudioProcessor(this.audioManager),this.mobileVibration&&t.setMobileVibrationProcessor(this.mobileVibration),this.input){let i=this.input.getGamepad();i&&t.setGamepadVibrationProcessor(i)}}async createLocalUser(){let t=this.localOptions;this.userId=t?.standalone.userId??"local",this.log(`Creating local user: ${this.userId}`);let i=this.core.createUser(this.userId,t?.standalone.username??"User");if(i.setBytesTickRate(this.tickRate>0?this.tickRate:20),this.configureUserProcessors(i),this.options.application?.initUser&&(this.log("Calling application.initUser()"),this.options.application.initUser(this.core,i,{username:t?.standalone.username??"User"})),i.hasAudioConfigCommands()&&(this.log("Applying audio config commands from initUser()"),i.applyAudioConfigCommands(i.flushAudioConfigCommands())),i.hasPendingMacroOrders()){this.log("Applying macro orders from initUser()");let a=i.flushMacroOrders();i.applyMacroOrders(a)}if(i.hasPostProcessCommands()){this.log("Applying post-process commands from initUser()");let a=i.flushPostProcessCommands(),c=this.postProcessOrderCollector.convertCommands(a);this.applyPostProcessOrders(c)}i.needsSendSounds()&&(await this.loadSoundsFromRegistry(),i.clearSendSounds());let r=this.core.generateAllLoadPackets();r.forEach(a=>{i.recordBytesReceived(a.length)});let s=this.core.generateMacroLoadPackets(this.userId);s.forEach(a=>{i.recordBytesReceived(a.length)});let n=i.getInputBindingsLoadPacket();if(n&&(i.recordBytesReceived(n.length),this.input)){let c=i.getInputBindingRegistry().getAllTouchZones();if(c.length>0){let d=this.rendererManager.getCanvas();if(d){let u=i.getDisplays(),h=u.length>0?u[0].getSize():{x:this.options.width??80,y:this.options.height??25},m=c.map(f=>({id:f.zoneId,x:f.x,y:f.y,width:f.width,height:f.height}));this.input.enableTouchZonesDevice(d,h.x,h.y,m)?this.log(`Touch zones synchronized from registry: ${c.length} zones`):this.log("Failed to enable touch zones - mobile input may not be initialized")}}}this.log(`Simulated ${r.length} load packets, ${s.length} macro packets for byte counting`),this.log("Performing initial render"),this.core.endTick().forEach(({static:a,dynamic:c},d)=>{let u=this.core.getUser(d);u&&(a&&u.recordBytesReceived(a.length),c&&u.recordBytesReceived(c.length))}),this.render(),this.log("Initial render complete")}async loadSoundsFromRegistry(){if(!this.audioManager){this.log("Cannot load sounds: AudioManager not initialized");return}let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load sounds: SoundBank not initialized");return}let r=this.core.getSoundRegistry().getAll();if(r.length===0){this.log("No sounds to load from registry");return}this.log(`Loading ${r.length} sounds from Core registry into AudioManager...`);let s=this.core.getUser(this.userId),n=0;for(let o of r)try{if(o.loadType==="file"&&o.data){await t.loadFromData(o.soundId,o.name,o.data);let a=o.data.length+o.name.length+10;n+=a,this.log(`\u{1F50A} Loaded sound: ${o.name} (${o.data.length} bytes)`)}else if(o.loadType==="external"&&o.url){await t.loadFromUrl(o.soundId,o.name,o.url);let a=o.url.length+o.name.length+10;n+=a,this.log(`\u{1F50A} Loaded external sound: ${o.name} from ${o.url}`)}}catch(a){console.error(`[ClientRuntime] Failed to load sound "${o.name}":`,a)}s&&n>0&&(s.recordBytesReceived(n),this.log(`Simulated ${n} bytes for ${r.length} sound(s)`)),this.log(`\u2713 ${t.size} sounds loaded into AudioManager`)}mainLoop(t){if(!this.running){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0);return}if(this.renderMode==="on-demand"){this.renderRequested&&(this.renderRequested=!1,this.performanceMonitor.updateFPS(t),this.render()),this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}let i=t-this.lastRenderTimestamp;if(this.lastRenderTimestamp>0&&i<this.FRAME_TIME_MIN-1){this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}this.lastRenderTimestamp=t;let r=(t-this.lastTimestamp)/1e3,s=Math.min(r,.1);this.lastTimestamp=t,this.performanceMonitor.updateFPS(t);let n=this.core.getUser(this.userId);if(!n){this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}if(this.mode==="standalone"){if(this.tickRate===0){let d=performance.now();this.render();let u=performance.now()-d;this.performanceMonitor.recordFrameTiming(0,u),this.rafId=requestAnimationFrame(h=>this.mainLoop(h));return}if(!this.firstTickDone){this.firstTickDone=!0,this.lastTimestamp=t,this.accumulatedTime=0,this.rafId=requestAnimationFrame(d=>this.mainLoop(d));return}this.accumulatedTime+=s;let o=1/this.tickRate;this.accumulatedTime>.5&&(this.accumulatedTime=o);let a=0,c=0;for(;this.accumulatedTime>=o&&a<5;){let d=performance.now();if(this.collectAndApplyInput(n),this.options.application&&(this.options.application.update?.(this.core,o),this.options.application.updateUser?.(this.core,n,o)),n.clearTextInputs(),n.hasAudioConfigCommands()&&n.applyAudioConfigCommands(n.flushAudioConfigCommands()),n.hasSoundCommands()&&n.applyAudioCommands(n.flushSoundCommands()),n.hasMobileVibrationCommands()&&n.applyMobileVibrationCommands(n.flushMobileVibrationCommands()),n.hasGamepadVibrationCommands()&&n.applyGamepadVibrationCommands(n.flushGamepadVibrationCommands()),n.hasPostProcessCommands()){let m=n.flushPostProcessCommands(),C=this.postProcessOrderCollector.convertCommands(m);this.applyPostProcessOrders(C)}if(n.hasPendingMacroOrders()){let m=n.flushMacroOrders();n.applyMacroOrders(m)}let u=n.updateMacros();if(n.processMacroEvents(u),n.hasBridgeMessages()){let m=n.getBridgeMessages();this.dispatchLocalBridgeMessages(m)}this.core.endTick().forEach(({static:m,dynamic:C})=>{let f=(m?.length??0)+(C?.length??0);n.recordBytesReceived(f)}),c+=performance.now()-d,this.accumulatedTime-=o,a++}if(a>0){let d=performance.now();this.render();let u=performance.now()-d;this.performanceMonitor.recordFrameTiming(c,u)}}else{let o=n.updateMacros();n.processMacroEvents(o),this.collectAndSendInput()}this.rafId=requestAnimationFrame(o=>this.mainLoop(o))}collectAndApplyInput(t){if(!this.input)return;let i=this.rendererManager.getCanvas();if(i){let a=t.getDisplays(),d=(a.find(g=>g.getId&&g.getId()===this.primaryDisplayId)??a[0])?.getSize()??{x:this.options.width,y:this.options.height},u=d.x,h=d.y,C=this.rendererManager.getRenderer()?.getOffsets?.(),f={offsetX:C?.offsetX??0,offsetY:C?.offsetY??0};this.input.updateTouchZoneLayout(u,h,f);let S=M.InputCollector.collectMousePosition(this.input,i,u,h,f);t.setMousePosition(S.x,S.y,S.over),t.updateMacroMouse(S.x,S.y,S.isLeftDown),M.InputCollector.collectTouchPositions(this.input,i,u,h,10,f).forEach(g=>{t.setTouchPosition(g.id,g.x,g.y,g.over)});let y=this.rendererManagers.get(this.primaryDisplayId)?.getAvailableSize();y&&t.setDisplayViewport(this.primaryDisplayId,y.width,y.height)}let r=M.InputCollector.collectTextInputs(this.input);r.length>0&&t.setTextInputs(r);let s=t.getInputBindingRegistry(),n=s.getAllAxes(),o=s.getAllButtons();if(n.length>0||o.length>0){let a=M.InputCollector.collectAxisSources(n,this.input),c=M.InputCollector.collectButtonSourcesWithTransitions(o,this.input);n.forEach(d=>{let u=s.evaluateAxis(d.bindingId,a);t.setAxis(d.name,u)}),o.forEach(d=>{let u=new Map,h=new Map,m=new Map;for(let[b,p]of c)u.set(b,p.pressed),h.set(b,p.justPressed),m.set(b,p.justReleased);let C=s.evaluateButton(d.bindingId,u),f=s.evaluateButton(d.bindingId,h),S=s.evaluateButton(d.bindingId,m);t.setButton(d.name,C),t.setButton(`${d.name}_justPressed`,f),t.setButton(`${d.name}_justReleased`,S)})}this.input.poll?.()}collectAndSendInput(){!this.networkSync||!this.input||this.networkSync.sendInput(this.input)}render(){let t=this.core.getUser(this.userId);if(t){let i=t.getDisplays();for(let r of i){let s=r.getId(),n=this.rendererManagers.get(s);if(!n){console.warn(`[ClientRuntime] No renderer for display ${s}, skipping resize`);continue}let o=n.getRenderer();if(!o)continue;let a=r.getSize(),c,d,u,h,m=null;if("getGridSize"in o){let f=o,S=f.getGridSize();c=S.cols,d=S.rows,u=f.getCellWidth(),h=f.getCellHeight(),m=f.getScalingMode()}else if("getCols"in o){let f=o;c=f.getCols(),d=f.getRows(),u=f.getCellWidth(),h=f.getCellHeight(),m=f.getScalingMode()}else continue;if(m===O.ScalingMode.Responsive){let f=n.getAvailableSize(),S=256*256;"getMaxCells"in o&&(S=Math.min(S,o.getMaxCells()));let b=Math.floor(f.width/u),p=Math.floor(f.height/h);if(b=Math.min(256,Math.max(1,b)),p=Math.min(256,Math.max(1,p)),b*p>S){let y=Math.sqrt(S/(b*p));b=Math.max(1,Math.floor(b*y)),p=Math.max(1,Math.floor(p*y)),this.log(`\u26A0\uFE0F [Display ${s}] Device limit: max ${S} cells, clamping to ${b}\xD7${p}`)}(a.x!==b||a.y!==p)&&(this.log(`\u{1F4D0} [Display ${s}] Resizing display from ${a.x}\xD7${a.y} to ${b}\xD7${p} (available: ${f.width}\xD7${f.height}px, cell: ${u}\xD7${h}px)`),r.setSize(new O.Vector2(b,p)))}let C=r.getSize();(c!==C.x||d!==C.y)&&(this.log(`\u{1F4D0} [Display ${s}] Resizing renderer from ${c}\xD7${d} to ${C.x}\xD7${C.y}`),o.resize(C.x,C.y))}}super.render()}onFontChanged(t,i){let r=i??this.primaryDisplayId,s=this.postProcessOverlays.get(r)??this.postProcessOverlay;s&&"syncWithRenderer"in s&&"getCellWidth"in t&&"getCellHeight"in t&&"getCurrentScale"in t&&"getGridSize"in t&&(s.syncWithRenderer(t),this.log(`\u2713 PostProcessOverlay synced with renderer dimensions (display ${r})`))}getAudioManager(){return this.audioManager}getLayerTrafficStats(){return this.networkSync?.getLayerTrafficStats()??{}}getMiscTrafficStats(){return this.networkSync?.getMiscTrafficStats?.()??{}}getDisplayTrafficStats(){return this.networkSync?.getDisplayTrafficStats?.()??{}}getAudioContext(){return this.audioManager?.getContext()??null}getPostProcessOverlay(){return this.postProcessOverlay}applyAmbientEffectConfig(t,i){let r=this.rendererManagers.get(t)?.getRenderer();r&&"setAmbientEffect"in r&&(i.enabled?r.setAmbientEffect({blur:i.blur,scale:i.scale}):r.setAmbientEffect(!1),this.log(`[Display ${t}] Ambient effect ${i.enabled?"enabled":"disabled"}`))}applyPostProcessOrders(t){for(let i of t){let r=i.displayId??this.primaryDisplayId,s=this.postProcessOverlays.get(r)??this.postProcessOverlay,n=this.rendererManagers.get(r)?.getRenderer();switch(i.type){case w.PostProcessOrderType.SetConfig:{if(!s){console.warn(`[ClientRuntime] No PostProcessOverlay for display ${r}`);break}let o={};i.scanlines&&(o.scanlines={enabled:i.scanlines.enabled,opacity:i.scanlines.opacity,pattern:this.patternFromType(i.scanlines.pattern),color:{r:i.scanlines.colorR,g:i.scanlines.colorG,b:i.scanlines.colorB}}),i.ambientEffect&&(o.ambientEffect={enabled:i.ambientEffect.enabled,blur:i.ambientEffect.blur,scale:i.ambientEffect.scale}),s.setConfig(Object.keys(o).length>0?o:null),o.ambientEffect&&n&&this.applyAmbientEffectConfig(r,o.ambientEffect),this.log(`[Display ${r}] SetConfig applied`);break}case w.PostProcessOrderType.SetScanlines:{if(!s){console.warn(`[ClientRuntime] No PostProcessOverlay for display ${r}`);break}s.setScanlines({enabled:i.enabled,opacity:i.opacity,pattern:this.patternFromType(i.pattern),color:{r:i.colorR,g:i.colorG,b:i.colorB}}),this.log(`[Display ${r}] Scanlines ${i.enabled?"enabled":"disabled"}`);break}case w.PostProcessOrderType.SetAmbientEffect:{this.applyAmbientEffectConfig(r,{enabled:i.enabled,blur:i.blur,scale:i.scale}),this.log(`[Display ${r}] Ambient effect ${i.enabled?"enabled":"disabled"}`);break}case w.PostProcessOrderType.SetScalingMode:{this.applyScalingMode(r,i.mode);break}case w.PostProcessOrderType.SetGrid:{this.applyGridConfig(r,i);break}case w.PostProcessOrderType.SwitchPalette:{this.applySwitchPalette(r,i);break}case w.PostProcessOrderType.SetCellSize:{this.applyCellSize(r,i.cellWidth,i.cellHeight);break}}}}applyScalingMode(t,i){let r=this.rendererManagers.get(t)?.getRenderer();if(r&&"setScalingMode"in r){let s=(0,O.valueToScalingMode)(i);r.setScalingMode(s),this.log(`[Display ${t}] Scaling mode set to ${s}`)}}applyGridConfig(t,i){let r=this.rendererManagers.get(t)?.getRenderer();if(r&&"setGrid"in r){let s=i.colorA/255;r.setGrid({enabled:i.enabled,color:`rgba(${i.colorR},${i.colorG},${i.colorB},${s})`,lineWidth:i.lineWidth}),this.log(`[Display ${t}] Grid ${i.enabled?"enabled":"disabled"}`)}}applySwitchPalette(t,i){let r=this.core.getPaletteFromSlot(i.slotId);if(!r){this.pendingPaletteSlotByDisplay.set(t,i.slotId),console.warn(`[ClientRuntime] Palette slot ${i.slotId} not found (display ${t}); will retry when available`);return}let s=[];for(let o=0;o<256;o++){let a=r.get(o);a?s.push({r:a.r,g:a.g,b:a.b,a:a.a}):s.push({r:0,g:0,b:0,a:0})}let n=this.rendererManagers.get(t)?.getRenderer();n&&"setPalette"in n&&(n.setPalette(s),this.log(`[Display ${t}] Switched to palette slot ${i.slotId}`)),this.pendingPaletteSlotByDisplay.get(t)===i.slotId&&this.pendingPaletteSlotByDisplay.delete(t)}retryPendingPaletteSelections(){if(this.pendingPaletteSlotByDisplay.size!==0)for(let[t,i]of this.pendingPaletteSlotByDisplay.entries()){let r=this.core.getPaletteFromSlot(i);if(!r)continue;let s=[];for(let o=0;o<256;o++){let a=r.get(o);a?s.push({r:a.r,g:a.g,b:a.b,a:a.a}):s.push({r:0,g:0,b:0,a:0})}let n=this.rendererManagers.get(t)?.getRenderer();n&&"setPalette"in n&&(n.setPalette(s),this.log(`[Display ${t}] Applied pending palette slot ${i}`),this.pendingPaletteSlotByDisplay.delete(t))}}applyCellSize(t,i,r){let s=this.rendererManagers.get(t)?.getRenderer();s&&"setCellSize"in s&&(s.setCellSize(i,r),this.log(`[Display ${t}] Cell size set to ${i}\xD7${r}px`))}patternFromType(t){switch(t){case 0:return"horizontal";case 1:return"vertical";case 2:return"grid";default:return"horizontal"}}dispatchLocalBridgeMessages(t){for(let i of t){let{channel:r,data:s}=i,n=this.localBridgeHandlers.get(r);if(n)for(let o of n)try{o(s)}catch(a){console.error(`[ClientRuntime] Bridge handler error on '${r}':`,a)}for(let o of this.localBridgeWildcardHandlers)try{o(r,s)}catch(a){console.error("[ClientRuntime] Bridge wildcard handler error:",a)}this.log(`Bridge message dispatched on channel '${r}'`)}}sendBridge(t,i){if(this.mode!=="standalone"&&this.networkSync)this.networkSync.sendBridge(t,i);else if(this.mode==="standalone"){let r=this.core.getUser(this.userId);r&&this.options.application?.onBridgeMessage&&(this.options.application.onBridgeMessage(this.core,r,t,i),this.log(`Bridge message sent to application on channel '${t}'`))}}onBridge(t,i){this.mode!=="standalone"&&this.networkSync?this.networkSync.onBridge(t,i):this.mode==="standalone"&&(t==="*"?this.localBridgeWildcardHandlers.add(i):(this.localBridgeHandlers.has(t)||this.localBridgeHandlers.set(t,new Set),this.localBridgeHandlers.get(t).add(i)),this.log(`Bridge handler registered for channel '${t}'`))}offBridge(t,i){this.mode!=="standalone"&&this.networkSync?this.networkSync.offBridge(t,i):this.mode==="standalone"&&(t==="*"?this.localBridgeWildcardHandlers.delete(i):this.localBridgeHandlers.get(t)?.delete(i))}removeAllBridgeHandlers(t){this.mode!=="standalone"&&this.networkSync?this.networkSync.removeAllBridgeHandlers(t):this.mode==="standalone"&&(t===void 0?(this.localBridgeHandlers.clear(),this.localBridgeWildcardHandlers.clear()):t==="*"?this.localBridgeWildcardHandlers.clear():this.localBridgeHandlers.delete(t))}log(t){this.options.debug&&console.warn(`[ClientRuntime/${this.mode}] ${t}`)}};R(Z,"ClientRuntime");var Q=Z;var T=require("@utsp/input");var _=class _{constructor(e={}){l(this,"input");l(this,"mobileVibration");this.input=new T.UnifiedInputRouter({enableKeyboardMouse:!0,enableGamepad:!0,enableMobile:!0,targetElement:window,mobileTargetElement:void 0,debug:e.debug,keyboardConfig:{preventDefault:e.captureInput??!1,stopPropagation:e.captureInput??!1},mouseConfig:{preventDefault:e.captureInput??!1,stopPropagation:e.captureInput??!1},mobileConfig:{preventDefault:e.mobileInputConfig?.preventDefault??!1,passive:e.mobileInputConfig?.passive??!0,maxTouches:e.mobileInputConfig?.maxTouches??10}}),this.mobileVibration=new T.MobileVibration({debug:e.debug})}setMobileTarget(e){this.input.setMobileTarget(e)}start(){this.input.start()}stop(){this.input.stop()}destroy(){this.input.destroy()}getRouter(){return this.input}getGamepad(){return this.input.getGamepad()}getMobileVibration(){return this.mobileVibration}collectAndApply(e,t,i,r,s){if(t){let d=T.InputCollector.collectMousePosition(this.input,t,i,r,s);e.setMousePosition(d.x,d.y,d.over),e.updateMacroMouse(d.x,d.y,d.isLeftDown),T.InputCollector.collectTouchPositions(this.input,t,i,r,10,s).forEach(h=>{e.setTouchPosition(h.id,h.x,h.y,h.over)})}let n=T.InputCollector.collectTextInputs(this.input);n.length>0&&e.setTextInputs(n);let o=e.getInputBindingRegistry(),a=o.getAllAxes(),c=o.getAllButtons();if(a.length>0||c.length>0){let d=T.InputCollector.collectAxisSources(a,this.input),u=T.InputCollector.collectButtonSourcesWithTransitions(c,this.input);a.forEach(h=>{let m=o.evaluateAxis(h.bindingId,d);e.setAxis(h.name,m)}),c.forEach(h=>{let m=new Map,C=new Map,f=new Map;for(let[y,g]of u)m.set(y,g.pressed),C.set(y,g.justPressed),f.set(y,g.justReleased);let S=o.evaluateButton(h.bindingId,m),b=o.evaluateButton(h.bindingId,C),p=o.evaluateButton(h.bindingId,f);e.setButton(h.name,S),e.setButton(`${h.name}_justPressed`,b),e.setButton(`${h.name}_justReleased`,p)})}this.input.poll?.()}processVibrationCommands(e){e.hasMobileVibrationCommands()&&e.applyMobileVibrationCommands(e.flushMobileVibrationCommands()),e.hasGamepadVibrationCommands()&&e.applyGamepadVibrationCommands(e.flushGamepadVibrationCommands())}};R(_,"InputFeature");var H=_;var he=require("@utsp/audio");var ee=class ee{constructor(e={}){l(this,"audioManager");l(this,"debug");this.debug=e.debug??!1,this.audioManager=new he.AudioManager({debug:e.debug})}initialize(){this.audioManager.initialize()}playStartSound(){this.audioManager.playStartSound()}stopAll(){this.audioManager.stopAll()}destroy(){this.audioManager.destroy()}getManager(){return this.audioManager}getContext(){return this.audioManager.getContext()}injectIntoUser(e){e.setAudioProcessor(this.audioManager)}processAudioCommands(e){e.hasAudioConfigCommands()&&e.applyAudioConfigCommands(e.flushAudioConfigCommands()),e.hasSoundCommands()&&e.applyAudioCommands(e.flushSoundCommands())}async loadSoundsFromRegistry(e){let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load sounds: SoundBank not initialized");return}let r=e.getSoundRegistry().getAll();if(r.length===0){this.log("No sounds to load from registry");return}this.log(`Loading ${r.length} sounds from Core registry...`);for(let s of r)try{s.loadType==="file"&&s.data?(await t.loadFromData(s.soundId,s.name,s.data),this.log(`Loaded sound: ${s.name} (${s.data.length} bytes)`)):s.loadType==="external"&&s.url&&(await t.loadFromUrl(s.soundId,s.name,s.url),this.log(`Loaded external sound: ${s.name} from ${s.url}`))}catch(n){console.error(`[AudioFeature] Failed to load sound "${s.name}":`,n)}this.log(`${t.size} sounds loaded`)}log(e){this.debug&&console.warn(`[AudioFeature] ${e}`)}};R(ee,"AudioFeature");var W=ee;var E=require("@utsp/core"),ue=require("@utsp/render"),pe=require("@utsp/types");var te=class te{constructor(e,t={}){l(this,"overlay");l(this,"orderCollector");l(this,"debug");this.debug=t.debug??!1,this.overlay=new ue.PostProcessOverlay(e),this.orderCollector=new E.PostProcessOrderCollector}destroy(){this.overlay.destroy()}getOverlay(){return this.overlay}syncWithRenderer(e){this.overlay.syncWithRenderer(e),this.log("Overlay synced with renderer dimensions")}processCommands(e,t){if(!e.hasPostProcessCommands())return;let i=e.flushPostProcessCommands(),r=this.orderCollector.convertCommands(i);this.applyOrders(r,t)}applyOrders(e,t){for(let i of e){let r=i.displayId;switch(i.type){case E.PostProcessOrderType.SetConfig:{let s={};i.scanlines&&(s.scanlines={enabled:i.scanlines.enabled,opacity:i.scanlines.opacity,pattern:this.patternFromType(i.scanlines.pattern),color:{r:i.scanlines.colorR,g:i.scanlines.colorG,b:i.scanlines.colorB}}),i.ambientEffect&&(s.ambientEffect={enabled:i.ambientEffect.enabled,blur:i.ambientEffect.blur,scale:i.ambientEffect.scale}),this.overlay.setConfig(Object.keys(s).length>0?s:null),s.ambientEffect&&this.applyAmbientEffect(t,s.ambientEffect),this.log(`[Display ${r}] SetConfig applied`);break}case E.PostProcessOrderType.SetScanlines:{this.overlay.setScanlines({enabled:i.enabled,opacity:i.opacity,pattern:this.patternFromType(i.pattern),color:{r:i.colorR,g:i.colorG,b:i.colorB}}),this.log(`[Display ${r}] Scanlines ${i.enabled?"enabled":"disabled"}`);break}case E.PostProcessOrderType.SetAmbientEffect:{this.applyAmbientEffect(t,{enabled:i.enabled,blur:i.blur,scale:i.scale}),this.log(`[Display ${r}] Ambient effect ${i.enabled?"enabled":"disabled"}`);break}case E.PostProcessOrderType.SetScalingMode:{this.applyScalingMode(t,r,i.mode);break}case E.PostProcessOrderType.SetGrid:{this.applyGridConfig(t,r,i);break}}}}applyAmbientEffect(e,t){e&&"setAmbientEffect"in e&&(t.enabled?e.setAmbientEffect({blur:t.blur,scale:t.scale}):e.setAmbientEffect(!1))}applyScalingMode(e,t,i){if(e&&"setScalingMode"in e){let r=(0,pe.valueToScalingMode)(i);e.setScalingMode(r),this.log(`[Display ${t}] Scaling mode set to ${r}`)}}applyGridConfig(e,t,i){if(e&&"setGrid"in e){let r=i.colorA/255;e.setGrid({enabled:i.enabled,color:`rgba(${i.colorR},${i.colorG},${i.colorB},${r})`,lineWidth:i.lineWidth}),this.log(`[Display ${t}] Grid ${i.enabled?"enabled":"disabled"}`)}}patternFromType(e){switch(e){case 0:return"horizontal";case 1:return"vertical";case 2:return"grid";default:return"horizontal"}}log(e){this.debug&&console.warn(`[PostProcessFeature] ${e}`)}};R(te,"PostProcessFeature");var Y=te;var ge=require("@utsp/render"),me=require("@utsp/types"),fe=require("@utsp/audio");
|
package/dist/index.d.ts
CHANGED
|
@@ -770,11 +770,15 @@ declare abstract class BaseClientRuntime {
|
|
|
770
770
|
e: number;
|
|
771
771
|
}>): void;
|
|
772
772
|
/**
|
|
773
|
-
* Handle
|
|
773
|
+
* Handle image font structure allocation
|
|
774
774
|
*/
|
|
775
|
-
protected
|
|
775
|
+
protected onCoreImageFontAllocated(fontId: number): void;
|
|
776
776
|
/**
|
|
777
|
-
* Handle image font
|
|
777
|
+
* Handle image font block addition
|
|
778
|
+
*/
|
|
779
|
+
protected onCoreImageFontBlockAdded(fontId: number, blockIndex: number): void;
|
|
780
|
+
/**
|
|
781
|
+
* Handle image font change from Core (Legacy/Complete)
|
|
778
782
|
*/
|
|
779
783
|
protected onCoreImageFontChanged(fontId: number): void;
|
|
780
784
|
/**
|
|
@@ -1375,7 +1379,6 @@ declare const DEFAULT_ATLAS_CONFIG: {
|
|
|
1375
1379
|
};
|
|
1376
1380
|
/**
|
|
1377
1381
|
* Decode base64 PNG data to Uint8Array
|
|
1378
|
-
* Note: This is a browser-only package, so we use atob (available in all modern browsers)
|
|
1379
1382
|
*/
|
|
1380
1383
|
declare function decodeDefaultAtlas(): Uint8Array;
|
|
1381
1384
|
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var ie=Object.defineProperty;var ne=(I,t,e)=>t in I?ie(I,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):I[t]=e;var S=(I,t)=>ie(I,"name",{value:t,configurable:!0});var d=(I,t,e)=>(ne(I,typeof t!="symbol"?t+"":t,e),e);import{Core as oe}from"@utsp/core";import{TerminalGL as ae,Terminal2D as de}from"@utsp/render";var re=(e=>(e.TerminalGL="webgl",e.Terminal2D="terminal2d",e))(re||{});var L=class L{constructor(t=60){d(this,"frameCount",0);d(this,"fps",0);d(this,"fpsUpdateTime",0);d(this,"lastCoreTime",0);d(this,"lastRenderTime",0);d(this,"lastTotalTime",0);d(this,"coreTimeSamples",[]);d(this,"renderTimeSamples",[]);d(this,"totalTimeSamples",[]);d(this,"maxSamples");if(t<=0)throw new Error("maxSamples must be positive");this.maxSamples=t}startTracking(t){this.fpsUpdateTime=t,this.frameCount=0,this.fps=0}updateFPS(t){this.frameCount++,t-this.fpsUpdateTime>=1e3&&(this.fps=Math.round(this.frameCount*1e3/(t-this.fpsUpdateTime)),this.frameCount=0,this.fpsUpdateTime=t)}recordFrameTiming(t,e){let i=t+e;this.lastCoreTime=t,this.lastRenderTime=e,this.lastTotalTime=i,this.coreTimeSamples.push(t),this.renderTimeSamples.push(e),this.totalTimeSamples.push(i),this.coreTimeSamples.length>this.maxSamples&&(this.coreTimeSamples.shift(),this.renderTimeSamples.shift(),this.totalTimeSamples.shift())}getFPS(){return this.fps}getLastFrameTiming(){if(!(this.lastCoreTime===0&&this.lastRenderTime===0))return{coreTime:this.lastCoreTime,renderTime:this.lastRenderTime,totalTime:this.lastTotalTime}}getAverageFrameTiming(){if(this.coreTimeSamples.length!==0)return{coreTime:this.average(this.coreTimeSamples),renderTime:this.average(this.renderTimeSamples),totalTime:this.average(this.totalTimeSamples)}}getStats(){return{fps:this.fps,lastFrame:this.getLastFrameTiming(),avgFrame:this.getAverageFrameTiming(),sampleCount:this.coreTimeSamples.length,maxSamples:this.maxSamples}}reset(){this.frameCount=0,this.fps=0,this.fpsUpdateTime=0,this.lastCoreTime=0,this.lastRenderTime=0,this.lastTotalTime=0,this.coreTimeSamples=[],this.renderTimeSamples=[],this.totalTimeSamples=[]}average(t){return t.length===0?0:t.reduce((e,i)=>e+i,0)/t.length}};S(L,"PerformanceMonitor");var x=L;var se="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",T={glyphWidth:8,glyphHeight:8,cellWidth:8,cellHeight:8,atlasBlocks:1,atlasWidth:128,atlasHeight:128};function $(){let I=atob(se),t=new Uint8Array(I.length);for(let e=0;e<I.length;e++)t[e]=I.charCodeAt(e);return t}S($,"decodeDefaultAtlas");var V=class V{constructor(t,e={}){d(this,"renderer");d(this,"options");d(this,"layerFilter",null);this.renderer=t,this.options={debug:e.debug??!1,useImageDataRendering:e.useImageDataRendering??!1}}setLayerFilter(t){this.layerFilter=t}getLayerFilter(){return this.layerFilter}async initialize(t){if("setImageDataRendering"in this.renderer&&this.options.useImageDataRendering&&(this.renderer.setImageDataRendering(!0),this.log("ImageData rendering enabled")),"setImageFont"in this.renderer&&typeof this.renderer.setImageFont=="function"){this.log("Loading default 8x8 font atlas...");let e=$();await this.renderer.setImageFont(e,T.glyphWidth,T.glyphHeight,T.cellWidth,T.cellHeight,T.atlasBlocks),this.log("Default 8x8 font atlas loaded")}await this.waitForReady(),this.log("Initialized and ready")}async waitForReady(t=100,e=50){this.log("Waiting for renderer to be ready");let i=0;return new Promise((r,s)=>{let n=S(()=>{if(i++,this.renderer.isReady())this.log(`Renderer ready after ${i*e}ms`),r();else if(i>=t){let a=`Renderer failed to be ready after ${t*e}ms`;this.log(a),s(new Error(a))}else setTimeout(n,e)},"check");n()})}async loadDefaultFont(t){console.warn("[RendererManager] loadDefaultFont() is deprecated. Use ImageFont instead.")}renderDisplay(t){return this.renderer.isReady()?t?(this.renderer.renderDisplayData(t),!0):(console.warn("[RENDERER MANAGER] No display provided"),!1):(console.warn("[RENDERER MANAGER] Renderer not ready"),!1)}render(t,e){let i=this.layerFilter?t.getRenderState(e,this.layerFilter):t.getRenderState(e);return!i||i.displays.length===0?(console.warn("[RENDERER MANAGER] No render state or no displays"),!1):this.renderDisplay(i.displays[0])}getRenderer(){return this.renderer}getCanvas(){return this.renderer.getCanvas()}getAvailableSize(){if(this.renderer.getAvailableSize)return this.renderer.getAvailableSize();let t=this.getCanvas();return{width:t?.clientWidth||t?.width||0,height:t?.clientHeight||t?.height||0}}isReady(){return this.renderer.isReady()}destroy(){this.log("Destroying renderer"),this.renderer.destroy()}log(t){this.options.debug&&console.warn(`[RendererManager] ${t}`)}};S(V,"RendererManager");var k=V;var G=class G{constructor(t){d(this,"core");d(this,"rendererManagers",new Map);d(this,"rendererInitPromises",new Map);d(this,"rendererManager");d(this,"rendererType");d(this,"primaryDisplayId",0);d(this,"displayConfigs");d(this,"options");d(this,"running",!1);d(this,"startTime",0);d(this,"lastTimestamp",0);d(this,"userId","");d(this,"visibilityChangeHandler");d(this,"tickRate",30);d(this,"accumulatedTime",0);d(this,"FRAME_TIME_MIN",1e3/60);d(this,"lastRenderTimestamp",0);d(this,"rafId",0);d(this,"firstTickDone",!1);d(this,"performanceMonitor");d(this,"renderMode","continuous");d(this,"renderRequested",!1);if(this.options={application:t.application,container:t.container,displayContainers:t.displayContainers,debug:t.debug??!1,width:t.width??80,height:t.height??25,renderer:t.renderer??"webgl",useImageDataRendering:t.useImageDataRendering??!0,renderMode:t.renderMode??"continuous"},this.log("Initializing BaseClientRuntime"),this.core=new oe({mode:"client",maxUsers:1}),this.core.onPaletteChanged(e=>{this.onCorePaletteChanged(e)}),this.core.onBitmapFontChanged(e=>{this.onCoreBitmapFontChanged(e)}),this.core.onImageFontChanged(e=>{this.onCoreImageFontChanged(e)}),this.visibilityChangeHandler=()=>{!document.hidden&&this.running&&(this.lastTimestamp=performance.now(),this.accumulatedTime=0,this.log("Tab visible: Reset timing"))},document.addEventListener("visibilitychange",this.visibilityChangeHandler),this.rendererType=this.options.renderer,this.options.displayContainers&&this.options.displayContainers.length>0){this.displayConfigs=new Map([[0,{container:this.options.container,renderer:this.options.renderer}]]);for(let e of this.options.displayContainers){let i=e.renderer;this.displayConfigs.set(e.id,{container:e.container,renderer:i})}this.primaryDisplayId=0}else this.displayConfigs=new Map([[0,{container:this.options.container,renderer:this.options.renderer}]]),this.primaryDisplayId=0;this.createRendererManagers(),this.performanceMonitor=new x(60),this.tickRate=20,this.renderMode=t.renderMode??"continuous",this.log(`Configured: tickRate=${this.tickRate}, renderMode=${this.renderMode}`),this.log("BaseClientRuntime initialized")}createRenderer(t,e){if(e==="terminal2d"){this.log("Creating Terminal 2D renderer");let n=new de(t,{fixedCols:this.options.width,fixedRows:this.options.height,cellAspectRatio:1});return this.options.useImageDataRendering&&(this.log("Enabling ImageData rendering (pixel-perfect, optimized)"),n.setImageDataRendering(!0)),this.log("Canvas 2D renderer created successfully"),n}this.log("Creating TerminalGL renderer");let r=document.createElement("canvas").getContext("webgl");if(!r)throw new Error("WebGL not supported. TerminalGL requires WebGL 1.0.");if(!r.getExtension("OES_element_index_uint"))throw new Error("OES_element_index_uint extension not supported. TerminalGL requires this extension for large terminals (256x256).");if(!(t instanceof HTMLDivElement))throw new Error(`TerminalGL requires container to be an HTMLDivElement. Received: ${t.tagName}`);let s=new ae(t,{cols:this.options.width,rows:this.options.height,charWidth:8,charHeight:8});return this.log("TerminalGL created successfully"),s}createRendererManagers(){let t=this.displayConfigs.size>=3;this.rendererManagers.clear();for(let[i,r]of this.displayConfigs.entries()){let s=t?"terminal2d":r.renderer??this.options.renderer,n=this.createRenderer(r.container,s??"webgl"),o=new k(n,{debug:this.options.debug,useImageDataRendering:this.options.useImageDataRendering});this.rendererManagers.set(i,o)}let e=this.rendererManagers.get(this.primaryDisplayId);if(!e)throw new Error(`Primary display ${this.primaryDisplayId} has no renderer. Check displayContainers configuration.`);this.rendererManager=e}ensureRendererManager(t){let e=this.rendererManagers.get(t);if(e)return e;let i=document.createElement("div");i.dataset.displayId=String(t),i.style.cssText="position:relative;display:inline-block;margin:4px;background:#000;overflow:hidden;",(this.options.container?.parentElement??document.body).appendChild(i),this.displayConfigs.set(t,{container:i});let o=this.displayConfigs.size>=3?"terminal2d":this.options.renderer??"webgl",a=this.createRenderer(i,o),l=new k(a,{debug:this.options.debug,useImageDataRendering:this.options.useImageDataRendering});if(this.rendererManagers.set(t,l),!this.rendererInitPromises.has(t)){let c=l.initialize(this.core).then(()=>{this.onCorePaletteChanged(this.core.getPalette());let h=this.core.getImageFontIds,u=typeof h=="function"?h.call(this.core):[];u.length>0&&this.onCoreImageFontChanged(u[0]);let m=this.rebuildPostProcessOverlays;typeof m=="function"&&m.call(this)}).catch(h=>{console.warn(`[BaseClientRuntime] Failed to init renderer for display ${t}:`,h)});this.rendererInitPromises.set(t,c)}return l}getRendererType(){return this.rendererType}isRunning(){return this.running}setTickRate(t){if(t<0||t>1e3)throw new Error(`Invalid tick rate: ${t}. Must be between 0 and 1000.`);if(this.tickRate=t,this.userId){let e=this.core.getUser(this.userId);e&&e.setBytesTickRate(t>0?t:20)}t===0&&this.renderMode==="continuous"?(this.renderMode="on-demand",this.log("Tick rate set to 0, switched to on-demand render mode")):this.log(`Tick rate set to ${t} TPS`)}setRenderMode(t){this.renderMode=t,this.log(`Render mode set to ${t}`)}setMaxFPS(t){if(t<=0||t>240)throw new Error(`Invalid FPS: ${t}. Must be between 1 and 240.`);this.FRAME_TIME_MIN=1e3/t,this.log(`Max FPS set to ${t}`)}getTickRate(){return this.tickRate}requestRender(){this.renderMode==="on-demand"&&(this.renderRequested=!0,this.log("Render requested"))}async start(){if(this.running){this.log("Already running");return}this.log("Starting BaseClientRuntime"),await this.onBeforeStart();for(let[t,e]of this.rendererManagers.entries())await e.initialize(this.core),this.log(`Renderer for display ${t} is ready`);this.onCorePaletteChanged(this.core.getPalette()),this.log("Initial palette sent to renderers"),this.options.application&&(this.log("Calling application.init()"),await this.options.application.init(this.core,this)),await this.onAfterInit(),await this.createLocalUser(),this.running=!0,this.startTime=performance.now(),this.lastTimestamp=this.startTime,this.lastRenderTimestamp=this.startTime,this.accumulatedTime=0,this.firstTickDone=!1,this.performanceMonitor.reset(),this.performanceMonitor.startTracking(this.startTime),this.log("Starting main loop"),this.mainLoop(this.lastTimestamp)}async onBeforeStart(){}async onAfterInit(){}async stop(){if(!this.running)return;this.log("Stopping BaseClientRuntime"),this.running=!1,this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0),await this.onStop();let t=this.core.getUser(this.userId);t&&this.options.application?.destroyUser&&this.options.application.destroyUser(this.core,t,"Runtime stopped"),this.log("BaseClientRuntime stopped")}async onStop(){}getStats(){let t=this.performanceMonitor.getStats();return{running:this.running,userCount:this.core.getUsers().length,fps:t.fps,uptime:this.running?performance.now()-this.startTime:0,totalFrames:0,lastFrameTiming:t.lastFrame,avgFrameTiming:t.avgFrame}}getTotalBytesReceived(){return this.core.getUser(this.userId)?.getTotalBytesReceived()??0}getBytesReceivedPerSecond(){return this.core.getUser(this.userId)?.getBytesReceivedPerSecond()??0}resetBytesReceived(){let t=this.core.getUser(this.userId);t&&t.resetByteCounters()}async destroy(){await this.stop(),this.log("Destroying BaseClientRuntime"),this.visibilityChangeHandler&&(document.removeEventListener("visibilitychange",this.visibilityChangeHandler),this.visibilityChangeHandler=void 0),await this.onDestroy();for(let t of this.rendererManagers.values()){let e=t.getRenderer();e&&"clearOnResizeCallback"in e&&e.clearOnResizeCallback()}this.options.application?.destroy&&this.options.application.destroy();for(let t of this.rendererManagers.values())t.destroy();this.log("BaseClientRuntime destroyed")}async onDestroy(){}async createLocalUser(){this.userId="local",this.log(`Creating local user: ${this.userId}`);let t=this.core.createUser(this.userId,"User");t.setBytesTickRate(this.tickRate>0?this.tickRate:20),this.onUserCreated(t),this.options.application?.initUser&&(this.log("Calling application.initUser()"),this.options.application.initUser(this.core,t,{username:"User"})),this.processInitialOrders(t);let e=this.core.generateAllLoadPackets();e.forEach(n=>{t.recordBytesReceived(n.length)});let i=this.core.generateMacroLoadPackets(this.userId);i.forEach(n=>{t.recordBytesReceived(n.length)});let r=t.getInputBindingsLoadPacket();r&&t.recordBytesReceived(r.length),this.log(`Simulated ${e.length} load packets, ${i.length} macro packets for byte counting`),this.log("Performing initial render"),this.core.endTick().forEach(({static:n,dynamic:o},a)=>{let l=this.core.getUser(a);l&&(n&&l.recordBytesReceived(n.length),o&&l.recordBytesReceived(o.length))})}processInitialOrders(t){if(t.hasPendingMacroOrders()){this.log("Applying macro orders from initUser()");let e=t.flushMacroOrders();t.applyMacroOrders(e)}}onUserCreated(t){}mainLoop(t){if(!this.running){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0);return}if(this.renderMode==="on-demand"){this.renderRequested&&(this.renderRequested=!1,this.performanceMonitor.updateFPS(t),this.render()),this.rafId=requestAnimationFrame(l=>this.mainLoop(l));return}let e=t-this.lastRenderTimestamp;if(this.lastRenderTimestamp>0&&e<this.FRAME_TIME_MIN-1){this.rafId=requestAnimationFrame(l=>this.mainLoop(l));return}this.lastRenderTimestamp=t;let i=(t-this.lastTimestamp)/1e3,r=Math.min(i,.1);this.lastTimestamp=t,this.performanceMonitor.updateFPS(t);let s=this.core.getUser(this.userId);if(!s){this.rafId=requestAnimationFrame(l=>this.mainLoop(l));return}if(this.tickRate===0){let l=performance.now();this.render();let c=performance.now()-l;this.performanceMonitor.recordFrameTiming(0,c),this.rafId=requestAnimationFrame(h=>this.mainLoop(h));return}if(!this.firstTickDone){this.firstTickDone=!0,this.lastTimestamp=t,this.accumulatedTime=0,this.rafId=requestAnimationFrame(l=>this.mainLoop(l));return}this.accumulatedTime+=r;let n=1/this.tickRate;this.accumulatedTime>.5&&(this.accumulatedTime=n);let o=0,a=0;for(;this.accumulatedTime>=n&&o<5;){let l=performance.now();this.collectAndApplyInput(s),this.options.application&&(this.options.application.update?.(this.core,n),this.options.application.updateUser?.(this.core,s,n)),this.processTickOrders(s);let c=s.updateMacros();s.processMacroEvents(c),this.core.endTick().forEach(({static:u,dynamic:m})=>{let v=(u?.length??0)+(m?.length??0);s.recordBytesReceived(v)}),a+=performance.now()-l,this.accumulatedTime-=n,o++}if(o>0){let l=performance.now();this.render();let c=performance.now()-l;this.performanceMonitor.recordFrameTiming(a,c)}this.rafId=requestAnimationFrame(l=>this.mainLoop(l))}collectAndApplyInput(t){}processTickOrders(t){if(t.clearTextInputs(),t.hasPendingMacroOrders()){let e=t.flushMacroOrders();t.applyMacroOrders(e)}}render(){let t=this.core.getUser(this.userId);if(t){let i=t.getMacroRenderOrders();for(let[r,s]of i){let n=t.getLayerById(r);n&&s.length>0&&n.addTemporaryOrders(s)}}let e=this.core.getRenderState(this.userId);if(!e||e.displays.length===0){console.warn("[BaseClientRuntime] No render state or displays");return}for(let i of e.displays){let r=this.rendererManagers.get(i.id)??this.ensureRendererManager(i.id);if(!r){console.warn(`[BaseClientRuntime] No renderer manager for display ${i.id}, skipping render`);continue}let s=r.getLayerFilter(),n=s?this.core.getRenderState(this.userId,s):e;if(!n){this.options.debug&&this.log(`Render state unavailable for display ${i.id} with filter`);continue}let o=n.displays.find(a=>a.id===i.id);if(!o){this.options.debug&&this.log(`Render state missing display ${i.id} after filtering`);continue}if(!r.isReady()){this.options.debug&&this.log(`Renderer for display ${i.id} not ready yet`);continue}r.renderDisplay(o)}}onCorePaletteChanged(t){this.log(`Palette changed, updating renderer (${t.size} colors)`);let e=[];for(let s=0;s<256;s++){let n=t.get(s);n?e.push({r:n.r,g:n.g,b:n.b,a:n.a}):e.push({r:0,g:0,b:0,a:0})}let i=S(s=>{s&&"setPalette"in s&&typeof s.setPalette=="function"&&s.setPalette(e)},"applyPalette"),r=0;for(let s of this.rendererManagers.values()){let n=s.getRenderer();n&&(i(n),r++)}r===0?console.warn("[BaseClientRuntime] Cannot update palette: no renderer available"):this.log(`\u2713 Palette updated on ${r} renderer(s)`)}onCoreBitmapFontChanged(t){this.log(`Bitmap font ${t} changed, updating renderer`);let e=this.core.getBitmapFont(t);if(!e){console.warn(`[BaseClientRuntime] Font ${t} not found in registry`);return}let i=new Map,r=0;for(let o=0;o<256;o++){let a=e.getGlyph(o);a&&(i.set(o,a),r++)}this.log(`Built bitmap font map with ${r} glyphs, dimensions: ${e.getCharWidth()}x${e.getCharHeight()}`);let s=S(o=>{o&&"setBitmapFont"in o&&typeof o.setBitmapFont=="function"&&o.setBitmapFont(i,e.getCharWidth(),e.getCharHeight(),e.getCellWidth(),e.getCellHeight())},"applyBitmapFont"),n=0;for(let[o,a]of this.rendererManagers.entries()){let l=a.getRenderer();l&&(s(l),n++,this.onFontChanged(l,o))}n===0?console.warn("[BaseClientRuntime] Cannot update font: no renderer available"):this.log(`\u2713 Renderer bitmap font updated successfully on ${n} renderer(s)`)}onCoreImageFontChanged(t){this.log(`Image font ${t} changed, updating renderer`);let e=this.core.getImageFont(t);if(!e){console.warn(`[BaseClientRuntime] Image font ${t} not found in registry`);return}this.log(`Loading image font with ${e.getAtlasBlocks()} blocks, glyph: ${e.getGlyphWidth()}x${e.getGlyphHeight()}`);let i=S(s=>{s&&"setImageFont"in s&&typeof s.setImageFont=="function"&&s.setImageFont(e.getImageData(),e.getGlyphWidth(),e.getGlyphHeight(),e.getCellWidth(),e.getCellHeight(),e.getAtlasBlocks())},"applyImageFont"),r=0;for(let[s,n]of this.rendererManagers.entries()){let o=n.getRenderer();o&&(i(o),r++,this.onFontChanged(o,s))}r===0?console.warn("[BaseClientRuntime] Cannot update image font: no renderer available"):this.log(`\u2713 Renderer image font updated successfully on ${r} renderer(s)`)}onFontChanged(t,e){}log(t){this.options.debug&&console.warn(`[BaseClientRuntime] ${t}`)}getCore(){return this.core}getRendererManager(t=this.primaryDisplayId){let e=this.rendererManagers.get(t);if(!e)throw new Error(`Renderer manager for display ${t} not found`);return e}setDisplayContainers(t){this.displayConfigs=new Map(t.map(i=>[i.id,{container:i.container}]));let e=Array.from(this.displayConfigs.keys());this.primaryDisplayId=e.length>0?Math.min(...e):0;for(let i of this.rendererManagers.values())i.destroy();this.rendererManagers.clear(),this.createRendererManagers()}getUserId(){return this.userId}};S(G,"BaseClientRuntime");var F=G;import{Core as ce,PostProcessOrderType as P,PostProcessOrderCollector as ue}from"@utsp/core";import{AutoplayOverlay as he,PostProcessOverlay as pe}from"@utsp/render";import{ScalingMode as ge,valueToScalingMode as me,Vector2 as fe}from"@utsp/types";import{UnifiedInputRouter as ye,InputCollector as U,MobileVibration as be}from"@utsp/input";import{SocketIOClient as ve,WebRTCClient as Ce}from"@utsp/network-client";import{AudioManager as Se}from"@utsp/audio";import{encodeCompressedInput as le}from"@utsp/core";import{InputCollector as E}from"@utsp/input";var w=1e3,z=class z{constructor(t,e,i,r,s,n,o){d(this,"network");d(this,"core");d(this,"rendererManagers");d(this,"primaryDisplayId");d(this,"performanceMonitor");d(this,"options");d(this,"layerTraffic",new Map);d(this,"miscTraffic",new Map);d(this,"displayTraffic",new Map);d(this,"audioManager",null);d(this,"postProcessCallback",null);d(this,"soundHandlersSetup",!1);d(this,"userId","");d(this,"lastReceivedTick",-1);d(this,"connected",!1);d(this,"totalBytesReceived",0);d(this,"lastSentViewports",new Map);d(this,"lastCollectedTouches",[]);d(this,"touchZonesCallback",null);d(this,"audioLoadingState",{totalExpected:0,loadedSounds:new Set,errors:new Map});d(this,"ensureRendererManager");this.network=t,this.core=e,this.rendererManagers=i,this.primaryDisplayId=n,this.performanceMonitor=r,this.ensureRendererManager=o,this.options={serverUrl:s.serverUrl,username:s.username,token:s.token??"",debug:s.debug??!1,autoReconnect:s.autoReconnect??!0,canvasWidth:s.canvasWidth,canvasHeight:s.canvasHeight}}getRendererManager(t){return this.rendererManagers.get(t)}getPrimaryRendererManager(){return this.rendererManagers.get(this.primaryDisplayId)??Array.from(this.rendererManagers.values())[0]}renderDisplays(){let t=this.core.getRenderState(this.userId);if(!t||t.displays.length===0){this.options.debug&&this.log("Render skipped: no render state or displays");return}for(let e of t.displays){let i=this.getRendererManager(e.id)??this.ensureRendererManager?.(e.id);if(!i){console.warn(`[NetworkSync] No renderer manager for display ${e.id}, skipping render`);continue}let r=i.getLayerFilter?.(),s=r?this.core.getRenderState(this.userId,r):t;if(!s){this.options.debug&&this.log(`Render state unavailable for display ${e.id} with filter`);continue}let n=s.displays.find(o=>o.id===e.id);if(!n){this.options.debug&&this.log(`Render state missing display ${e.id} after filtering`);continue}if(!i.isReady()){this.options.debug&&this.log(`Renderer for display ${e.id} not ready yet`);continue}i.renderDisplay(n)}}async connect(){this.log(`Connecting to ${this.options.serverUrl}`),await this.network.connect(),this.connected=!0,this.log("Connected to server"),this.setupNetworkHandlers()}async joinGame(t){return new Promise((e,i)=>{this.network.send("join",{username:this.options.username,token:this.options.token}),this.network.on("join_response",r=>{if(r.success){this.userId=r.userId,this.log(`Joined game as ${this.userId}`);let s=this.core.createUser(this.userId,this.options.username);s.setBytesTickRate(20),this.audioManager&&s.setAudioProcessor(this.audioManager),t?.initUser&&t.initUser(this.core,s,{username:this.options.username,token:this.options.token}),e(this.userId)}else i(new Error(r.error||"Failed to join game"))}),setTimeout(()=>i(new Error("Join timeout")),5e3)})}sendInput(t){let e=this.core.getUser(this.userId);if(!e)return;let i=this.getPrimaryRendererManager(),r=i?.getCanvas();if(r){let g=e.getDisplays(),J=(g.find(M=>M.getId&&M.getId()===this.primaryDisplayId)??g[0])?.getSize()??{x:this.options.canvasWidth,y:this.options.canvasHeight},Z=J.x,X=J.y,_=i?.getRenderer()?.getOffsets?.(),ee={offsetX:_?.offsetX??0,offsetY:_?.offsetY??0},A=E.collectMousePosition(t,r,Z,X,ee);e.setMousePosition(A.x,A.y,A.over),e.updateMacroMouse(A.x,A.y,A.isLeftDown);let te=E.collectTouchPositions(t,r,Z,X,10,ee);te.forEach(M=>{e.setTouchPosition(M.id,M.x,M.y,M.over)}),this.lastCollectedTouches=te}else this.lastCollectedTouches=[];let s=e.getInputBindingRegistry(),n=s.getAllAxes(),o=s.getAllButtons(),a=E.collectAxisSources(n,t),l=E.collectButtonSources(o,t),c=E.collectTextInputs(t);c.length>0&&e.setTextInputs(c);let h=n.sort((g,R)=>g.bindingId-R.bindingId),u=new Map;for(let g of h){let R=s.evaluateAxis(g.bindingId,a);u.set(g.bindingId,R),e.setAxis(g.name,R)}let m=o.sort((g,R)=>g.bindingId-R.bindingId),v=new Map;for(let g of m){let R=s.evaluateButton(g.bindingId,l);v.set(g.bindingId,R),e.setButton(g.name,R)}let f=e.getMouseDisplayInfo(),C=e.getIsMouseOnADisplay(),b=this.collectChangedViewports(),p=this.lastCollectedTouches.map(g=>({id:g.id,x:g.x,y:g.y,over:g.over})),y=le(0n,u,v,f?.displayId??0,f?.localX??0,f?.localY??0,C,c,[],b,p);this.network.send("input",y)}collectChangedViewports(){let t=[];for(let[e,i]of this.rendererManagers.entries()){let{width:r,height:s}=i.getAvailableSize();if(r===0||s===0)continue;let n=this.lastSentViewports.get(e);(!n||n.pixelWidth!==r||n.pixelHeight!==s)&&(t.push({displayId:e,pixelWidth:r,pixelHeight:s}),this.lastSentViewports.set(e,{pixelWidth:r,pixelHeight:s}),this.log(`Viewport changed: display ${e} = ${r}x${s}px`))}return t}disconnect(){this.connected&&(this.network.send("leave",{}),this.network.disconnect(),this.connected=!1,this.soundHandlersSetup=!1,this.log("Disconnected from server"))}getUserId(){return this.userId}isConnected(){return this.connected}getTotalBytesReceived(){return this.totalBytesReceived}getAudioLoadingState(){let t=this.audioLoadingState.loadedSounds.size,e=this.audioLoadingState.totalExpected,i=this.audioLoadingState.errors.size,r=e>0&&t>=e,s=Array.from(this.audioLoadingState.errors.keys());return{loadedCount:t,totalExpected:e,errorCount:i,isComplete:r,errors:s}}destroy(){this.disconnect(),this.network.destroy(),this.log("NetworkSync destroyed")}setupNetworkHandlers(){this.network.on("update",t=>{try{let e=this.convertToUint8Array(t,"update");if(!e)return;this.recordBytesReceived(e.length);let i=this.core.applyUpdatePacketBuffer(this.userId,e);i?(this.postProcessCallback&&i.postProcessOrders&&i.postProcessOrders.length>0&&this.postProcessCallback(i.postProcessOrders),this.renderDisplays()):this.log("Failed to apply update packet")}catch(e){this.log(`Error applying update packet: ${e}`)}}),this.network.on("update-static",t=>{this.handleUpdatePacket(t,"update-static")}),this.network.on("update-dynamic",t=>{this.handleUpdatePacket(t,"update-dynamic")}),this.network.on("load",t=>{try{let e=this.convertToUint8Array(t,"load");if(!e)return;this.recordBytesReceived(e.length),this.core.applyLoadPacket(e)?this.log("Load packet applied successfully"):this.log("Failed to apply load packet")}catch(e){this.log(`Error applying load packet: ${e}`)}}),this.network.on("input-bindings",t=>{if(this.recordBytesReceived(t.length),this.core.applyInputBindingsLoadPacket(this.userId,t)){this.log("Input bindings configured");try{let i=JSON.parse(t);if(this.log(`Touch zones in packet: ${i.touchZones?.length??0}, callback defined: ${!!this.touchZonesCallback}`),i.touchZones&&i.touchZones.length>0&&this.touchZonesCallback){let r=i.touchZones.map(s=>({id:s.zoneId,x:s.x,y:s.y,width:s.width,height:s.height}));this.touchZonesCallback(r),this.log(`Touch zones configured: ${r.length} zones`)}}catch{}}else this.log("Failed to apply input bindings")}),this.audioManager&&this.setupSoundHandlers(),this.network.on("disconnect",()=>{this.connected=!1,this.soundHandlersSetup=!1,this.log("Disconnected from server")})}handleUpdatePacket(t,e){try{let i=this.convertToUint8Array(t,e);if(!i)return;this.recordBytesReceived(i.length);let r=new DataView(i.buffer,i.byteOffset,i.byteLength),s=Number(r.getBigUint64(0,!1));if(e==="update-dynamic"&&s<this.lastReceivedTick)return;s>this.lastReceivedTick&&(this.lastReceivedTick=s);let n=this.core.applyUpdatePacketBuffer(this.userId,i);if(n){let o=performance.now(),a=S((b,p)=>{if(p<=0)return;let y=this.miscTraffic.get(b)??{total:0,windowSum:0,samples:[]};y.total+=p,y.windowSum+=p,y.samples.push({time:o,bytes:p}),this.miscTraffic.set(b,y)},"recordMisc"),l=S(b=>{try{return JSON.stringify(b).length}catch{return 0}},"safeLen"),c=n.__byteSizes,h=c?.audioOrders;typeof h=="number"?a("update.audioOrders",h):n.audioOrders&&n.audioOrders.length&&a("update.audioOrders",l(n.audioOrders));let u=c?.vibrationOrders;typeof u=="number"?a("update.vibrationOrders",u):n.vibrationOrders&&n.vibrationOrders.length&&a("update.vibrationOrders",l(n.vibrationOrders));let m=c?.macroOrders;typeof m=="number"?a("update.macroOrders",m):n.macroOrders&&n.macroOrders.length&&a("update.macroOrders",l(n.macroOrders));let v=c?.postProcessOrders;if(typeof v=="number"?a("update.postProcessOrders",v):n.postProcessOrders&&n.postProcessOrders.length&&a("update.postProcessOrders",l(n.postProcessOrders)),n.displays&&n.displays.length)for(let b of n.displays){let p=b.id;if(typeof p!="number")continue;let y=this.displayTraffic.get(p)??{total:0,windowSum:0,samples:[]},g=7;y.total+=g,y.windowSum+=g,y.samples.push({time:o,bytes:g}),this.displayTraffic.set(p,y)}for(let b of n.layers){let p=b.byteSize??0,y=this.layerTraffic.get(b.id)??{total:0,windowSum:0,samples:[]};y.total+=p,y.windowSum+=p,y.samples.push({time:o,bytes:p});let g=o-w;for(;y.samples.length&&y.samples[0].time<g;){let R=y.samples.shift();R&&(y.windowSum-=R.bytes)}this.layerTraffic.set(b.id,y)}{let b=o-w;this.miscTraffic.forEach((p,y)=>{for(;p.samples.length&&p.samples[0].time<b;){let g=p.samples.shift();g&&(p.windowSum-=g.bytes)}p.windowSum<0&&(p.windowSum=0),this.miscTraffic.set(y,p)})}{let b=o-w;this.displayTraffic.forEach((p,y)=>{for(;p.samples.length&&p.samples[0].time<b;){let g=p.samples.shift();g&&(p.windowSum-=g.bytes)}p.windowSum<0&&(p.windowSum=0),this.displayTraffic.set(y,p)})}this.postProcessCallback&&n.postProcessOrders&&n.postProcessOrders.length>0&&this.postProcessCallback(n.postProcessOrders),this.options.debug&&this.debugRenderState();let f=performance.now();this.renderDisplays();let C=performance.now()-f;this.performanceMonitor.recordFrameTiming(0,C),this.options.debug&&console.warn(`[CLIENT] render() completed for ${e} (${C.toFixed(2)}ms)`)}else this.options.debug&&this.log(`Failed to apply ${e} packet (tick ${s})`)}catch(i){this.log(`Error applying ${e} update packet: ${i}`),console.error(i)}}convertToUint8Array(t,e){return t instanceof Uint8Array?t:t instanceof ArrayBuffer?new Uint8Array(t):Array.isArray(t)?new Uint8Array(t):t.data&&Array.isArray(t.data)?new Uint8Array(t.data):typeof t=="object"&&t.type==="Buffer"?new Uint8Array(t.data):(this.log(`Unknown data type for ${e} packet: ${typeof t}`),null)}debugRenderState(){let t=this.core.getUser(this.userId);if(t){let r=t.getLayers();console.warn(`[CLIENT] User has ${r.length} layers`),r.forEach((s,n)=>{let o=s.getOrders(),a=s.getStatic();(o.length>0||a)&&console.warn(` Layer ${n}: ${o.length} orders, static=${a}, z=${s.getZOrder()}`)})}let i=this.getPrimaryRendererManager()?.isReady()??!1;console.warn(`[CLIENT] Renderer ready: ${i}`)}log(t){this.options.debug&&console.warn(`[NetworkSync] ${t}`)}recordBytesReceived(t){this.totalBytesReceived+=t;let e=this.core.getUser(this.userId);e&&e.recordBytesReceived(t)}getLayerTrafficStats(){let t={},i=performance.now()-w;return this.layerTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),t[s]={total:r.total,bytesPerSec1s:r.windowSum/(w/1e3)}}),t}getMiscTrafficStats(){let t={},i=performance.now()-w;return this.miscTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),t[s]={total:r.total,bytesPerSec1s:r.windowSum/(w/1e3)}}),t}getDisplayTrafficStats(){let t={},i=performance.now()-w;return this.displayTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),t[s]={total:r.total,bytesPerSec1s:r.windowSum/(w/1e3)}}),t}getSoundPacketSize(t){return t.mode==="file"?t.sounds.reduce((i,r)=>i+this.getSoundDataLength(r.data)+r.name.length+10,0):t.sounds.reduce((i,r)=>i+r.url.length+r.name.length+10,0)}getSoundDataLength(t){if(t instanceof Uint8Array)return t.length;if(t instanceof ArrayBuffer||ArrayBuffer.isView(t))return t.byteLength;let e=globalThis.Buffer;return e&&t instanceof e?t.length:t&&typeof t=="object"&&Array.isArray(t.data)?t.data.length:Array.isArray(t)?t.length:0}setAudioManager(t){if(this.audioManager=t,t&&this.userId){let e=this.core.getUser(this.userId);e&&e.setAudioProcessor(t)}this.connected&&t&&this.setupSoundHandlers()}setPostProcessCallback(t){this.postProcessCallback=t}setTouchZonesCallback(t){this.touchZonesCallback=t}setupSoundHandlers(){if(this.audioManager){if(this.soundHandlersSetup){this.log("Sound handlers already registered, skipping");return}this.soundHandlersSetup=!0,this.network.on("sound-load",async t=>{this.recordBytesReceived(this.getSoundPacketSize(t)),t.totalSounds!==void 0&&t.totalSounds>this.audioLoadingState.totalExpected&&(this.audioLoadingState.totalExpected=t.totalSounds,this.log(`Audio loading: expecting ${t.totalSounds} total sounds`)),t.mode==="file"?await this.handleSoundLoad(t):t.mode==="external"&&await this.handleSoundExternalLoad(t)}),this.log("Sound handlers registered")}}async handleSoundLoad(t){if(!this.audioManager){this.log("Cannot load sounds: AudioManager not initialized");return}let e=this.audioManager.getSoundBank();if(!e){this.log("Cannot load sounds: SoundBank not initialized");return}for(let i of t.sounds)try{let r=this.normalizeSoundData(i.data);await e.loadFromData(i.soundId,i.name,r),this.log(`Loaded sound: ${i.name} (${r.length} bytes)`),this.audioLoadingState.loadedSounds.add(i.name),this.audioLoadingState.errors.delete(i.name),this.sendAudioAck({type:"sound-loaded",soundId:i.soundId,name:i.name})}catch(r){console.error(`[NetworkSync] Failed to load sound "${i.name}":`,r),this.audioLoadingState.errors.set(i.name,String(r)),this.sendAudioAck({type:"sound-error",soundId:i.soundId,name:i.name,error:String(r)})}}normalizeSoundData(t){if(t instanceof Uint8Array)return t;if(t instanceof ArrayBuffer)return new Uint8Array(t);if(ArrayBuffer.isView(t))return new Uint8Array(t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength));let e=globalThis.Buffer;if(e&&t instanceof e)return new Uint8Array(t);if(t&&typeof t=="object"&&Array.isArray(t.data))return new Uint8Array(t.data);if(Array.isArray(t))return new Uint8Array(t);if(typeof t=="string")try{let i=atob(t),r=i.length,s=new Uint8Array(r);for(let n=0;n<r;n++)s[n]=i.charCodeAt(n);return s}catch{}throw new Error("Invalid sound data payload")}async handleSoundExternalLoad(t){if(!this.audioManager){this.log("Cannot load external sounds: AudioManager not initialized");return}let e=this.audioManager.getSoundBank();if(!e){this.log("Cannot load external sounds: SoundBank not initialized");return}for(let i of t.sounds)try{await e.loadFromUrl(i.soundId,i.name,i.url),this.log(`Loaded external sound: ${i.name} from ${i.url}`),this.audioLoadingState.loadedSounds.add(i.name),this.audioLoadingState.errors.delete(i.name),this.sendAudioAck({type:"sound-loaded",soundId:i.soundId,name:i.name})}catch(r){console.error(`[NetworkSync] Failed to load external sound "${i.name}":`,r),this.audioLoadingState.errors.set(i.name,String(r)),this.sendAudioAck({type:"sound-error",soundId:i.soundId,name:i.name,error:String(r)})}}sendAudioAck(t){this.network.send("audio-ack",t),this.log(`Sent audio-ack: ${t.type}`)}sendBridge(t,e){this.network.sendBridge?.(t,e),this.log(`Bridge sent on channel '${t}'`)}onBridge(t,e){this.network.onBridge?.(t,e),this.log(`Bridge handler registered for channel '${t}'`)}offBridge(t,e){this.network.offBridge?.(t,e),this.log(`Bridge handler removed for channel '${t}'`)}removeAllBridgeHandlers(t){this.network.removeAllBridgeHandlers?.(t),this.log(t?`All bridge handlers removed for '${t}'`:"All bridge handlers removed")}};S(z,"NetworkSync");var D=z;var H=class H extends F{constructor(e){let i=e.mode;if(i!=="standalone"&&i!=="socketio"&&i!=="webrtc")throw new Error(`Invalid ClientRuntime mode: "${i}". Expected 'standalone', 'socketio', or 'webrtc'.`);let r;if(e.mode==="standalone"&&(r=e.standalone.application),!r&&e.mode==="standalone")throw new Error("Application instance required for standalone mode");super({application:r,container:e.container,displayContainers:e.displayContainers,debug:e.debug,width:e.width,height:e.height,renderer:e.renderer,useImageDataRendering:e.useImageDataRendering,renderMode:e.renderMode});d(this,"input",null);d(this,"networkSync",null);d(this,"mode");d(this,"localOptions",null);d(this,"autoplayOverlay",null);d(this,"autoplay",!0);d(this,"audioManager",null);d(this,"mobileVibration",null);d(this,"postProcessOverlay",null);d(this,"postProcessOverlays",new Map);d(this,"postProcessOrderCollector",new ue);d(this,"pendingPaletteSlotByDisplay",new Map);d(this,"localBridgeHandlers",new Map);d(this,"localBridgeWildcardHandlers",new Set);this.mode=e.mode,this.autoplay=e.autoplay??!0,e.mode==="standalone"?(this.localOptions=e,this.userId=e.standalone.userId??"local"):this.localOptions=null,this.mode==="standalone"?(this.log("Initializing in STANDALONE mode"),this.initLocalMode()):(this.log(`Initializing in ${this.mode.toUpperCase()} mode`),this.initConnectedMode(e))}initLocalMode(){let e=this.localOptions;if(!e)return;this.log("Initializing ClientRuntime (standalone mode)"),e.inputEnabled??!0?this.initInput(e):this.log("Input disabled (inputEnabled: false)")}initConnectedMode(e){this.log(`Initializing ClientRuntime (${this.mode} mode)`),this.core=new ce({mode:"client",maxUsers:100}),this.core.onPaletteChanged(n=>{this.onCorePaletteChanged(n),this.retryPendingPaletteSelections()}),this.core.onBitmapFontChanged(n=>{this.onCoreBitmapFontChanged(n)}),this.core.onImageFontChanged(n=>{this.onCoreImageFontChanged(n)});let i;if(e.mode==="webrtc"){let n=e.webrtc;i=new Ce({url:n.signalUrl??"",sessionId:n.sessionId,signalingPath:n.signalingPath,iceServers:n.iceServers,autoReconnect:n.autoReconnect,auth:n.auth??{username:n.username},debug:e.debug})}else{let n=e.socketio;if(!n)throw new Error(`SocketIO configuration missing. Mode is '${e.mode}' but 'socketio' options are undefined.`);i=new ve({url:n.url??"",path:n.path,autoReconnect:n.autoReconnect,auth:n.auth??{username:n.username},debug:e.debug})}let r=e.mode==="socketio"?e.socketio:e.webrtc;this.networkSync=new D(i,this.core,this.rendererManagers,this.performanceMonitor,{serverUrl:e.mode==="socketio"?e.socketio.url:e.webrtc.signalUrl||"WebRTC",username:r.username??"User",debug:e.debug,autoReconnect:r.autoReconnect,canvasWidth:e.width??80,canvasHeight:e.height??25},this.primaryDisplayId,n=>this.ensureRendererManager(n)),(e.inputEnabled??!0)&&(this.input||this.initInput(e))}initInput(e){this.input=new ye({enableKeyboardMouse:!0,enableGamepad:!0,enableMobile:!0,targetElement:window,mobileTargetElement:e.touchZones?.targetElement??void 0,debug:e.debug,keyboardConfig:{preventDefault:e.captureInput??!1,stopPropagation:e.captureInput??!1},mouseConfig:{preventDefault:e.captureInput??!1,stopPropagation:e.captureInput??!1},mobileConfig:{preventDefault:e.mobileInputConfig?.preventDefault??!1,passive:e.mobileInputConfig?.passive??!0,maxTouches:e.mobileInputConfig?.maxTouches??10},enableTouchZones:e.touchZones?.enable??!1,touchZoneConfig:{targetElement:e.touchZones?.targetElement,gridWidth:e.touchZones?.gridWidth??e.width??0,gridHeight:e.touchZones?.gridHeight??e.height??0,rendererOffsets:e.touchZones?.rendererOffsets,zones:e.touchZones?.zones}})}rebuildPostProcessOverlays(){for(let e of this.postProcessOverlays.values())e.destroy();this.postProcessOverlays.clear(),this.postProcessOverlay=null;for(let[e,i]of this.displayConfigs.entries()){let r=new pe(i.container);this.postProcessOverlays.set(e,r),e===this.primaryDisplayId&&(this.postProcessOverlay=r)}!this.postProcessOverlay&&this.postProcessOverlays.size>0&&(this.postProcessOverlay=Array.from(this.postProcessOverlays.values())[0]??null)}getMode(){return this.mode}setTickRate(e){if(this.mode!=="standalone"){this.log("setTickRate() has no effect in connected mode");return}super.setTickRate(e)}async onBeforeStart(){this.audioManager=new Se({debug:this.options.debug}),this.mobileVibration=new be({debug:this.options.debug}),this.autoplay?(this.log("Autoplay enabled, initializing AudioManager..."),this.audioManager.initialize()):(this.log("Autoplay disabled, showing overlay..."),await new Promise(e=>{this.autoplayOverlay=new he(this.options.container,{...this.localOptions?.autoplayOptions,onStart:()=>{this.log("User clicked start button"),this.audioManager&&(this.audioManager.initialize(),this.audioManager.playStartSound()),this.mobileVibration&&this.mobileVibration.vibrate(50),this.autoplayOverlay&&(this.autoplayOverlay.destroy(),this.autoplayOverlay=null),e()}})}),this.log("Autoplay overlay dismissed, continuing startup..."))}async start(){if(this.running){this.log("Already running");return}this.log("Starting ClientRuntime"),await this.onBeforeStart();for(let[r,s]of this.rendererManagers.entries())await s.initialize(this.core),this.log(`Renderer for display ${r} is ready`);this.rebuildPostProcessOverlays(),this.log("PostProcessOverlays created"),this.onCorePaletteChanged(this.core.getPalette()),this.log("Initial palette sent to renderer"),this.options.application&&(this.log("Calling application.init()"),await this.options.application.init(this.core,this));let e=this.rendererManager.getCanvas();if(e&&this.input&&this.input.setMobileTarget(e),this.mode!=="standalone"&&this.networkSync){if(this.audioManager&&this.networkSync.setAudioManager(this.audioManager),this.networkSync.setPostProcessCallback(s=>{this.applyPostProcessOrders(s)}),this.input){let s=this.input,n=this.rendererManager;this.networkSync.setTouchZonesCallback(o=>{this.log(`[start] Touch zones callback called with ${o.length} zones`);let a=n.getCanvas();if(this.log(`[start] Canvas available: ${!!a}`),a){let l=o.reduce((u,m)=>Math.max(u,m.x+m.width),0),c=o.reduce((u,m)=>Math.max(u,m.y+m.height),0);this.log(`[start] Grid from zones: ${l}x${c}`);let h=s.enableTouchZonesDevice(a,l,c,o);this.log(`[start] enableTouchZonesDevice returned: ${h}`),h&&this.log(`Touch zones configured from server: ${o.length} zones`)}})}await this.networkSync.connect(),this.userId=await this.networkSync.joinGame(this.options.application);let r=this.core.getUser(this.userId);r&&this.configureUserProcessors(r)}else await this.createLocalUser();let i=this.core.getUser(this.userId);if(i){let r=i.getDisplays();if(r.length>0){let n=r[0].getSize(),o=n.x,a=n.y,l=this.rendererManager.getRenderer(),c,h;if(this.rendererType==="webgl"){let m=l.getGridSize();c=m.cols,h=m.rows}else{let u=l;c=u.getCols(),h=u.getRows()}(c!==o||h!==a)&&(this.log(`Adjusting renderer from ${c}\xD7${h} to match display ${o}\xD7${a}`),l.resize(o,a))}}this.input&&this.input.start(),this.running=!0,this.startTime=performance.now(),this.lastTimestamp=this.startTime,this.lastRenderTimestamp=this.startTime,this.accumulatedTime=0,this.firstTickDone=!1,this.performanceMonitor.reset(),this.performanceMonitor.startTracking(this.startTime),this.log("Starting main loop"),this.mainLoop(this.lastTimestamp)}async onStop(){this.audioManager&&this.audioManager.stopAll(),this.input&&this.input.stop(),this.mode!=="standalone"&&this.networkSync&&this.networkSync.disconnect()}getStats(){let e=super.getStats(),r=this.core.getUser(this.userId)?.getTotalBytesReceived();return{...e,mode:this.mode,latency:void 0,totalBytesReceived:r}}getAudioLoadingState(){if(this.mode!=="standalone"&&this.networkSync)return this.networkSync.getAudioLoadingState();if(this.audioManager){let e=this.audioManager.getSoundBank();if(e){let i=e.getStats();return{loadedCount:i.totalSounds,totalExpected:i.totalSounds,errorCount:0,isComplete:!0,errors:[]}}}return{loadedCount:0,totalExpected:0,errorCount:0,isComplete:!0,errors:[]}}async onDestroy(){this.autoplayOverlay&&(this.autoplayOverlay.destroy(),this.autoplayOverlay=null),this.audioManager&&(this.audioManager.destroy(),this.audioManager=null),this.postProcessOverlay&&(this.postProcessOverlay.destroy(),this.postProcessOverlay=null);for(let e of this.postProcessOverlays.values())e.destroy();this.postProcessOverlays.clear(),this.input&&this.input.destroy(),this.networkSync&&this.networkSync.destroy()}configureUserProcessors(e){if(this.audioManager&&e.setAudioProcessor(this.audioManager),this.mobileVibration&&e.setMobileVibrationProcessor(this.mobileVibration),this.input){let i=this.input.getGamepad();i&&e.setGamepadVibrationProcessor(i)}}async createLocalUser(){let e=this.localOptions;this.userId=e?.standalone.userId??"local",this.log(`Creating local user: ${this.userId}`);let i=this.core.createUser(this.userId,e?.standalone.username??"User");if(i.setBytesTickRate(this.tickRate>0?this.tickRate:20),this.configureUserProcessors(i),this.options.application?.initUser&&(this.log("Calling application.initUser()"),this.options.application.initUser(this.core,i,{username:e?.standalone.username??"User"})),i.hasAudioConfigCommands()&&(this.log("Applying audio config commands from initUser()"),i.applyAudioConfigCommands(i.flushAudioConfigCommands())),i.hasPendingMacroOrders()){this.log("Applying macro orders from initUser()");let a=i.flushMacroOrders();i.applyMacroOrders(a)}if(i.hasPostProcessCommands()){this.log("Applying post-process commands from initUser()");let a=i.flushPostProcessCommands(),l=this.postProcessOrderCollector.convertCommands(a);this.applyPostProcessOrders(l)}i.needsSendSounds()&&(await this.loadSoundsFromRegistry(),i.clearSendSounds());let r=this.core.generateAllLoadPackets();r.forEach(a=>{i.recordBytesReceived(a.length)});let s=this.core.generateMacroLoadPackets(this.userId);s.forEach(a=>{i.recordBytesReceived(a.length)});let n=i.getInputBindingsLoadPacket();if(n&&(i.recordBytesReceived(n.length),this.input)){let l=i.getInputBindingRegistry().getAllTouchZones();if(l.length>0){let c=this.rendererManager.getCanvas();if(c){let h=i.getDisplays(),u=h.length>0?h[0].getSize():{x:this.options.width??80,y:this.options.height??25},m=l.map(f=>({id:f.zoneId,x:f.x,y:f.y,width:f.width,height:f.height}));this.input.enableTouchZonesDevice(c,u.x,u.y,m)?this.log(`Touch zones synchronized from registry: ${l.length} zones`):this.log("Failed to enable touch zones - mobile input may not be initialized")}}}this.log(`Simulated ${r.length} load packets, ${s.length} macro packets for byte counting`),this.log("Performing initial render"),this.core.endTick().forEach(({static:a,dynamic:l},c)=>{let h=this.core.getUser(c);h&&(a&&h.recordBytesReceived(a.length),l&&h.recordBytesReceived(l.length))}),this.render(),this.log("Initial render complete")}async loadSoundsFromRegistry(){if(!this.audioManager){this.log("Cannot load sounds: AudioManager not initialized");return}let e=this.audioManager.getSoundBank();if(!e){this.log("Cannot load sounds: SoundBank not initialized");return}let r=this.core.getSoundRegistry().getAll();if(r.length===0){this.log("No sounds to load from registry");return}this.log(`Loading ${r.length} sounds from Core registry into AudioManager...`);let s=this.core.getUser(this.userId),n=0;for(let o of r)try{if(o.loadType==="file"&&o.data){await e.loadFromData(o.soundId,o.name,o.data);let a=o.data.length+o.name.length+10;n+=a,this.log(`\u{1F50A} Loaded sound: ${o.name} (${o.data.length} bytes)`)}else if(o.loadType==="external"&&o.url){await e.loadFromUrl(o.soundId,o.name,o.url);let a=o.url.length+o.name.length+10;n+=a,this.log(`\u{1F50A} Loaded external sound: ${o.name} from ${o.url}`)}}catch(a){console.error(`[ClientRuntime] Failed to load sound "${o.name}":`,a)}s&&n>0&&(s.recordBytesReceived(n),this.log(`Simulated ${n} bytes for ${r.length} sound(s)`)),this.log(`\u2713 ${e.size} sounds loaded into AudioManager`)}mainLoop(e){if(!this.running){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0);return}if(this.renderMode==="on-demand"){this.renderRequested&&(this.renderRequested=!1,this.performanceMonitor.updateFPS(e),this.render()),this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}let i=e-this.lastRenderTimestamp;if(this.lastRenderTimestamp>0&&i<this.FRAME_TIME_MIN-1){this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}this.lastRenderTimestamp=e;let r=(e-this.lastTimestamp)/1e3,s=Math.min(r,.1);this.lastTimestamp=e,this.performanceMonitor.updateFPS(e);let n=this.core.getUser(this.userId);if(!n){this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}if(this.mode==="standalone"){if(this.tickRate===0){let c=performance.now();this.render();let h=performance.now()-c;this.performanceMonitor.recordFrameTiming(0,h),this.rafId=requestAnimationFrame(u=>this.mainLoop(u));return}if(!this.firstTickDone){this.firstTickDone=!0,this.lastTimestamp=e,this.accumulatedTime=0,this.rafId=requestAnimationFrame(c=>this.mainLoop(c));return}this.accumulatedTime+=s;let o=1/this.tickRate;this.accumulatedTime>.5&&(this.accumulatedTime=o);let a=0,l=0;for(;this.accumulatedTime>=o&&a<5;){let c=performance.now();if(this.collectAndApplyInput(n),this.options.application&&(this.options.application.update?.(this.core,o),this.options.application.updateUser?.(this.core,n,o)),n.clearTextInputs(),n.hasAudioConfigCommands()&&n.applyAudioConfigCommands(n.flushAudioConfigCommands()),n.hasSoundCommands()&&n.applyAudioCommands(n.flushSoundCommands()),n.hasMobileVibrationCommands()&&n.applyMobileVibrationCommands(n.flushMobileVibrationCommands()),n.hasGamepadVibrationCommands()&&n.applyGamepadVibrationCommands(n.flushGamepadVibrationCommands()),n.hasPostProcessCommands()){let m=n.flushPostProcessCommands(),v=this.postProcessOrderCollector.convertCommands(m);this.applyPostProcessOrders(v)}if(n.hasPendingMacroOrders()){let m=n.flushMacroOrders();n.applyMacroOrders(m)}let h=n.updateMacros();if(n.processMacroEvents(h),n.hasBridgeMessages()){let m=n.getBridgeMessages();this.dispatchLocalBridgeMessages(m)}this.core.endTick().forEach(({static:m,dynamic:v})=>{let f=(m?.length??0)+(v?.length??0);n.recordBytesReceived(f)}),l+=performance.now()-c,this.accumulatedTime-=o,a++}if(a>0){let c=performance.now();this.render();let h=performance.now()-c;this.performanceMonitor.recordFrameTiming(l,h)}}else{let o=n.updateMacros();n.processMacroEvents(o),this.collectAndSendInput()}this.rafId=requestAnimationFrame(o=>this.mainLoop(o))}collectAndApplyInput(e){if(!this.input)return;let i=this.rendererManager.getCanvas();if(i){let a=e.getDisplays(),c=(a.find(g=>g.getId&&g.getId()===this.primaryDisplayId)??a[0])?.getSize()??{x:this.options.width,y:this.options.height},h=c.x,u=c.y,v=this.rendererManager.getRenderer()?.getOffsets?.(),f={offsetX:v?.offsetX??0,offsetY:v?.offsetY??0};this.input.updateTouchZoneLayout(h,u,f);let C=U.collectMousePosition(this.input,i,h,u,f);e.setMousePosition(C.x,C.y,C.over),e.updateMacroMouse(C.x,C.y,C.isLeftDown),U.collectTouchPositions(this.input,i,h,u,10,f).forEach(g=>{e.setTouchPosition(g.id,g.x,g.y,g.over)});let y=this.rendererManagers.get(this.primaryDisplayId)?.getAvailableSize();y&&e.setDisplayViewport(this.primaryDisplayId,y.width,y.height)}let r=U.collectTextInputs(this.input);r.length>0&&e.setTextInputs(r);let s=e.getInputBindingRegistry(),n=s.getAllAxes(),o=s.getAllButtons();if(n.length>0||o.length>0){let a=U.collectAxisSources(n,this.input),l=U.collectButtonSourcesWithTransitions(o,this.input);n.forEach(c=>{let h=s.evaluateAxis(c.bindingId,a);e.setAxis(c.name,h)}),o.forEach(c=>{let h=new Map,u=new Map,m=new Map;for(let[b,p]of l)h.set(b,p.pressed),u.set(b,p.justPressed),m.set(b,p.justReleased);let v=s.evaluateButton(c.bindingId,h),f=s.evaluateButton(c.bindingId,u),C=s.evaluateButton(c.bindingId,m);e.setButton(c.name,v),e.setButton(`${c.name}_justPressed`,f),e.setButton(`${c.name}_justReleased`,C)})}this.input.poll?.()}collectAndSendInput(){!this.networkSync||!this.input||this.networkSync.sendInput(this.input)}render(){let e=this.core.getUser(this.userId);if(e){let i=e.getDisplays();for(let r of i){let s=r.getId(),n=this.rendererManagers.get(s);if(!n){console.warn(`[ClientRuntime] No renderer for display ${s}, skipping resize`);continue}let o=n.getRenderer();if(!o)continue;let a=r.getSize(),l,c,h,u,m=null;if("getGridSize"in o){let f=o,C=f.getGridSize();l=C.cols,c=C.rows,h=f.getCellWidth(),u=f.getCellHeight(),m=f.getScalingMode()}else if("getCols"in o){let f=o;l=f.getCols(),c=f.getRows(),h=f.getCellWidth(),u=f.getCellHeight(),m=f.getScalingMode()}else continue;if(m===ge.Responsive){let f=n.getAvailableSize(),C=256*256;"getMaxCells"in o&&(C=Math.min(C,o.getMaxCells()));let b=Math.floor(f.width/h),p=Math.floor(f.height/u);if(b=Math.min(256,Math.max(1,b)),p=Math.min(256,Math.max(1,p)),b*p>C){let y=Math.sqrt(C/(b*p));b=Math.max(1,Math.floor(b*y)),p=Math.max(1,Math.floor(p*y)),this.log(`\u26A0\uFE0F [Display ${s}] Device limit: max ${C} cells, clamping to ${b}\xD7${p}`)}(a.x!==b||a.y!==p)&&(this.log(`\u{1F4D0} [Display ${s}] Resizing display from ${a.x}\xD7${a.y} to ${b}\xD7${p} (available: ${f.width}\xD7${f.height}px, cell: ${h}\xD7${u}px)`),r.setSize(new fe(b,p)))}let v=r.getSize();(l!==v.x||c!==v.y)&&(this.log(`\u{1F4D0} [Display ${s}] Resizing renderer from ${l}\xD7${c} to ${v.x}\xD7${v.y}`),o.resize(v.x,v.y))}}super.render()}onFontChanged(e,i){let r=i??this.primaryDisplayId,s=this.postProcessOverlays.get(r)??this.postProcessOverlay;s&&"syncWithRenderer"in s&&"getCellWidth"in e&&"getCellHeight"in e&&"getCurrentScale"in e&&"getGridSize"in e&&(s.syncWithRenderer(e),this.log(`\u2713 PostProcessOverlay synced with renderer dimensions (display ${r})`))}getAudioManager(){return this.audioManager}getLayerTrafficStats(){return this.networkSync?.getLayerTrafficStats()??{}}getMiscTrafficStats(){return this.networkSync?.getMiscTrafficStats?.()??{}}getDisplayTrafficStats(){return this.networkSync?.getDisplayTrafficStats?.()??{}}getAudioContext(){return this.audioManager?.getContext()??null}getPostProcessOverlay(){return this.postProcessOverlay}applyAmbientEffectConfig(e,i){let r=this.rendererManagers.get(e)?.getRenderer();r&&"setAmbientEffect"in r&&(i.enabled?r.setAmbientEffect({blur:i.blur,scale:i.scale}):r.setAmbientEffect(!1),this.log(`[Display ${e}] Ambient effect ${i.enabled?"enabled":"disabled"}`))}applyPostProcessOrders(e){for(let i of e){let r=i.displayId??this.primaryDisplayId,s=this.postProcessOverlays.get(r)??this.postProcessOverlay,n=this.rendererManagers.get(r)?.getRenderer();switch(i.type){case P.SetConfig:{if(!s){console.warn(`[ClientRuntime] No PostProcessOverlay for display ${r}`);break}let o={};i.scanlines&&(o.scanlines={enabled:i.scanlines.enabled,opacity:i.scanlines.opacity,pattern:this.patternFromType(i.scanlines.pattern),color:{r:i.scanlines.colorR,g:i.scanlines.colorG,b:i.scanlines.colorB}}),i.ambientEffect&&(o.ambientEffect={enabled:i.ambientEffect.enabled,blur:i.ambientEffect.blur,scale:i.ambientEffect.scale}),s.setConfig(Object.keys(o).length>0?o:null),o.ambientEffect&&n&&this.applyAmbientEffectConfig(r,o.ambientEffect),this.log(`[Display ${r}] SetConfig applied`);break}case P.SetScanlines:{if(!s){console.warn(`[ClientRuntime] No PostProcessOverlay for display ${r}`);break}s.setScanlines({enabled:i.enabled,opacity:i.opacity,pattern:this.patternFromType(i.pattern),color:{r:i.colorR,g:i.colorG,b:i.colorB}}),this.log(`[Display ${r}] Scanlines ${i.enabled?"enabled":"disabled"}`);break}case P.SetAmbientEffect:{this.applyAmbientEffectConfig(r,{enabled:i.enabled,blur:i.blur,scale:i.scale}),this.log(`[Display ${r}] Ambient effect ${i.enabled?"enabled":"disabled"}`);break}case P.SetScalingMode:{this.applyScalingMode(r,i.mode);break}case P.SetGrid:{this.applyGridConfig(r,i);break}case P.SwitchPalette:{this.applySwitchPalette(r,i);break}case P.SetCellSize:{this.applyCellSize(r,i.cellWidth,i.cellHeight);break}}}}applyScalingMode(e,i){let r=this.rendererManagers.get(e)?.getRenderer();if(r&&"setScalingMode"in r){let s=me(i);r.setScalingMode(s),this.log(`[Display ${e}] Scaling mode set to ${s}`)}}applyGridConfig(e,i){let r=this.rendererManagers.get(e)?.getRenderer();if(r&&"setGrid"in r){let s=i.colorA/255;r.setGrid({enabled:i.enabled,color:`rgba(${i.colorR},${i.colorG},${i.colorB},${s})`,lineWidth:i.lineWidth}),this.log(`[Display ${e}] Grid ${i.enabled?"enabled":"disabled"}`)}}applySwitchPalette(e,i){let r=this.core.getPaletteFromSlot(i.slotId);if(!r){this.pendingPaletteSlotByDisplay.set(e,i.slotId),console.warn(`[ClientRuntime] Palette slot ${i.slotId} not found (display ${e}); will retry when available`);return}let s=[];for(let o=0;o<256;o++){let a=r.get(o);a?s.push({r:a.r,g:a.g,b:a.b,a:a.a}):s.push({r:0,g:0,b:0,a:0})}let n=this.rendererManagers.get(e)?.getRenderer();n&&"setPalette"in n&&(n.setPalette(s),this.log(`[Display ${e}] Switched to palette slot ${i.slotId}`)),this.pendingPaletteSlotByDisplay.get(e)===i.slotId&&this.pendingPaletteSlotByDisplay.delete(e)}retryPendingPaletteSelections(){if(this.pendingPaletteSlotByDisplay.size!==0)for(let[e,i]of this.pendingPaletteSlotByDisplay.entries()){let r=this.core.getPaletteFromSlot(i);if(!r)continue;let s=[];for(let o=0;o<256;o++){let a=r.get(o);a?s.push({r:a.r,g:a.g,b:a.b,a:a.a}):s.push({r:0,g:0,b:0,a:0})}let n=this.rendererManagers.get(e)?.getRenderer();n&&"setPalette"in n&&(n.setPalette(s),this.log(`[Display ${e}] Applied pending palette slot ${i}`),this.pendingPaletteSlotByDisplay.delete(e))}}applyCellSize(e,i,r){let s=this.rendererManagers.get(e)?.getRenderer();s&&"setCellSize"in s&&(s.setCellSize(i,r),this.log(`[Display ${e}] Cell size set to ${i}\xD7${r}px`))}patternFromType(e){switch(e){case 0:return"horizontal";case 1:return"vertical";case 2:return"grid";default:return"horizontal"}}dispatchLocalBridgeMessages(e){for(let i of e){let{channel:r,data:s}=i,n=this.localBridgeHandlers.get(r);if(n)for(let o of n)try{o(s)}catch(a){console.error(`[ClientRuntime] Bridge handler error on '${r}':`,a)}for(let o of this.localBridgeWildcardHandlers)try{o(r,s)}catch(a){console.error("[ClientRuntime] Bridge wildcard handler error:",a)}this.log(`Bridge message dispatched on channel '${r}'`)}}sendBridge(e,i){if(this.mode!=="standalone"&&this.networkSync)this.networkSync.sendBridge(e,i);else if(this.mode==="standalone"){let r=this.core.getUser(this.userId);r&&this.options.application?.onBridgeMessage&&(this.options.application.onBridgeMessage(this.core,r,e,i),this.log(`Bridge message sent to application on channel '${e}'`))}}onBridge(e,i){this.mode!=="standalone"&&this.networkSync?this.networkSync.onBridge(e,i):this.mode==="standalone"&&(e==="*"?this.localBridgeWildcardHandlers.add(i):(this.localBridgeHandlers.has(e)||this.localBridgeHandlers.set(e,new Set),this.localBridgeHandlers.get(e).add(i)),this.log(`Bridge handler registered for channel '${e}'`))}offBridge(e,i){this.mode!=="standalone"&&this.networkSync?this.networkSync.offBridge(e,i):this.mode==="standalone"&&(e==="*"?this.localBridgeWildcardHandlers.delete(i):this.localBridgeHandlers.get(e)?.delete(i))}removeAllBridgeHandlers(e){this.mode!=="standalone"&&this.networkSync?this.networkSync.removeAllBridgeHandlers(e):this.mode==="standalone"&&(e===void 0?(this.localBridgeHandlers.clear(),this.localBridgeWildcardHandlers.clear()):e==="*"?this.localBridgeWildcardHandlers.clear():this.localBridgeHandlers.delete(e))}log(e){this.options.debug&&console.warn(`[ClientRuntime/${this.mode}] ${e}`)}};S(H,"ClientRuntime");var W=H;import{UnifiedInputRouter as Re,InputCollector as O,MobileVibration as Ie}from"@utsp/input";var Q=class Q{constructor(t={}){d(this,"input");d(this,"mobileVibration");this.input=new Re({enableKeyboardMouse:!0,enableGamepad:!0,enableMobile:!0,targetElement:window,mobileTargetElement:void 0,debug:t.debug,keyboardConfig:{preventDefault:t.captureInput??!1,stopPropagation:t.captureInput??!1},mouseConfig:{preventDefault:t.captureInput??!1,stopPropagation:t.captureInput??!1},mobileConfig:{preventDefault:t.mobileInputConfig?.preventDefault??!1,passive:t.mobileInputConfig?.passive??!0,maxTouches:t.mobileInputConfig?.maxTouches??10}}),this.mobileVibration=new Ie({debug:t.debug})}setMobileTarget(t){this.input.setMobileTarget(t)}start(){this.input.start()}stop(){this.input.stop()}destroy(){this.input.destroy()}getRouter(){return this.input}getGamepad(){return this.input.getGamepad()}getMobileVibration(){return this.mobileVibration}collectAndApply(t,e,i,r,s){if(e){let c=O.collectMousePosition(this.input,e,i,r,s);t.setMousePosition(c.x,c.y,c.over),t.updateMacroMouse(c.x,c.y,c.isLeftDown),O.collectTouchPositions(this.input,e,i,r,10,s).forEach(u=>{t.setTouchPosition(u.id,u.x,u.y,u.over)})}let n=O.collectTextInputs(this.input);n.length>0&&t.setTextInputs(n);let o=t.getInputBindingRegistry(),a=o.getAllAxes(),l=o.getAllButtons();if(a.length>0||l.length>0){let c=O.collectAxisSources(a,this.input),h=O.collectButtonSourcesWithTransitions(l,this.input);a.forEach(u=>{let m=o.evaluateAxis(u.bindingId,c);t.setAxis(u.name,m)}),l.forEach(u=>{let m=new Map,v=new Map,f=new Map;for(let[y,g]of h)m.set(y,g.pressed),v.set(y,g.justPressed),f.set(y,g.justReleased);let C=o.evaluateButton(u.bindingId,m),b=o.evaluateButton(u.bindingId,v),p=o.evaluateButton(u.bindingId,f);t.setButton(u.name,C),t.setButton(`${u.name}_justPressed`,b),t.setButton(`${u.name}_justReleased`,p)})}this.input.poll?.()}processVibrationCommands(t){t.hasMobileVibrationCommands()&&t.applyMobileVibrationCommands(t.flushMobileVibrationCommands()),t.hasGamepadVibrationCommands()&&t.applyGamepadVibrationCommands(t.flushGamepadVibrationCommands())}};S(Q,"InputFeature");var q=Q;import{AudioManager as we}from"@utsp/audio";var Y=class Y{constructor(t={}){d(this,"audioManager");d(this,"debug");this.debug=t.debug??!1,this.audioManager=new we({debug:t.debug})}initialize(){this.audioManager.initialize()}playStartSound(){this.audioManager.playStartSound()}stopAll(){this.audioManager.stopAll()}destroy(){this.audioManager.destroy()}getManager(){return this.audioManager}getContext(){return this.audioManager.getContext()}injectIntoUser(t){t.setAudioProcessor(this.audioManager)}processAudioCommands(t){t.hasAudioConfigCommands()&&t.applyAudioConfigCommands(t.flushAudioConfigCommands()),t.hasSoundCommands()&&t.applyAudioCommands(t.flushSoundCommands())}async loadSoundsFromRegistry(t){let e=this.audioManager.getSoundBank();if(!e){this.log("Cannot load sounds: SoundBank not initialized");return}let r=t.getSoundRegistry().getAll();if(r.length===0){this.log("No sounds to load from registry");return}this.log(`Loading ${r.length} sounds from Core registry...`);for(let s of r)try{s.loadType==="file"&&s.data?(await e.loadFromData(s.soundId,s.name,s.data),this.log(`Loaded sound: ${s.name} (${s.data.length} bytes)`)):s.loadType==="external"&&s.url&&(await e.loadFromUrl(s.soundId,s.name,s.url),this.log(`Loaded external sound: ${s.name} from ${s.url}`))}catch(n){console.error(`[AudioFeature] Failed to load sound "${s.name}":`,n)}this.log(`${e.size} sounds loaded`)}log(t){this.debug&&console.warn(`[AudioFeature] ${t}`)}};S(Y,"AudioFeature");var K=Y;import{PostProcessOrderCollector as Me,PostProcessOrderType as B}from"@utsp/core";import{PostProcessOverlay as Te}from"@utsp/render";import{valueToScalingMode as Pe}from"@utsp/types";var N=class N{constructor(t,e={}){d(this,"overlay");d(this,"orderCollector");d(this,"debug");this.debug=e.debug??!1,this.overlay=new Te(t),this.orderCollector=new Me}destroy(){this.overlay.destroy()}getOverlay(){return this.overlay}syncWithRenderer(t){this.overlay.syncWithRenderer(t),this.log("Overlay synced with renderer dimensions")}processCommands(t,e){if(!t.hasPostProcessCommands())return;let i=t.flushPostProcessCommands(),r=this.orderCollector.convertCommands(i);this.applyOrders(r,e)}applyOrders(t,e){for(let i of t){let r=i.displayId;switch(i.type){case B.SetConfig:{let s={};i.scanlines&&(s.scanlines={enabled:i.scanlines.enabled,opacity:i.scanlines.opacity,pattern:this.patternFromType(i.scanlines.pattern),color:{r:i.scanlines.colorR,g:i.scanlines.colorG,b:i.scanlines.colorB}}),i.ambientEffect&&(s.ambientEffect={enabled:i.ambientEffect.enabled,blur:i.ambientEffect.blur,scale:i.ambientEffect.scale}),this.overlay.setConfig(Object.keys(s).length>0?s:null),s.ambientEffect&&this.applyAmbientEffect(e,s.ambientEffect),this.log(`[Display ${r}] SetConfig applied`);break}case B.SetScanlines:{this.overlay.setScanlines({enabled:i.enabled,opacity:i.opacity,pattern:this.patternFromType(i.pattern),color:{r:i.colorR,g:i.colorG,b:i.colorB}}),this.log(`[Display ${r}] Scanlines ${i.enabled?"enabled":"disabled"}`);break}case B.SetAmbientEffect:{this.applyAmbientEffect(e,{enabled:i.enabled,blur:i.blur,scale:i.scale}),this.log(`[Display ${r}] Ambient effect ${i.enabled?"enabled":"disabled"}`);break}case B.SetScalingMode:{this.applyScalingMode(e,r,i.mode);break}case B.SetGrid:{this.applyGridConfig(e,r,i);break}}}}applyAmbientEffect(t,e){t&&"setAmbientEffect"in t&&(e.enabled?t.setAmbientEffect({blur:e.blur,scale:e.scale}):t.setAmbientEffect(!1))}applyScalingMode(t,e,i){if(t&&"setScalingMode"in t){let r=Pe(i);t.setScalingMode(r),this.log(`[Display ${e}] Scaling mode set to ${r}`)}}applyGridConfig(t,e,i){if(t&&"setGrid"in t){let r=i.colorA/255;t.setGrid({enabled:i.enabled,color:`rgba(${i.colorR},${i.colorG},${i.colorB},${r})`,lineWidth:i.lineWidth}),this.log(`[Display ${e}] Grid ${i.enabled?"enabled":"disabled"}`)}}patternFromType(t){switch(t){case 0:return"horizontal";case 1:return"vertical";case 2:return"grid";default:return"horizontal"}}log(t){this.debug&&console.warn(`[PostProcessFeature] ${t}`)}};S(N,"PostProcessFeature");var j=N;import{ScalingMode as Pt}from"@utsp/render";import{NetworkTransportType as Et}from"@utsp/types";import{AudioManager as Ot}from"@utsp/audio";export{K as AudioFeature,Ot as AudioManager,F as BaseClientRuntime,W as ClientRuntime,T as DEFAULT_ATLAS_CONFIG,q as InputFeature,Et as NetworkTransportType,j as PostProcessFeature,k as RendererManager,re as RendererType,Pt as ScalingMode,$ as decodeDefaultAtlas};
|
|
1
|
+
var ie=Object.defineProperty;var ne=(I,e,t)=>e in I?ie(I,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):I[e]=t;var R=(I,e)=>ie(I,"name",{value:e,configurable:!0});var l=(I,e,t)=>(ne(I,typeof e!="symbol"?e+"":e,t),t);import{Core as oe}from"@utsp/core";import{TerminalGL as ae,Terminal2D as le}from"@utsp/render";var re=(t=>(t.TerminalGL="webgl",t.Terminal2D="terminal2d",t))(re||{});var D=class D{constructor(e=60){l(this,"frameCount",0);l(this,"fps",0);l(this,"fpsUpdateTime",0);l(this,"lastCoreTime",0);l(this,"lastRenderTime",0);l(this,"lastTotalTime",0);l(this,"coreTimeSamples",[]);l(this,"renderTimeSamples",[]);l(this,"totalTimeSamples",[]);l(this,"maxSamples");if(e<=0)throw new Error("maxSamples must be positive");this.maxSamples=e}startTracking(e){this.fpsUpdateTime=e,this.frameCount=0,this.fps=0}updateFPS(e){this.frameCount++,e-this.fpsUpdateTime>=1e3&&(this.fps=Math.round(this.frameCount*1e3/(e-this.fpsUpdateTime)),this.frameCount=0,this.fpsUpdateTime=e)}recordFrameTiming(e,t){let i=e+t;this.lastCoreTime=e,this.lastRenderTime=t,this.lastTotalTime=i,this.coreTimeSamples.push(e),this.renderTimeSamples.push(t),this.totalTimeSamples.push(i),this.coreTimeSamples.length>this.maxSamples&&(this.coreTimeSamples.shift(),this.renderTimeSamples.shift(),this.totalTimeSamples.shift())}getFPS(){return this.fps}getLastFrameTiming(){if(!(this.lastCoreTime===0&&this.lastRenderTime===0))return{coreTime:this.lastCoreTime,renderTime:this.lastRenderTime,totalTime:this.lastTotalTime}}getAverageFrameTiming(){if(this.coreTimeSamples.length!==0)return{coreTime:this.average(this.coreTimeSamples),renderTime:this.average(this.renderTimeSamples),totalTime:this.average(this.totalTimeSamples)}}getStats(){return{fps:this.fps,lastFrame:this.getLastFrameTiming(),avgFrame:this.getAverageFrameTiming(),sampleCount:this.coreTimeSamples.length,maxSamples:this.maxSamples}}reset(){this.frameCount=0,this.fps=0,this.fpsUpdateTime=0,this.lastCoreTime=0,this.lastRenderTime=0,this.lastTotalTime=0,this.coreTimeSamples=[],this.renderTimeSamples=[],this.totalTimeSamples=[]}average(e){return e.length===0?0:e.reduce((t,i)=>t+i,0)/e.length}};R(D,"PerformanceMonitor");var O=D;var se="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",T={glyphWidth:8,glyphHeight:8,cellWidth:8,cellHeight:8,atlasBlocks:1,atlasWidth:128,atlasHeight:128};function K(){if(typeof atob=="function"){let I=atob(se),e=new Uint8Array(I.length);for(let t=0;t<I.length;t++)e[t]=I.charCodeAt(t);return e}throw new Error("[UTSP] decodeDefaultAtlas: atob() is not available in this environment")}R(K,"decodeDefaultAtlas");var L=class L{constructor(e,t={}){l(this,"renderer");l(this,"options");l(this,"layerFilter",null);this.renderer=e,this.options={debug:t.debug??!1,useImageDataRendering:t.useImageDataRendering??!1}}setLayerFilter(e){this.layerFilter=e}getLayerFilter(){return this.layerFilter}async initialize(e){if("setImageDataRendering"in this.renderer&&this.options.useImageDataRendering&&(this.renderer.setImageDataRendering(!0),this.log("ImageData rendering enabled")),"setImageFont"in this.renderer&&typeof this.renderer.setImageFont=="function"){this.log("Loading default 8x8 font atlas...");let t=K();await this.renderer.setImageFont(t,T.glyphWidth,T.glyphHeight,T.cellWidth,T.cellHeight,T.atlasBlocks),this.log("Default 8x8 font atlas loaded")}await this.waitForReady(),this.log("Initialized and ready")}async waitForReady(e=100,t=50){this.log("Waiting for renderer to be ready");let i=0;return new Promise((r,s)=>{let n=R(()=>{if(i++,this.renderer.isReady())this.log(`Renderer ready after ${i*t}ms`),r();else if(i>=e){let a=`Renderer failed to be ready after ${e*t}ms`;this.log(a),s(new Error(a))}else setTimeout(n,t)},"check");n()})}async loadDefaultFont(e){console.warn("[RendererManager] loadDefaultFont() is deprecated. Use ImageFont instead.")}renderDisplay(e){return this.renderer.isReady()?e?(this.renderer.renderDisplayData(e),!0):(console.warn("[RENDERER MANAGER] No display provided"),!1):(console.warn("[RENDERER MANAGER] Renderer not ready"),!1)}render(e,t){let i=this.layerFilter?e.getRenderState(t,this.layerFilter):e.getRenderState(t);return!i||i.displays.length===0?(console.warn("[RENDERER MANAGER] No render state or no displays"),!1):this.renderDisplay(i.displays[0])}getRenderer(){return this.renderer}getCanvas(){return this.renderer.getCanvas()}getAvailableSize(){if(this.renderer.getAvailableSize)return this.renderer.getAvailableSize();let e=this.getCanvas();return{width:e?.clientWidth||e?.width||0,height:e?.clientHeight||e?.height||0}}isReady(){return this.renderer.isReady()}destroy(){this.log("Destroying renderer"),this.renderer.destroy()}log(e){this.options.debug&&console.warn(`[RendererManager] ${e}`)}};R(L,"RendererManager");var E=L;var q=class q{constructor(e){l(this,"core");l(this,"rendererManagers",new Map);l(this,"rendererInitPromises",new Map);l(this,"rendererManager");l(this,"rendererType");l(this,"primaryDisplayId",0);l(this,"displayConfigs");l(this,"options");l(this,"running",!1);l(this,"startTime",0);l(this,"lastTimestamp",0);l(this,"userId","");l(this,"visibilityChangeHandler");l(this,"tickRate",30);l(this,"accumulatedTime",0);l(this,"FRAME_TIME_MIN",1e3/60);l(this,"lastRenderTimestamp",0);l(this,"rafId",0);l(this,"firstTickDone",!1);l(this,"performanceMonitor");l(this,"renderMode","continuous");l(this,"renderRequested",!1);if(this.options={application:e.application,container:e.container,displayContainers:e.displayContainers,debug:e.debug??!1,width:e.width??80,height:e.height??25,renderer:e.renderer??"webgl",useImageDataRendering:e.useImageDataRendering??!0,renderMode:e.renderMode??"continuous"},this.log("Initializing BaseClientRuntime"),this.core=new oe({mode:"client",maxUsers:1}),this.core.onPaletteChanged(t=>{this.onCorePaletteChanged(t)}),this.core.onFontAllocated(()=>{this.onCoreImageFontAllocated(0)}),this.core.onFontBlockAdded(t=>{this.onCoreImageFontBlockAdded(0,t)}),this.core.onImageFontChanged(t=>{this.onCoreImageFontChanged(t)}),this.visibilityChangeHandler=()=>{!document.hidden&&this.running&&(this.lastTimestamp=performance.now(),this.accumulatedTime=0,this.log("Tab visible: Reset timing"))},document.addEventListener("visibilitychange",this.visibilityChangeHandler),this.rendererType=this.options.renderer,this.options.displayContainers&&this.options.displayContainers.length>0){this.displayConfigs=new Map([[0,{container:this.options.container,renderer:this.options.renderer}]]);for(let t of this.options.displayContainers){let i=t.renderer;this.displayConfigs.set(t.id,{container:t.container,renderer:i})}this.primaryDisplayId=0}else this.displayConfigs=new Map([[0,{container:this.options.container,renderer:this.options.renderer}]]),this.primaryDisplayId=0;this.createRendererManagers(),this.performanceMonitor=new O(60),this.tickRate=20,this.renderMode=e.renderMode??"continuous",this.log(`Configured: tickRate=${this.tickRate}, renderMode=${this.renderMode}`),this.log("BaseClientRuntime initialized")}createRenderer(e,t){if(t==="terminal2d"){this.log("Creating Terminal 2D renderer");let n=new le(e,{fixedCols:this.options.width,fixedRows:this.options.height,cellAspectRatio:1});return this.log("Canvas 2D renderer created successfully"),n}this.log("Creating TerminalGL renderer");let r=document.createElement("canvas").getContext("webgl");if(!r)throw new Error("WebGL not supported. TerminalGL requires WebGL 1.0.");if(!r.getExtension("OES_element_index_uint"))throw new Error("OES_element_index_uint extension not supported. TerminalGL requires this extension for large terminals (256x256).");if(!(e instanceof HTMLDivElement))throw new Error(`TerminalGL requires container to be an HTMLDivElement. Received: ${e.tagName}`);let s=new ae(e,{cols:this.options.width,rows:this.options.height,charWidth:8,charHeight:8});return this.log("TerminalGL created successfully"),s}createRendererManagers(){let e=this.displayConfigs.size>=3;this.rendererManagers.clear();for(let[i,r]of this.displayConfigs.entries()){let s=e?"terminal2d":r.renderer??this.options.renderer,n=this.createRenderer(r.container,s??"webgl"),o=new E(n,{debug:this.options.debug,useImageDataRendering:this.options.useImageDataRendering});this.rendererManagers.set(i,o)}let t=this.rendererManagers.get(this.primaryDisplayId);if(!t)throw new Error(`Primary display ${this.primaryDisplayId} has no renderer. Check displayContainers configuration.`);this.rendererManager=t}ensureRendererManager(e){let t=this.rendererManagers.get(e);if(t)return t;let i=document.createElement("div");i.dataset.displayId=String(e),i.style.cssText="position:relative;display:inline-block;margin:4px;background:#000;overflow:hidden;",(this.options.container?.parentElement??document.body).appendChild(i),this.displayConfigs.set(e,{container:i});let o=this.displayConfigs.size>=3?"terminal2d":this.options.renderer??"webgl",a=this.createRenderer(i,o),c=new E(a,{debug:this.options.debug,useImageDataRendering:this.options.useImageDataRendering});if(this.rendererManagers.set(e,c),!this.rendererInitPromises.has(e)){let d=c.initialize(this.core).then(()=>{this.onCorePaletteChanged(this.core.getPalette());let u=this.core.getImageFontIds,h=typeof u=="function"?u.call(this.core):[];h.length>0&&this.onCoreImageFontChanged(h[0]);let m=this.rebuildPostProcessOverlays;typeof m=="function"&&m.call(this)}).catch(u=>{console.warn(`[BaseClientRuntime] Failed to init renderer for display ${e}:`,u)});this.rendererInitPromises.set(e,d)}return c}getRendererType(){return this.rendererType}isRunning(){return this.running}setTickRate(e){if(e<0||e>1e3)throw new Error(`Invalid tick rate: ${e}. Must be between 0 and 1000.`);if(this.tickRate=e,this.userId){let t=this.core.getUser(this.userId);t&&t.setBytesTickRate(e>0?e:20)}e===0&&this.renderMode==="continuous"?(this.renderMode="on-demand",this.log("Tick rate set to 0, switched to on-demand render mode")):this.log(`Tick rate set to ${e} TPS`)}setRenderMode(e){this.renderMode=e,this.log(`Render mode set to ${e}`)}setMaxFPS(e){if(e<=0||e>240)throw new Error(`Invalid FPS: ${e}. Must be between 1 and 240.`);this.FRAME_TIME_MIN=1e3/e,this.log(`Max FPS set to ${e}`)}getTickRate(){return this.tickRate}requestRender(){this.renderMode==="on-demand"&&(this.renderRequested=!0,this.log("Render requested"))}async start(){if(this.running){this.log("Already running");return}this.log("Starting BaseClientRuntime"),await this.onBeforeStart();for(let[e,t]of this.rendererManagers.entries())await t.initialize(this.core),this.log(`Renderer for display ${e} is ready`);this.onCorePaletteChanged(this.core.getPalette()),this.log("Initial palette sent to renderers"),this.options.application&&(this.log("Calling application.init()"),await this.options.application.init(this.core,this)),await this.onAfterInit(),await this.createLocalUser(),this.running=!0,this.startTime=performance.now(),this.lastTimestamp=this.startTime,this.lastRenderTimestamp=this.startTime,this.accumulatedTime=0,this.firstTickDone=!1,this.performanceMonitor.reset(),this.performanceMonitor.startTracking(this.startTime),this.log("Starting main loop"),this.mainLoop(this.lastTimestamp)}async onBeforeStart(){}async onAfterInit(){}async stop(){if(!this.running)return;this.log("Stopping BaseClientRuntime"),this.running=!1,this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0),await this.onStop();let e=this.core.getUser(this.userId);e&&this.options.application?.destroyUser&&this.options.application.destroyUser(this.core,e,"Runtime stopped"),this.log("BaseClientRuntime stopped")}async onStop(){}getStats(){let e=this.performanceMonitor.getStats();return{running:this.running,userCount:this.core.getUsers().length,fps:e.fps,uptime:this.running?performance.now()-this.startTime:0,totalFrames:0,lastFrameTiming:e.lastFrame,avgFrameTiming:e.avgFrame}}getTotalBytesReceived(){return this.core.getUser(this.userId)?.getTotalBytesReceived()??0}getBytesReceivedPerSecond(){return this.core.getUser(this.userId)?.getBytesReceivedPerSecond()??0}resetBytesReceived(){let e=this.core.getUser(this.userId);e&&e.resetByteCounters()}async destroy(){await this.stop(),this.log("Destroying BaseClientRuntime"),this.visibilityChangeHandler&&(document.removeEventListener("visibilitychange",this.visibilityChangeHandler),this.visibilityChangeHandler=void 0),await this.onDestroy();for(let e of this.rendererManagers.values()){let t=e.getRenderer();t&&"clearOnResizeCallback"in t&&t.clearOnResizeCallback()}this.options.application?.destroy&&this.options.application.destroy();for(let e of this.rendererManagers.values())e.destroy();this.log("BaseClientRuntime destroyed")}async onDestroy(){}async createLocalUser(){this.userId="local",this.log(`Creating local user: ${this.userId}`);let e=this.core.createUser(this.userId,"User");e.setBytesTickRate(this.tickRate>0?this.tickRate:20),this.onUserCreated(e),this.options.application?.initUser&&(this.log("Calling application.initUser()"),this.options.application.initUser(this.core,e,{username:"User"})),this.processInitialOrders(e);let t=this.core.generateAllLoadPackets();t.forEach(n=>{e.recordBytesReceived(n.length)});let i=this.core.generateMacroLoadPackets(this.userId);i.forEach(n=>{e.recordBytesReceived(n.length)});let r=e.getInputBindingsLoadPacket();r&&e.recordBytesReceived(r.length),this.log(`Simulated ${t.length} load packets, ${i.length} macro packets for byte counting`),this.log("Performing initial render"),this.core.endTick().forEach(({static:n,dynamic:o},a)=>{let c=this.core.getUser(a);c&&(n&&c.recordBytesReceived(n.length),o&&c.recordBytesReceived(o.length))})}processInitialOrders(e){if(e.hasPendingMacroOrders()){this.log("Applying macro orders from initUser()");let t=e.flushMacroOrders();e.applyMacroOrders(t)}}onUserCreated(e){}mainLoop(e){if(!this.running){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0);return}if(this.renderMode==="on-demand"){this.renderRequested&&(this.renderRequested=!1,this.performanceMonitor.updateFPS(e),this.render()),this.rafId=requestAnimationFrame(c=>this.mainLoop(c));return}let t=e-this.lastRenderTimestamp;if(this.lastRenderTimestamp>0&&t<this.FRAME_TIME_MIN-1){this.rafId=requestAnimationFrame(c=>this.mainLoop(c));return}this.lastRenderTimestamp=e;let i=(e-this.lastTimestamp)/1e3,r=Math.min(i,.1);this.lastTimestamp=e,this.performanceMonitor.updateFPS(e);let s=this.core.getUser(this.userId);if(!s){this.rafId=requestAnimationFrame(c=>this.mainLoop(c));return}if(this.tickRate===0){let c=performance.now();this.render();let d=performance.now()-c;this.performanceMonitor.recordFrameTiming(0,d),this.rafId=requestAnimationFrame(u=>this.mainLoop(u));return}if(!this.firstTickDone){this.firstTickDone=!0,this.lastTimestamp=e,this.accumulatedTime=0,this.rafId=requestAnimationFrame(c=>this.mainLoop(c));return}this.accumulatedTime+=r;let n=1/this.tickRate;this.accumulatedTime>.5&&(this.accumulatedTime=n);let o=0,a=0;for(;this.accumulatedTime>=n&&o<5;){let c=performance.now();this.collectAndApplyInput(s),this.options.application&&(this.options.application.update?.(this.core,n),this.options.application.updateUser?.(this.core,s,n)),this.processTickOrders(s);let d=s.updateMacros();s.processMacroEvents(d),this.core.endTick().forEach(({static:h,dynamic:m})=>{let C=(h?.length??0)+(m?.length??0);s.recordBytesReceived(C)}),a+=performance.now()-c,this.accumulatedTime-=n,o++}if(o>0){let c=performance.now();this.render();let d=performance.now()-c;this.performanceMonitor.recordFrameTiming(a,d)}this.rafId=requestAnimationFrame(c=>this.mainLoop(c))}collectAndApplyInput(e){}processTickOrders(e){if(e.clearTextInputs(),e.hasPendingMacroOrders()){let t=e.flushMacroOrders();e.applyMacroOrders(t)}}render(){let e=this.core.getUser(this.userId);if(e){let i=e.getMacroRenderOrders();for(let[r,s]of i){let n=e.getLayerById(r);n&&s.length>0&&n.addTemporaryOrders(s)}}let t=this.core.getRenderState(this.userId);if(!t||t.displays.length===0){console.warn("[BaseClientRuntime] No render state or displays");return}for(let i of t.displays){let r=this.rendererManagers.get(i.id)??this.ensureRendererManager(i.id);if(!r){console.warn(`[BaseClientRuntime] No renderer manager for display ${i.id}, skipping render`);continue}let s=r.getLayerFilter(),n=s?this.core.getRenderState(this.userId,s):t;if(!n){this.options.debug&&this.log(`Render state unavailable for display ${i.id} with filter`);continue}let o=n.displays.find(a=>a.id===i.id);if(!o){this.options.debug&&this.log(`Render state missing display ${i.id} after filtering`);continue}if(!r.isReady()){this.options.debug&&this.log(`Renderer for display ${i.id} not ready yet`);continue}r.renderDisplay(o)}}onCorePaletteChanged(e){this.log(`Palette changed, updating renderer (${e.size} colors)`);let t=[];for(let s=0;s<256;s++){let n=e.get(s);n?t.push({r:n.r,g:n.g,b:n.b,a:n.a}):t.push({r:0,g:0,b:0,a:0})}let i=R(s=>{s&&"setPalette"in s&&typeof s.setPalette=="function"&&s.setPalette(t)},"applyPalette"),r=0;for(let s of this.rendererManagers.values()){let n=s.getRenderer();n&&(i(n),r++)}r===0?console.warn("[BaseClientRuntime] Cannot update palette: no renderer available"):this.log(`\u2713 Palette updated on ${r} renderer(s)`)}onCoreImageFontAllocated(e){let t=this.core.getImageFont(e);if(!t)return;this.log(`Allocating image font ${e} structure: blocks=${t.getAtlasBlocks()}, size=${t.getGlyphWidth()}x${t.getGlyphHeight()}`);let i=R(r=>{r&&typeof r.setImageFontStructure=="function"&&r.setImageFontStructure(t.getGlyphWidth(),t.getGlyphHeight(),t.getCellWidth(),t.getCellHeight(),t.getAtlasBlocks())},"applyStruct");for(let r of this.rendererManagers.values()){let s=r.getRenderer();s&&i(s)}}onCoreImageFontBlockAdded(e,t){let i=this.core.getImageFont(e);if(!i)return;let r=i.getBlock(t);if(!r)return;let s=R(n=>{n&&typeof n.setImageFontBlock=="function"&&n.setImageFontBlock(t,r)},"applyBlock");for(let n of this.rendererManagers.values()){let o=n.getRenderer();o&&s(o)}}onCoreImageFontChanged(e){this.log(`Image font ${e} changed (legacy event), updating renderer`),this.onCoreImageFontAllocated(e);let t=this.core.getImageFont(e);if(!t)return;let i=t.getAtlasBlocks();for(let r=0;r<i;r++)t.getBlock(r)&&this.onCoreImageFontBlockAdded(e,r);for(let[r,s]of this.rendererManagers.entries()){let n=s.getRenderer();n&&this.onFontChanged(n,r)}}onFontChanged(e,t){}log(e){this.options.debug&&console.warn(`[BaseClientRuntime] ${e}`)}getCore(){return this.core}getRendererManager(e=this.primaryDisplayId){let t=this.rendererManagers.get(e);if(!t)throw new Error(`Renderer manager for display ${e} not found`);return t}setDisplayContainers(e){this.displayConfigs=new Map(e.map(i=>[i.id,{container:i.container}]));let t=Array.from(this.displayConfigs.keys());this.primaryDisplayId=t.length>0?Math.min(...t):0;for(let i of this.rendererManagers.values())i.destroy();this.rendererManagers.clear(),this.createRendererManagers()}getUserId(){return this.userId}};R(q,"BaseClientRuntime");var k=q;import{Core as ce,PostProcessOrderType as F,PostProcessOrderCollector as he}from"@utsp/core";import{AutoplayOverlay as ue,PostProcessOverlay as pe}from"@utsp/render";import{ScalingMode as ge,valueToScalingMode as me,Vector2 as fe}from"@utsp/types";import{UnifiedInputRouter as ye,InputCollector as P,MobileVibration as be}from"@utsp/input";import{SocketIOClient as Ce,WebRTCClient as Se}from"@utsp/network-client";import{AudioManager as Re}from"@utsp/audio";import{encodeCompressedInput as de}from"@utsp/core";import{InputCollector as A}from"@utsp/input";var w=1e3,Q=class Q{constructor(e,t,i,r,s,n,o){l(this,"network");l(this,"core");l(this,"rendererManagers");l(this,"primaryDisplayId");l(this,"performanceMonitor");l(this,"options");l(this,"layerTraffic",new Map);l(this,"miscTraffic",new Map);l(this,"displayTraffic",new Map);l(this,"audioManager",null);l(this,"postProcessCallback",null);l(this,"soundHandlersSetup",!1);l(this,"userId","");l(this,"lastReceivedTick",-1);l(this,"connected",!1);l(this,"totalBytesReceived",0);l(this,"lastSentViewports",new Map);l(this,"lastCollectedTouches",[]);l(this,"touchZonesCallback",null);l(this,"audioLoadingState",{totalExpected:0,loadedSounds:new Set,errors:new Map});l(this,"ensureRendererManager");this.network=e,this.core=t,this.rendererManagers=i,this.primaryDisplayId=n,this.performanceMonitor=r,this.ensureRendererManager=o,this.options={serverUrl:s.serverUrl,username:s.username,token:s.token??"",debug:s.debug??!1,autoReconnect:s.autoReconnect??!0,canvasWidth:s.canvasWidth,canvasHeight:s.canvasHeight}}getRendererManager(e){return this.rendererManagers.get(e)}getPrimaryRendererManager(){return this.rendererManagers.get(this.primaryDisplayId)??Array.from(this.rendererManagers.values())[0]}renderDisplays(){let e=this.core.getRenderState(this.userId);if(!e||e.displays.length===0){this.options.debug&&this.log("Render skipped: no render state or displays");return}for(let t of e.displays){let i=this.getRendererManager(t.id)??this.ensureRendererManager?.(t.id);if(!i){console.warn(`[NetworkSync] No renderer manager for display ${t.id}, skipping render`);continue}let r=i.getLayerFilter?.(),s=r?this.core.getRenderState(this.userId,r):e;if(!s){this.options.debug&&this.log(`Render state unavailable for display ${t.id} with filter`);continue}let n=s.displays.find(o=>o.id===t.id);if(!n){this.options.debug&&this.log(`Render state missing display ${t.id} after filtering`);continue}if(!i.isReady()){this.options.debug&&this.log(`Renderer for display ${t.id} not ready yet`);continue}i.renderDisplay(n)}}async connect(){this.log(`Connecting to ${this.options.serverUrl}`),await this.network.connect(),this.connected=!0,this.log("Connected to server"),this.setupNetworkHandlers()}async joinGame(e){return new Promise((t,i)=>{this.network.send("join",{username:this.options.username,token:this.options.token}),this.network.on("join_response",r=>{if(r.success){this.userId=r.userId,this.log(`Joined game as ${this.userId}`);let s=this.core.createUser(this.userId,this.options.username);s.setBytesTickRate(20),this.audioManager&&s.setAudioProcessor(this.audioManager),e?.initUser&&e.initUser(this.core,s,{username:this.options.username,token:this.options.token}),t(this.userId)}else i(new Error(r.error||"Failed to join game"))}),setTimeout(()=>i(new Error("Join timeout")),5e3)})}sendInput(e){let t=this.core.getUser(this.userId);if(!t)return;let i=this.getPrimaryRendererManager(),r=i?.getCanvas();if(r){let g=t.getDisplays(),N=(g.find(M=>M.getId&&M.getId()===this.primaryDisplayId)??g[0])?.getSize()??{x:this.options.canvasWidth,y:this.options.canvasHeight},X=N.x,Z=N.y,_=i?.getRenderer()?.getOffsets?.(),ee={offsetX:_?.offsetX??0,offsetY:_?.offsetY??0},U=A.collectMousePosition(e,r,X,Z,ee);t.setMousePosition(U.x,U.y,U.over),t.updateMacroMouse(U.x,U.y,U.isLeftDown);let te=A.collectTouchPositions(e,r,X,Z,10,ee);te.forEach(M=>{t.setTouchPosition(M.id,M.x,M.y,M.over)}),this.lastCollectedTouches=te}else this.lastCollectedTouches=[];let s=t.getInputBindingRegistry(),n=s.getAllAxes(),o=s.getAllButtons(),a=A.collectAxisSources(n,e),c=A.collectButtonSources(o,e),d=A.collectTextInputs(e);d.length>0&&t.setTextInputs(d);let u=n.sort((g,v)=>g.bindingId-v.bindingId),h=new Map;for(let g of u){let v=s.evaluateAxis(g.bindingId,a);h.set(g.bindingId,v),t.setAxis(g.name,v)}let m=o.sort((g,v)=>g.bindingId-v.bindingId),C=new Map;for(let g of m){let v=s.evaluateButton(g.bindingId,c);C.set(g.bindingId,v),t.setButton(g.name,v)}let f=t.getMouseDisplayInfo(),S=t.getIsMouseOnADisplay(),b=this.collectChangedViewports(),p=this.lastCollectedTouches.map(g=>({id:g.id,x:g.x,y:g.y,over:g.over})),y=de(0n,h,C,f?.displayId??0,f?.localX??0,f?.localY??0,S,d,[],b,p);this.network.send("input",y)}collectChangedViewports(){let e=[];for(let[t,i]of this.rendererManagers.entries()){let{width:r,height:s}=i.getAvailableSize();if(r===0||s===0)continue;let n=this.lastSentViewports.get(t);(!n||n.pixelWidth!==r||n.pixelHeight!==s)&&(e.push({displayId:t,pixelWidth:r,pixelHeight:s}),this.lastSentViewports.set(t,{pixelWidth:r,pixelHeight:s}),this.log(`Viewport changed: display ${t} = ${r}x${s}px`))}return e}disconnect(){this.connected&&(this.network.send("leave",{}),this.network.disconnect(),this.connected=!1,this.soundHandlersSetup=!1,this.log("Disconnected from server"))}getUserId(){return this.userId}isConnected(){return this.connected}getTotalBytesReceived(){return this.totalBytesReceived}getAudioLoadingState(){let e=this.audioLoadingState.loadedSounds.size,t=this.audioLoadingState.totalExpected,i=this.audioLoadingState.errors.size,r=t>0&&e>=t,s=Array.from(this.audioLoadingState.errors.keys());return{loadedCount:e,totalExpected:t,errorCount:i,isComplete:r,errors:s}}destroy(){this.disconnect(),this.network.destroy(),this.log("NetworkSync destroyed")}setupNetworkHandlers(){this.network.on("update",e=>{try{let t=this.convertToUint8Array(e,"update");if(!t)return;this.recordBytesReceived(t.length);let i=this.core.applyUpdatePacketBuffer(this.userId,t);i?(this.postProcessCallback&&i.postProcessOrders&&i.postProcessOrders.length>0&&this.postProcessCallback(i.postProcessOrders),this.renderDisplays()):this.log("Failed to apply update packet")}catch(t){this.log(`Error applying update packet: ${t}`)}}),this.network.on("update-static",e=>{this.handleUpdatePacket(e,"update-static")}),this.network.on("update-dynamic",e=>{this.handleUpdatePacket(e,"update-dynamic")}),this.network.on("load",e=>{try{let t=this.convertToUint8Array(e,"load");if(!t)return;this.recordBytesReceived(t.length),this.core.applyLoadPacket(t)?this.log("Load packet applied successfully"):this.log("Failed to apply load packet")}catch(t){this.log(`Error applying load packet: ${t}`)}}),this.network.on("input-bindings",e=>{if(this.recordBytesReceived(e.length),this.core.applyInputBindingsLoadPacket(this.userId,e)){this.log("Input bindings configured");try{let i=JSON.parse(e);if(this.log(`Touch zones in packet: ${i.touchZones?.length??0}, callback defined: ${!!this.touchZonesCallback}`),i.touchZones&&i.touchZones.length>0&&this.touchZonesCallback){let r=i.touchZones.map(s=>({id:s.zoneId,x:s.x,y:s.y,width:s.width,height:s.height}));this.touchZonesCallback(r),this.log(`Touch zones configured: ${r.length} zones`)}}catch{}}else this.log("Failed to apply input bindings")}),this.audioManager&&this.setupSoundHandlers(),this.network.on("disconnect",()=>{this.connected=!1,this.soundHandlersSetup=!1,this.log("Disconnected from server")})}handleUpdatePacket(e,t){try{let i=this.convertToUint8Array(e,t);if(!i)return;this.recordBytesReceived(i.length);let r=new DataView(i.buffer,i.byteOffset,i.byteLength),s=Number(r.getBigUint64(0,!1));if(t==="update-dynamic"&&s<this.lastReceivedTick)return;s>this.lastReceivedTick&&(this.lastReceivedTick=s);let n=this.core.applyUpdatePacketBuffer(this.userId,i);if(n){let o=performance.now(),a=R((b,p)=>{if(p<=0)return;let y=this.miscTraffic.get(b)??{total:0,windowSum:0,samples:[]};y.total+=p,y.windowSum+=p,y.samples.push({time:o,bytes:p}),this.miscTraffic.set(b,y)},"recordMisc"),c=R(b=>{try{return JSON.stringify(b).length}catch{return 0}},"safeLen"),d=n.__byteSizes,u=d?.audioOrders;typeof u=="number"?a("update.audioOrders",u):n.audioOrders&&n.audioOrders.length&&a("update.audioOrders",c(n.audioOrders));let h=d?.vibrationOrders;typeof h=="number"?a("update.vibrationOrders",h):n.vibrationOrders&&n.vibrationOrders.length&&a("update.vibrationOrders",c(n.vibrationOrders));let m=d?.macroOrders;typeof m=="number"?a("update.macroOrders",m):n.macroOrders&&n.macroOrders.length&&a("update.macroOrders",c(n.macroOrders));let C=d?.postProcessOrders;if(typeof C=="number"?a("update.postProcessOrders",C):n.postProcessOrders&&n.postProcessOrders.length&&a("update.postProcessOrders",c(n.postProcessOrders)),n.displays&&n.displays.length)for(let b of n.displays){let p=b.id;if(typeof p!="number")continue;let y=this.displayTraffic.get(p)??{total:0,windowSum:0,samples:[]},g=7;y.total+=g,y.windowSum+=g,y.samples.push({time:o,bytes:g}),this.displayTraffic.set(p,y)}for(let b of n.layers){let p=b.byteSize??0,y=this.layerTraffic.get(b.id)??{total:0,windowSum:0,samples:[]};y.total+=p,y.windowSum+=p,y.samples.push({time:o,bytes:p});let g=o-w;for(;y.samples.length&&y.samples[0].time<g;){let v=y.samples.shift();v&&(y.windowSum-=v.bytes)}this.layerTraffic.set(b.id,y)}{let b=o-w;this.miscTraffic.forEach((p,y)=>{for(;p.samples.length&&p.samples[0].time<b;){let g=p.samples.shift();g&&(p.windowSum-=g.bytes)}p.windowSum<0&&(p.windowSum=0),this.miscTraffic.set(y,p)})}{let b=o-w;this.displayTraffic.forEach((p,y)=>{for(;p.samples.length&&p.samples[0].time<b;){let g=p.samples.shift();g&&(p.windowSum-=g.bytes)}p.windowSum<0&&(p.windowSum=0),this.displayTraffic.set(y,p)})}this.postProcessCallback&&n.postProcessOrders&&n.postProcessOrders.length>0&&this.postProcessCallback(n.postProcessOrders),this.options.debug&&this.debugRenderState();let f=performance.now();this.renderDisplays();let S=performance.now()-f;this.performanceMonitor.recordFrameTiming(0,S),this.options.debug&&console.warn(`[CLIENT] render() completed for ${t} (${S.toFixed(2)}ms)`)}else this.options.debug&&this.log(`Failed to apply ${t} packet (tick ${s})`)}catch(i){this.log(`Error applying ${t} update packet: ${i}`),console.error(i)}}convertToUint8Array(e,t){return e instanceof Uint8Array?e:e instanceof ArrayBuffer?new Uint8Array(e):Array.isArray(e)?new Uint8Array(e):e.data&&Array.isArray(e.data)?new Uint8Array(e.data):typeof e=="object"&&e.type==="Buffer"?new Uint8Array(e.data):(this.log(`Unknown data type for ${t} packet: ${typeof e}`),null)}debugRenderState(){let e=this.core.getUser(this.userId);if(e){let r=e.getLayers();console.warn(`[CLIENT] User has ${r.length} layers`),r.forEach((s,n)=>{let o=s.getOrders(),a=s.getMustBeReliable();(o.length>0||a)&&console.warn(` Layer ${n}: ${o.length} orders, reliable=${a}, z=${s.getZOrder()}`)})}let i=this.getPrimaryRendererManager()?.isReady()??!1;console.warn(`[CLIENT] Renderer ready: ${i}`)}log(e){this.options.debug&&console.warn(`[NetworkSync] ${e}`)}recordBytesReceived(e){this.totalBytesReceived+=e;let t=this.core.getUser(this.userId);t&&t.recordBytesReceived(e)}getLayerTrafficStats(){let e={},i=performance.now()-w;return this.layerTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),e[s]={total:r.total,bytesPerSec1s:r.windowSum/(w/1e3)}}),e}getMiscTrafficStats(){let e={},i=performance.now()-w;return this.miscTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),e[s]={total:r.total,bytesPerSec1s:r.windowSum/(w/1e3)}}),e}getDisplayTrafficStats(){let e={},i=performance.now()-w;return this.displayTraffic.forEach((r,s)=>{for(;r.samples.length&&r.samples[0].time<i;){let n=r.samples.shift();n&&(r.windowSum-=n.bytes)}r.windowSum<0&&(r.windowSum=0),e[s]={total:r.total,bytesPerSec1s:r.windowSum/(w/1e3)}}),e}getSoundPacketSize(e){return e.mode==="file"?e.sounds.reduce((i,r)=>i+this.getSoundDataLength(r.data)+r.name.length+10,0):e.sounds.reduce((i,r)=>i+r.url.length+r.name.length+10,0)}getSoundDataLength(e){if(e instanceof Uint8Array)return e.length;if(e instanceof ArrayBuffer||ArrayBuffer.isView(e))return e.byteLength;let t=globalThis.Buffer;return t&&e instanceof t?e.length:e&&typeof e=="object"&&Array.isArray(e.data)?e.data.length:Array.isArray(e)?e.length:0}setAudioManager(e){if(this.audioManager=e,e&&this.userId){let t=this.core.getUser(this.userId);t&&t.setAudioProcessor(e)}this.connected&&e&&this.setupSoundHandlers()}setPostProcessCallback(e){this.postProcessCallback=e}setTouchZonesCallback(e){this.touchZonesCallback=e}setupSoundHandlers(){if(this.audioManager){if(this.soundHandlersSetup){this.log("Sound handlers already registered, skipping");return}this.soundHandlersSetup=!0,this.network.on("sound-load",async e=>{this.recordBytesReceived(this.getSoundPacketSize(e)),e.totalSounds!==void 0&&e.totalSounds>this.audioLoadingState.totalExpected&&(this.audioLoadingState.totalExpected=e.totalSounds,this.log(`Audio loading: expecting ${e.totalSounds} total sounds`)),e.mode==="file"?await this.handleSoundLoad(e):e.mode==="external"&&await this.handleSoundExternalLoad(e)}),this.log("Sound handlers registered")}}async handleSoundLoad(e){if(!this.audioManager){this.log("Cannot load sounds: AudioManager not initialized");return}let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load sounds: SoundBank not initialized");return}for(let i of e.sounds)try{let r=this.normalizeSoundData(i.data);await t.loadFromData(i.soundId,i.name,r),this.log(`Loaded sound: ${i.name} (${r.length} bytes)`),this.audioLoadingState.loadedSounds.add(i.name),this.audioLoadingState.errors.delete(i.name),this.sendAudioAck({type:"sound-loaded",soundId:i.soundId,name:i.name})}catch(r){console.error(`[NetworkSync] Failed to load sound "${i.name}":`,r),this.audioLoadingState.errors.set(i.name,String(r)),this.sendAudioAck({type:"sound-error",soundId:i.soundId,name:i.name,error:String(r)})}}normalizeSoundData(e){if(e instanceof Uint8Array)return e;if(e instanceof ArrayBuffer)return new Uint8Array(e);if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength));let t=globalThis.Buffer;if(t&&e instanceof t)return new Uint8Array(e);if(e&&typeof e=="object"&&Array.isArray(e.data))return new Uint8Array(e.data);if(Array.isArray(e))return new Uint8Array(e);if(typeof e=="string")try{let i=atob(e),r=i.length,s=new Uint8Array(r);for(let n=0;n<r;n++)s[n]=i.charCodeAt(n);return s}catch{}throw new Error("Invalid sound data payload")}async handleSoundExternalLoad(e){if(!this.audioManager){this.log("Cannot load external sounds: AudioManager not initialized");return}let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load external sounds: SoundBank not initialized");return}for(let i of e.sounds)try{await t.loadFromUrl(i.soundId,i.name,i.url),this.log(`Loaded external sound: ${i.name} from ${i.url}`),this.audioLoadingState.loadedSounds.add(i.name),this.audioLoadingState.errors.delete(i.name),this.sendAudioAck({type:"sound-loaded",soundId:i.soundId,name:i.name})}catch(r){console.error(`[NetworkSync] Failed to load external sound "${i.name}":`,r),this.audioLoadingState.errors.set(i.name,String(r)),this.sendAudioAck({type:"sound-error",soundId:i.soundId,name:i.name,error:String(r)})}}sendAudioAck(e){this.network.send("audio-ack",e),this.log(`Sent audio-ack: ${e.type}`)}sendBridge(e,t){this.network.sendBridge?.(e,t),this.log(`Bridge sent on channel '${e}'`)}onBridge(e,t){this.network.onBridge?.(e,t),this.log(`Bridge handler registered for channel '${e}'`)}offBridge(e,t){this.network.offBridge?.(e,t),this.log(`Bridge handler removed for channel '${e}'`)}removeAllBridgeHandlers(e){this.network.removeAllBridgeHandlers?.(e),this.log(e?`All bridge handlers removed for '${e}'`:"All bridge handlers removed")}};R(Q,"NetworkSync");var V=Q;var $=class $ extends k{constructor(t){let i=t.mode;if(i!=="standalone"&&i!=="socketio"&&i!=="webrtc")throw new Error(`Invalid ClientRuntime mode: "${i}". Expected 'standalone', 'socketio', or 'webrtc'.`);let r;if(t.mode==="standalone"&&(r=t.standalone.application),!r&&t.mode==="standalone")throw new Error("Application instance required for standalone mode");super({application:r,container:t.container,displayContainers:t.displayContainers,debug:t.debug,width:t.width,height:t.height,renderer:t.renderer,useImageDataRendering:t.useImageDataRendering,renderMode:t.renderMode});l(this,"input",null);l(this,"networkSync",null);l(this,"mode");l(this,"localOptions",null);l(this,"autoplayOverlay",null);l(this,"autoplay",!0);l(this,"audioManager",null);l(this,"mobileVibration",null);l(this,"postProcessOverlay",null);l(this,"postProcessOverlays",new Map);l(this,"postProcessOrderCollector",new he);l(this,"pendingPaletteSlotByDisplay",new Map);l(this,"localBridgeHandlers",new Map);l(this,"localBridgeWildcardHandlers",new Set);this.mode=t.mode,this.autoplay=t.autoplay??!0,t.mode==="standalone"?(this.localOptions=t,this.userId=t.standalone.userId??"local"):this.localOptions=null,this.mode==="standalone"?(this.log("Initializing in STANDALONE mode"),this.initLocalMode()):(this.log(`Initializing in ${this.mode.toUpperCase()} mode`),this.initConnectedMode(t))}initLocalMode(){let t=this.localOptions;if(!t)return;this.log("Initializing ClientRuntime (standalone mode)"),t.inputEnabled??!0?this.initInput(t):this.log("Input disabled (inputEnabled: false)")}initConnectedMode(t){this.log(`Initializing ClientRuntime (${this.mode} mode)`),this.core=new ce({mode:"client",maxUsers:100}),this.core.onPaletteChanged(n=>{this.onCorePaletteChanged(n),this.retryPendingPaletteSelections()}),this.core.onImageFontChanged(n=>{this.onCoreImageFontChanged(n)});let i;if(t.mode==="webrtc"){let n=t.webrtc;i=new Se({url:n.signalUrl??"",sessionId:n.sessionId,signalingPath:n.signalingPath,iceServers:n.iceServers,autoReconnect:n.autoReconnect,auth:n.auth??{username:n.username},debug:t.debug})}else{let n=t.socketio;if(!n)throw new Error(`SocketIO configuration missing. Mode is '${t.mode}' but 'socketio' options are undefined.`);i=new Ce({url:n.url??"",path:n.path,autoReconnect:n.autoReconnect,auth:n.auth??{username:n.username},debug:t.debug})}let r=t.mode==="socketio"?t.socketio:t.webrtc;this.networkSync=new V(i,this.core,this.rendererManagers,this.performanceMonitor,{serverUrl:t.mode==="socketio"?t.socketio.url:t.webrtc.signalUrl||"WebRTC",username:r.username??"User",debug:t.debug,autoReconnect:r.autoReconnect,canvasWidth:t.width??80,canvasHeight:t.height??25},this.primaryDisplayId,n=>this.ensureRendererManager(n)),(t.inputEnabled??!0)&&(this.input||this.initInput(t))}initInput(t){this.input=new ye({enableKeyboardMouse:!0,enableGamepad:!0,enableMobile:!0,targetElement:window,mobileTargetElement:t.touchZones?.targetElement??void 0,debug:t.debug,keyboardConfig:{preventDefault:t.captureInput??!1,stopPropagation:t.captureInput??!1},mouseConfig:{preventDefault:t.captureInput??!1,stopPropagation:t.captureInput??!1},mobileConfig:{preventDefault:t.mobileInputConfig?.preventDefault??!1,passive:t.mobileInputConfig?.passive??!0,maxTouches:t.mobileInputConfig?.maxTouches??10},enableTouchZones:t.touchZones?.enable??!1,touchZoneConfig:{targetElement:t.touchZones?.targetElement,gridWidth:t.touchZones?.gridWidth??t.width??0,gridHeight:t.touchZones?.gridHeight??t.height??0,rendererOffsets:t.touchZones?.rendererOffsets,zones:t.touchZones?.zones}})}rebuildPostProcessOverlays(){for(let t of this.postProcessOverlays.values())t.destroy();this.postProcessOverlays.clear(),this.postProcessOverlay=null;for(let[t,i]of this.displayConfigs.entries()){let r=new pe(i.container);this.postProcessOverlays.set(t,r),t===this.primaryDisplayId&&(this.postProcessOverlay=r)}!this.postProcessOverlay&&this.postProcessOverlays.size>0&&(this.postProcessOverlay=Array.from(this.postProcessOverlays.values())[0]??null)}getMode(){return this.mode}setTickRate(t){if(this.mode!=="standalone"){this.log("setTickRate() has no effect in connected mode");return}super.setTickRate(t)}async onBeforeStart(){this.audioManager=new Re({debug:this.options.debug}),this.mobileVibration=new be({debug:this.options.debug}),this.autoplay?(this.log("Autoplay enabled, initializing AudioManager..."),this.audioManager.initialize()):(this.log("Autoplay disabled, showing overlay..."),await new Promise(t=>{this.autoplayOverlay=new ue(this.options.container,{...this.localOptions?.autoplayOptions,onStart:()=>{this.log("User clicked start button"),this.audioManager&&(this.audioManager.initialize(),this.audioManager.playStartSound()),this.mobileVibration&&this.mobileVibration.vibrate(50),this.autoplayOverlay&&(this.autoplayOverlay.destroy(),this.autoplayOverlay=null),t()}})}),this.log("Autoplay overlay dismissed, continuing startup..."))}async start(){if(this.running){this.log("Already running");return}this.log("Starting ClientRuntime"),await this.onBeforeStart();for(let[r,s]of this.rendererManagers.entries())await s.initialize(this.core),this.log(`Renderer for display ${r} is ready`);this.rebuildPostProcessOverlays(),this.log("PostProcessOverlays created"),this.onCorePaletteChanged(this.core.getPalette()),this.log("Initial palette sent to renderer"),this.options.application&&(this.log("Calling application.init()"),await this.options.application.init(this.core,this));let t=this.rendererManager.getCanvas();if(t&&this.input&&this.input.setMobileTarget(t),this.mode!=="standalone"&&this.networkSync){if(this.audioManager&&this.networkSync.setAudioManager(this.audioManager),this.networkSync.setPostProcessCallback(s=>{this.applyPostProcessOrders(s)}),this.input){let s=this.input,n=this.rendererManager;this.networkSync.setTouchZonesCallback(o=>{this.log(`[start] Touch zones callback called with ${o.length} zones`);let a=n.getCanvas();if(this.log(`[start] Canvas available: ${!!a}`),a){let c=o.reduce((h,m)=>Math.max(h,m.x+m.width),0),d=o.reduce((h,m)=>Math.max(h,m.y+m.height),0);this.log(`[start] Grid from zones: ${c}x${d}`);let u=s.enableTouchZonesDevice(a,c,d,o);this.log(`[start] enableTouchZonesDevice returned: ${u}`),u&&this.log(`Touch zones configured from server: ${o.length} zones`)}})}await this.networkSync.connect(),this.userId=await this.networkSync.joinGame(this.options.application);let r=this.core.getUser(this.userId);r&&this.configureUserProcessors(r)}else await this.createLocalUser();let i=this.core.getUser(this.userId);if(i){let r=i.getDisplays();if(r.length>0){let n=r[0].getSize(),o=n.x,a=n.y,c=this.rendererManager.getRenderer(),d,u;if(this.rendererType==="webgl"){let m=c.getGridSize();d=m.cols,u=m.rows}else{let h=c;d=h.getCols(),u=h.getRows()}(d!==o||u!==a)&&(this.log(`Adjusting renderer from ${d}\xD7${u} to match display ${o}\xD7${a}`),c.resize(o,a))}}this.input&&this.input.start(),this.running=!0,this.startTime=performance.now(),this.lastTimestamp=this.startTime,this.lastRenderTimestamp=this.startTime,this.accumulatedTime=0,this.firstTickDone=!1,this.performanceMonitor.reset(),this.performanceMonitor.startTracking(this.startTime),this.log("Starting main loop"),this.mainLoop(this.lastTimestamp)}async onStop(){this.audioManager&&this.audioManager.stopAll(),this.input&&this.input.stop(),this.mode!=="standalone"&&this.networkSync&&this.networkSync.disconnect()}getStats(){let t=super.getStats(),r=this.core.getUser(this.userId)?.getTotalBytesReceived();return{...t,mode:this.mode,latency:void 0,totalBytesReceived:r}}getAudioLoadingState(){if(this.mode!=="standalone"&&this.networkSync)return this.networkSync.getAudioLoadingState();if(this.audioManager){let t=this.audioManager.getSoundBank();if(t){let i=t.getStats();return{loadedCount:i.totalSounds,totalExpected:i.totalSounds,errorCount:0,isComplete:!0,errors:[]}}}return{loadedCount:0,totalExpected:0,errorCount:0,isComplete:!0,errors:[]}}async onDestroy(){this.autoplayOverlay&&(this.autoplayOverlay.destroy(),this.autoplayOverlay=null),this.audioManager&&(this.audioManager.destroy(),this.audioManager=null),this.postProcessOverlay&&(this.postProcessOverlay.destroy(),this.postProcessOverlay=null);for(let t of this.postProcessOverlays.values())t.destroy();this.postProcessOverlays.clear(),this.input&&this.input.destroy(),this.networkSync&&this.networkSync.destroy()}configureUserProcessors(t){if(this.audioManager&&t.setAudioProcessor(this.audioManager),this.mobileVibration&&t.setMobileVibrationProcessor(this.mobileVibration),this.input){let i=this.input.getGamepad();i&&t.setGamepadVibrationProcessor(i)}}async createLocalUser(){let t=this.localOptions;this.userId=t?.standalone.userId??"local",this.log(`Creating local user: ${this.userId}`);let i=this.core.createUser(this.userId,t?.standalone.username??"User");if(i.setBytesTickRate(this.tickRate>0?this.tickRate:20),this.configureUserProcessors(i),this.options.application?.initUser&&(this.log("Calling application.initUser()"),this.options.application.initUser(this.core,i,{username:t?.standalone.username??"User"})),i.hasAudioConfigCommands()&&(this.log("Applying audio config commands from initUser()"),i.applyAudioConfigCommands(i.flushAudioConfigCommands())),i.hasPendingMacroOrders()){this.log("Applying macro orders from initUser()");let a=i.flushMacroOrders();i.applyMacroOrders(a)}if(i.hasPostProcessCommands()){this.log("Applying post-process commands from initUser()");let a=i.flushPostProcessCommands(),c=this.postProcessOrderCollector.convertCommands(a);this.applyPostProcessOrders(c)}i.needsSendSounds()&&(await this.loadSoundsFromRegistry(),i.clearSendSounds());let r=this.core.generateAllLoadPackets();r.forEach(a=>{i.recordBytesReceived(a.length)});let s=this.core.generateMacroLoadPackets(this.userId);s.forEach(a=>{i.recordBytesReceived(a.length)});let n=i.getInputBindingsLoadPacket();if(n&&(i.recordBytesReceived(n.length),this.input)){let c=i.getInputBindingRegistry().getAllTouchZones();if(c.length>0){let d=this.rendererManager.getCanvas();if(d){let u=i.getDisplays(),h=u.length>0?u[0].getSize():{x:this.options.width??80,y:this.options.height??25},m=c.map(f=>({id:f.zoneId,x:f.x,y:f.y,width:f.width,height:f.height}));this.input.enableTouchZonesDevice(d,h.x,h.y,m)?this.log(`Touch zones synchronized from registry: ${c.length} zones`):this.log("Failed to enable touch zones - mobile input may not be initialized")}}}this.log(`Simulated ${r.length} load packets, ${s.length} macro packets for byte counting`),this.log("Performing initial render"),this.core.endTick().forEach(({static:a,dynamic:c},d)=>{let u=this.core.getUser(d);u&&(a&&u.recordBytesReceived(a.length),c&&u.recordBytesReceived(c.length))}),this.render(),this.log("Initial render complete")}async loadSoundsFromRegistry(){if(!this.audioManager){this.log("Cannot load sounds: AudioManager not initialized");return}let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load sounds: SoundBank not initialized");return}let r=this.core.getSoundRegistry().getAll();if(r.length===0){this.log("No sounds to load from registry");return}this.log(`Loading ${r.length} sounds from Core registry into AudioManager...`);let s=this.core.getUser(this.userId),n=0;for(let o of r)try{if(o.loadType==="file"&&o.data){await t.loadFromData(o.soundId,o.name,o.data);let a=o.data.length+o.name.length+10;n+=a,this.log(`\u{1F50A} Loaded sound: ${o.name} (${o.data.length} bytes)`)}else if(o.loadType==="external"&&o.url){await t.loadFromUrl(o.soundId,o.name,o.url);let a=o.url.length+o.name.length+10;n+=a,this.log(`\u{1F50A} Loaded external sound: ${o.name} from ${o.url}`)}}catch(a){console.error(`[ClientRuntime] Failed to load sound "${o.name}":`,a)}s&&n>0&&(s.recordBytesReceived(n),this.log(`Simulated ${n} bytes for ${r.length} sound(s)`)),this.log(`\u2713 ${t.size} sounds loaded into AudioManager`)}mainLoop(t){if(!this.running){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0);return}if(this.renderMode==="on-demand"){this.renderRequested&&(this.renderRequested=!1,this.performanceMonitor.updateFPS(t),this.render()),this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}let i=t-this.lastRenderTimestamp;if(this.lastRenderTimestamp>0&&i<this.FRAME_TIME_MIN-1){this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}this.lastRenderTimestamp=t;let r=(t-this.lastTimestamp)/1e3,s=Math.min(r,.1);this.lastTimestamp=t,this.performanceMonitor.updateFPS(t);let n=this.core.getUser(this.userId);if(!n){this.rafId=requestAnimationFrame(o=>this.mainLoop(o));return}if(this.mode==="standalone"){if(this.tickRate===0){let d=performance.now();this.render();let u=performance.now()-d;this.performanceMonitor.recordFrameTiming(0,u),this.rafId=requestAnimationFrame(h=>this.mainLoop(h));return}if(!this.firstTickDone){this.firstTickDone=!0,this.lastTimestamp=t,this.accumulatedTime=0,this.rafId=requestAnimationFrame(d=>this.mainLoop(d));return}this.accumulatedTime+=s;let o=1/this.tickRate;this.accumulatedTime>.5&&(this.accumulatedTime=o);let a=0,c=0;for(;this.accumulatedTime>=o&&a<5;){let d=performance.now();if(this.collectAndApplyInput(n),this.options.application&&(this.options.application.update?.(this.core,o),this.options.application.updateUser?.(this.core,n,o)),n.clearTextInputs(),n.hasAudioConfigCommands()&&n.applyAudioConfigCommands(n.flushAudioConfigCommands()),n.hasSoundCommands()&&n.applyAudioCommands(n.flushSoundCommands()),n.hasMobileVibrationCommands()&&n.applyMobileVibrationCommands(n.flushMobileVibrationCommands()),n.hasGamepadVibrationCommands()&&n.applyGamepadVibrationCommands(n.flushGamepadVibrationCommands()),n.hasPostProcessCommands()){let m=n.flushPostProcessCommands(),C=this.postProcessOrderCollector.convertCommands(m);this.applyPostProcessOrders(C)}if(n.hasPendingMacroOrders()){let m=n.flushMacroOrders();n.applyMacroOrders(m)}let u=n.updateMacros();if(n.processMacroEvents(u),n.hasBridgeMessages()){let m=n.getBridgeMessages();this.dispatchLocalBridgeMessages(m)}this.core.endTick().forEach(({static:m,dynamic:C})=>{let f=(m?.length??0)+(C?.length??0);n.recordBytesReceived(f)}),c+=performance.now()-d,this.accumulatedTime-=o,a++}if(a>0){let d=performance.now();this.render();let u=performance.now()-d;this.performanceMonitor.recordFrameTiming(c,u)}}else{let o=n.updateMacros();n.processMacroEvents(o),this.collectAndSendInput()}this.rafId=requestAnimationFrame(o=>this.mainLoop(o))}collectAndApplyInput(t){if(!this.input)return;let i=this.rendererManager.getCanvas();if(i){let a=t.getDisplays(),d=(a.find(g=>g.getId&&g.getId()===this.primaryDisplayId)??a[0])?.getSize()??{x:this.options.width,y:this.options.height},u=d.x,h=d.y,C=this.rendererManager.getRenderer()?.getOffsets?.(),f={offsetX:C?.offsetX??0,offsetY:C?.offsetY??0};this.input.updateTouchZoneLayout(u,h,f);let S=P.collectMousePosition(this.input,i,u,h,f);t.setMousePosition(S.x,S.y,S.over),t.updateMacroMouse(S.x,S.y,S.isLeftDown),P.collectTouchPositions(this.input,i,u,h,10,f).forEach(g=>{t.setTouchPosition(g.id,g.x,g.y,g.over)});let y=this.rendererManagers.get(this.primaryDisplayId)?.getAvailableSize();y&&t.setDisplayViewport(this.primaryDisplayId,y.width,y.height)}let r=P.collectTextInputs(this.input);r.length>0&&t.setTextInputs(r);let s=t.getInputBindingRegistry(),n=s.getAllAxes(),o=s.getAllButtons();if(n.length>0||o.length>0){let a=P.collectAxisSources(n,this.input),c=P.collectButtonSourcesWithTransitions(o,this.input);n.forEach(d=>{let u=s.evaluateAxis(d.bindingId,a);t.setAxis(d.name,u)}),o.forEach(d=>{let u=new Map,h=new Map,m=new Map;for(let[b,p]of c)u.set(b,p.pressed),h.set(b,p.justPressed),m.set(b,p.justReleased);let C=s.evaluateButton(d.bindingId,u),f=s.evaluateButton(d.bindingId,h),S=s.evaluateButton(d.bindingId,m);t.setButton(d.name,C),t.setButton(`${d.name}_justPressed`,f),t.setButton(`${d.name}_justReleased`,S)})}this.input.poll?.()}collectAndSendInput(){!this.networkSync||!this.input||this.networkSync.sendInput(this.input)}render(){let t=this.core.getUser(this.userId);if(t){let i=t.getDisplays();for(let r of i){let s=r.getId(),n=this.rendererManagers.get(s);if(!n){console.warn(`[ClientRuntime] No renderer for display ${s}, skipping resize`);continue}let o=n.getRenderer();if(!o)continue;let a=r.getSize(),c,d,u,h,m=null;if("getGridSize"in o){let f=o,S=f.getGridSize();c=S.cols,d=S.rows,u=f.getCellWidth(),h=f.getCellHeight(),m=f.getScalingMode()}else if("getCols"in o){let f=o;c=f.getCols(),d=f.getRows(),u=f.getCellWidth(),h=f.getCellHeight(),m=f.getScalingMode()}else continue;if(m===ge.Responsive){let f=n.getAvailableSize(),S=256*256;"getMaxCells"in o&&(S=Math.min(S,o.getMaxCells()));let b=Math.floor(f.width/u),p=Math.floor(f.height/h);if(b=Math.min(256,Math.max(1,b)),p=Math.min(256,Math.max(1,p)),b*p>S){let y=Math.sqrt(S/(b*p));b=Math.max(1,Math.floor(b*y)),p=Math.max(1,Math.floor(p*y)),this.log(`\u26A0\uFE0F [Display ${s}] Device limit: max ${S} cells, clamping to ${b}\xD7${p}`)}(a.x!==b||a.y!==p)&&(this.log(`\u{1F4D0} [Display ${s}] Resizing display from ${a.x}\xD7${a.y} to ${b}\xD7${p} (available: ${f.width}\xD7${f.height}px, cell: ${u}\xD7${h}px)`),r.setSize(new fe(b,p)))}let C=r.getSize();(c!==C.x||d!==C.y)&&(this.log(`\u{1F4D0} [Display ${s}] Resizing renderer from ${c}\xD7${d} to ${C.x}\xD7${C.y}`),o.resize(C.x,C.y))}}super.render()}onFontChanged(t,i){let r=i??this.primaryDisplayId,s=this.postProcessOverlays.get(r)??this.postProcessOverlay;s&&"syncWithRenderer"in s&&"getCellWidth"in t&&"getCellHeight"in t&&"getCurrentScale"in t&&"getGridSize"in t&&(s.syncWithRenderer(t),this.log(`\u2713 PostProcessOverlay synced with renderer dimensions (display ${r})`))}getAudioManager(){return this.audioManager}getLayerTrafficStats(){return this.networkSync?.getLayerTrafficStats()??{}}getMiscTrafficStats(){return this.networkSync?.getMiscTrafficStats?.()??{}}getDisplayTrafficStats(){return this.networkSync?.getDisplayTrafficStats?.()??{}}getAudioContext(){return this.audioManager?.getContext()??null}getPostProcessOverlay(){return this.postProcessOverlay}applyAmbientEffectConfig(t,i){let r=this.rendererManagers.get(t)?.getRenderer();r&&"setAmbientEffect"in r&&(i.enabled?r.setAmbientEffect({blur:i.blur,scale:i.scale}):r.setAmbientEffect(!1),this.log(`[Display ${t}] Ambient effect ${i.enabled?"enabled":"disabled"}`))}applyPostProcessOrders(t){for(let i of t){let r=i.displayId??this.primaryDisplayId,s=this.postProcessOverlays.get(r)??this.postProcessOverlay,n=this.rendererManagers.get(r)?.getRenderer();switch(i.type){case F.SetConfig:{if(!s){console.warn(`[ClientRuntime] No PostProcessOverlay for display ${r}`);break}let o={};i.scanlines&&(o.scanlines={enabled:i.scanlines.enabled,opacity:i.scanlines.opacity,pattern:this.patternFromType(i.scanlines.pattern),color:{r:i.scanlines.colorR,g:i.scanlines.colorG,b:i.scanlines.colorB}}),i.ambientEffect&&(o.ambientEffect={enabled:i.ambientEffect.enabled,blur:i.ambientEffect.blur,scale:i.ambientEffect.scale}),s.setConfig(Object.keys(o).length>0?o:null),o.ambientEffect&&n&&this.applyAmbientEffectConfig(r,o.ambientEffect),this.log(`[Display ${r}] SetConfig applied`);break}case F.SetScanlines:{if(!s){console.warn(`[ClientRuntime] No PostProcessOverlay for display ${r}`);break}s.setScanlines({enabled:i.enabled,opacity:i.opacity,pattern:this.patternFromType(i.pattern),color:{r:i.colorR,g:i.colorG,b:i.colorB}}),this.log(`[Display ${r}] Scanlines ${i.enabled?"enabled":"disabled"}`);break}case F.SetAmbientEffect:{this.applyAmbientEffectConfig(r,{enabled:i.enabled,blur:i.blur,scale:i.scale}),this.log(`[Display ${r}] Ambient effect ${i.enabled?"enabled":"disabled"}`);break}case F.SetScalingMode:{this.applyScalingMode(r,i.mode);break}case F.SetGrid:{this.applyGridConfig(r,i);break}case F.SwitchPalette:{this.applySwitchPalette(r,i);break}case F.SetCellSize:{this.applyCellSize(r,i.cellWidth,i.cellHeight);break}}}}applyScalingMode(t,i){let r=this.rendererManagers.get(t)?.getRenderer();if(r&&"setScalingMode"in r){let s=me(i);r.setScalingMode(s),this.log(`[Display ${t}] Scaling mode set to ${s}`)}}applyGridConfig(t,i){let r=this.rendererManagers.get(t)?.getRenderer();if(r&&"setGrid"in r){let s=i.colorA/255;r.setGrid({enabled:i.enabled,color:`rgba(${i.colorR},${i.colorG},${i.colorB},${s})`,lineWidth:i.lineWidth}),this.log(`[Display ${t}] Grid ${i.enabled?"enabled":"disabled"}`)}}applySwitchPalette(t,i){let r=this.core.getPaletteFromSlot(i.slotId);if(!r){this.pendingPaletteSlotByDisplay.set(t,i.slotId),console.warn(`[ClientRuntime] Palette slot ${i.slotId} not found (display ${t}); will retry when available`);return}let s=[];for(let o=0;o<256;o++){let a=r.get(o);a?s.push({r:a.r,g:a.g,b:a.b,a:a.a}):s.push({r:0,g:0,b:0,a:0})}let n=this.rendererManagers.get(t)?.getRenderer();n&&"setPalette"in n&&(n.setPalette(s),this.log(`[Display ${t}] Switched to palette slot ${i.slotId}`)),this.pendingPaletteSlotByDisplay.get(t)===i.slotId&&this.pendingPaletteSlotByDisplay.delete(t)}retryPendingPaletteSelections(){if(this.pendingPaletteSlotByDisplay.size!==0)for(let[t,i]of this.pendingPaletteSlotByDisplay.entries()){let r=this.core.getPaletteFromSlot(i);if(!r)continue;let s=[];for(let o=0;o<256;o++){let a=r.get(o);a?s.push({r:a.r,g:a.g,b:a.b,a:a.a}):s.push({r:0,g:0,b:0,a:0})}let n=this.rendererManagers.get(t)?.getRenderer();n&&"setPalette"in n&&(n.setPalette(s),this.log(`[Display ${t}] Applied pending palette slot ${i}`),this.pendingPaletteSlotByDisplay.delete(t))}}applyCellSize(t,i,r){let s=this.rendererManagers.get(t)?.getRenderer();s&&"setCellSize"in s&&(s.setCellSize(i,r),this.log(`[Display ${t}] Cell size set to ${i}\xD7${r}px`))}patternFromType(t){switch(t){case 0:return"horizontal";case 1:return"vertical";case 2:return"grid";default:return"horizontal"}}dispatchLocalBridgeMessages(t){for(let i of t){let{channel:r,data:s}=i,n=this.localBridgeHandlers.get(r);if(n)for(let o of n)try{o(s)}catch(a){console.error(`[ClientRuntime] Bridge handler error on '${r}':`,a)}for(let o of this.localBridgeWildcardHandlers)try{o(r,s)}catch(a){console.error("[ClientRuntime] Bridge wildcard handler error:",a)}this.log(`Bridge message dispatched on channel '${r}'`)}}sendBridge(t,i){if(this.mode!=="standalone"&&this.networkSync)this.networkSync.sendBridge(t,i);else if(this.mode==="standalone"){let r=this.core.getUser(this.userId);r&&this.options.application?.onBridgeMessage&&(this.options.application.onBridgeMessage(this.core,r,t,i),this.log(`Bridge message sent to application on channel '${t}'`))}}onBridge(t,i){this.mode!=="standalone"&&this.networkSync?this.networkSync.onBridge(t,i):this.mode==="standalone"&&(t==="*"?this.localBridgeWildcardHandlers.add(i):(this.localBridgeHandlers.has(t)||this.localBridgeHandlers.set(t,new Set),this.localBridgeHandlers.get(t).add(i)),this.log(`Bridge handler registered for channel '${t}'`))}offBridge(t,i){this.mode!=="standalone"&&this.networkSync?this.networkSync.offBridge(t,i):this.mode==="standalone"&&(t==="*"?this.localBridgeWildcardHandlers.delete(i):this.localBridgeHandlers.get(t)?.delete(i))}removeAllBridgeHandlers(t){this.mode!=="standalone"&&this.networkSync?this.networkSync.removeAllBridgeHandlers(t):this.mode==="standalone"&&(t===void 0?(this.localBridgeHandlers.clear(),this.localBridgeWildcardHandlers.clear()):t==="*"?this.localBridgeWildcardHandlers.clear():this.localBridgeHandlers.delete(t))}log(t){this.options.debug&&console.warn(`[ClientRuntime/${this.mode}] ${t}`)}};R($,"ClientRuntime");var G=$;import{UnifiedInputRouter as ve,InputCollector as B,MobileVibration as Ie}from"@utsp/input";var W=class W{constructor(e={}){l(this,"input");l(this,"mobileVibration");this.input=new ve({enableKeyboardMouse:!0,enableGamepad:!0,enableMobile:!0,targetElement:window,mobileTargetElement:void 0,debug:e.debug,keyboardConfig:{preventDefault:e.captureInput??!1,stopPropagation:e.captureInput??!1},mouseConfig:{preventDefault:e.captureInput??!1,stopPropagation:e.captureInput??!1},mobileConfig:{preventDefault:e.mobileInputConfig?.preventDefault??!1,passive:e.mobileInputConfig?.passive??!0,maxTouches:e.mobileInputConfig?.maxTouches??10}}),this.mobileVibration=new Ie({debug:e.debug})}setMobileTarget(e){this.input.setMobileTarget(e)}start(){this.input.start()}stop(){this.input.stop()}destroy(){this.input.destroy()}getRouter(){return this.input}getGamepad(){return this.input.getGamepad()}getMobileVibration(){return this.mobileVibration}collectAndApply(e,t,i,r,s){if(t){let d=B.collectMousePosition(this.input,t,i,r,s);e.setMousePosition(d.x,d.y,d.over),e.updateMacroMouse(d.x,d.y,d.isLeftDown),B.collectTouchPositions(this.input,t,i,r,10,s).forEach(h=>{e.setTouchPosition(h.id,h.x,h.y,h.over)})}let n=B.collectTextInputs(this.input);n.length>0&&e.setTextInputs(n);let o=e.getInputBindingRegistry(),a=o.getAllAxes(),c=o.getAllButtons();if(a.length>0||c.length>0){let d=B.collectAxisSources(a,this.input),u=B.collectButtonSourcesWithTransitions(c,this.input);a.forEach(h=>{let m=o.evaluateAxis(h.bindingId,d);e.setAxis(h.name,m)}),c.forEach(h=>{let m=new Map,C=new Map,f=new Map;for(let[y,g]of u)m.set(y,g.pressed),C.set(y,g.justPressed),f.set(y,g.justReleased);let S=o.evaluateButton(h.bindingId,m),b=o.evaluateButton(h.bindingId,C),p=o.evaluateButton(h.bindingId,f);e.setButton(h.name,S),e.setButton(`${h.name}_justPressed`,b),e.setButton(`${h.name}_justReleased`,p)})}this.input.poll?.()}processVibrationCommands(e){e.hasMobileVibrationCommands()&&e.applyMobileVibrationCommands(e.flushMobileVibrationCommands()),e.hasGamepadVibrationCommands()&&e.applyGamepadVibrationCommands(e.flushGamepadVibrationCommands())}};R(W,"InputFeature");var H=W;import{AudioManager as we}from"@utsp/audio";var z=class z{constructor(e={}){l(this,"audioManager");l(this,"debug");this.debug=e.debug??!1,this.audioManager=new we({debug:e.debug})}initialize(){this.audioManager.initialize()}playStartSound(){this.audioManager.playStartSound()}stopAll(){this.audioManager.stopAll()}destroy(){this.audioManager.destroy()}getManager(){return this.audioManager}getContext(){return this.audioManager.getContext()}injectIntoUser(e){e.setAudioProcessor(this.audioManager)}processAudioCommands(e){e.hasAudioConfigCommands()&&e.applyAudioConfigCommands(e.flushAudioConfigCommands()),e.hasSoundCommands()&&e.applyAudioCommands(e.flushSoundCommands())}async loadSoundsFromRegistry(e){let t=this.audioManager.getSoundBank();if(!t){this.log("Cannot load sounds: SoundBank not initialized");return}let r=e.getSoundRegistry().getAll();if(r.length===0){this.log("No sounds to load from registry");return}this.log(`Loading ${r.length} sounds from Core registry...`);for(let s of r)try{s.loadType==="file"&&s.data?(await t.loadFromData(s.soundId,s.name,s.data),this.log(`Loaded sound: ${s.name} (${s.data.length} bytes)`)):s.loadType==="external"&&s.url&&(await t.loadFromUrl(s.soundId,s.name,s.url),this.log(`Loaded external sound: ${s.name} from ${s.url}`))}catch(n){console.error(`[AudioFeature] Failed to load sound "${s.name}":`,n)}this.log(`${t.size} sounds loaded`)}log(e){this.debug&&console.warn(`[AudioFeature] ${e}`)}};R(z,"AudioFeature");var Y=z;import{PostProcessOrderCollector as Me,PostProcessOrderType as x}from"@utsp/core";import{PostProcessOverlay as Te}from"@utsp/render";import{valueToScalingMode as Fe}from"@utsp/types";var J=class J{constructor(e,t={}){l(this,"overlay");l(this,"orderCollector");l(this,"debug");this.debug=t.debug??!1,this.overlay=new Te(e),this.orderCollector=new Me}destroy(){this.overlay.destroy()}getOverlay(){return this.overlay}syncWithRenderer(e){this.overlay.syncWithRenderer(e),this.log("Overlay synced with renderer dimensions")}processCommands(e,t){if(!e.hasPostProcessCommands())return;let i=e.flushPostProcessCommands(),r=this.orderCollector.convertCommands(i);this.applyOrders(r,t)}applyOrders(e,t){for(let i of e){let r=i.displayId;switch(i.type){case x.SetConfig:{let s={};i.scanlines&&(s.scanlines={enabled:i.scanlines.enabled,opacity:i.scanlines.opacity,pattern:this.patternFromType(i.scanlines.pattern),color:{r:i.scanlines.colorR,g:i.scanlines.colorG,b:i.scanlines.colorB}}),i.ambientEffect&&(s.ambientEffect={enabled:i.ambientEffect.enabled,blur:i.ambientEffect.blur,scale:i.ambientEffect.scale}),this.overlay.setConfig(Object.keys(s).length>0?s:null),s.ambientEffect&&this.applyAmbientEffect(t,s.ambientEffect),this.log(`[Display ${r}] SetConfig applied`);break}case x.SetScanlines:{this.overlay.setScanlines({enabled:i.enabled,opacity:i.opacity,pattern:this.patternFromType(i.pattern),color:{r:i.colorR,g:i.colorG,b:i.colorB}}),this.log(`[Display ${r}] Scanlines ${i.enabled?"enabled":"disabled"}`);break}case x.SetAmbientEffect:{this.applyAmbientEffect(t,{enabled:i.enabled,blur:i.blur,scale:i.scale}),this.log(`[Display ${r}] Ambient effect ${i.enabled?"enabled":"disabled"}`);break}case x.SetScalingMode:{this.applyScalingMode(t,r,i.mode);break}case x.SetGrid:{this.applyGridConfig(t,r,i);break}}}}applyAmbientEffect(e,t){e&&"setAmbientEffect"in e&&(t.enabled?e.setAmbientEffect({blur:t.blur,scale:t.scale}):e.setAmbientEffect(!1))}applyScalingMode(e,t,i){if(e&&"setScalingMode"in e){let r=Fe(i);e.setScalingMode(r),this.log(`[Display ${t}] Scaling mode set to ${r}`)}}applyGridConfig(e,t,i){if(e&&"setGrid"in e){let r=i.colorA/255;e.setGrid({enabled:i.enabled,color:`rgba(${i.colorR},${i.colorG},${i.colorB},${r})`,lineWidth:i.lineWidth}),this.log(`[Display ${t}] Grid ${i.enabled?"enabled":"disabled"}`)}}patternFromType(e){switch(e){case 0:return"horizontal";case 1:return"vertical";case 2:return"grid";default:return"horizontal"}}log(e){this.debug&&console.warn(`[PostProcessFeature] ${e}`)}};R(J,"PostProcessFeature");var j=J;import{ScalingMode as Ft}from"@utsp/render";import{NetworkTransportType as At}from"@utsp/types";import{AudioManager as Bt}from"@utsp/audio";export{Y as AudioFeature,Bt as AudioManager,k as BaseClientRuntime,G as ClientRuntime,T as DEFAULT_ATLAS_CONFIG,H as InputFeature,At as NetworkTransportType,j as PostProcessFeature,E as RendererManager,re as RendererType,Ft as ScalingMode,K as decodeDefaultAtlas};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utsp/runtime-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0-nightly.20260120215017.712755a",
|
|
4
4
|
"description": "UTSP Runtime Client - Local and multi-user client runtime",
|
|
5
5
|
"author": "THP Software",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@utsp/audio": "0.
|
|
52
|
-
"@utsp/core": "0.
|
|
53
|
-
"@utsp/input": "0.
|
|
54
|
-
"@utsp/network-client": "0.
|
|
55
|
-
"@utsp/render": "0.
|
|
56
|
-
"@utsp/types": "0.
|
|
51
|
+
"@utsp/audio": "0.17.0-nightly.20260120215017.712755a",
|
|
52
|
+
"@utsp/core": "0.17.0-nightly.20260120215017.712755a",
|
|
53
|
+
"@utsp/input": "0.17.0-nightly.20260120215017.712755a",
|
|
54
|
+
"@utsp/network-client": "0.17.0-nightly.20260120215017.712755a",
|
|
55
|
+
"@utsp/render": "0.17.0-nightly.20260120215017.712755a",
|
|
56
|
+
"@utsp/types": "0.17.0-nightly.20260120215017.712755a"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"typescript": "^5.6.3"
|