From cf2dc91af6c7260e9ce5940af5aff400ee6a05e5 Mon Sep 17 00:00:00 2001 From: YHH <359807859@qq.com> Date: Sun, 28 Sep 2025 18:29:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0worker-demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/.vitepress/config.mjs | 29 +- docs/examples/index.md | 22 +- docs/examples/worker-system-demo.md | 13 + .../worker-system/assets/ecs-framework.umd.js | 4 + .../worker-system/assets/index-a4a166b2.js | 12754 ++++++++++++++++ docs/public/demos/worker-system/index.html | 176 + 6 files changed, 12995 insertions(+), 3 deletions(-) create mode 100644 docs/examples/worker-system-demo.md create mode 100644 docs/public/demos/worker-system/assets/ecs-framework.umd.js create mode 100644 docs/public/demos/worker-system/assets/index-a4a166b2.js create mode 100644 docs/public/demos/worker-system/index.html diff --git a/docs/.vitepress/config.mjs b/docs/.vitepress/config.mjs index 0a343f69..033785b8 100644 --- a/docs/.vitepress/config.mjs +++ b/docs/.vitepress/config.mjs @@ -16,7 +16,17 @@ export default defineConfig({ compiler: 'vue3', autoInstall: true }) - ] + ], + server: { + fs: { + allow: ['..'] + }, + middlewareMode: false, + headers: { + 'Cross-Origin-Embedder-Policy': 'require-corp', + 'Cross-Origin-Opener-Policy': 'same-origin' + } + } }, title: 'ECS Framework', description: '高性能TypeScript ECS框架 - 为游戏开发而生', @@ -28,7 +38,13 @@ export default defineConfig({ { text: '快速开始', link: '/guide/getting-started' }, { text: '指南', link: '/guide/' }, { text: 'API', link: '/api/README' }, - { text: '示例', link: 'https://github.com/esengine/lawn-mower-demo' }, + { + text: '示例', + items: [ + { text: 'Worker系统演示', link: '/examples/worker-system-demo' }, + { text: '割草机演示', link: 'https://github.com/esengine/lawn-mower-demo' } + ] + }, { text: `v${corePackageJson.version}`, link: 'https://github.com/esengine/ecs-framework/releases' @@ -58,6 +74,15 @@ export default defineConfig({ ] } ], + '/examples/': [ + { + text: '示例', + items: [ + { text: '示例概览', link: '/examples/' }, + { text: 'Worker系统演示', link: '/examples/worker-system-demo' } + ] + } + ], '/api/': [ { text: 'API 参考', diff --git a/docs/examples/index.md b/docs/examples/index.md index 270acc77..d6ebe7e3 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -1,3 +1,23 @@ # 示例 -代码示例。 \ No newline at end of file +这里展示了ECS Framework的各种使用示例,通过实际的演示帮助您理解框架的功能和最佳实践。 + +## 🎮 互动演示 + +### [Worker系统演示](./worker-system-demo) +- **功能**: 展示Worker多线程物理计算和渲染优化 +- **特性**: 1000+粒子实时物理模拟、碰撞检测、性能对比 +- **技术点**: SharedArrayBuffer、Canvas 2D优化、实体生命周期管理 + +## 🔗 外部示例 + +### [割草机演示](https://github.com/esengine/lawn-mower-demo) +- **平台**: Cocos Creator 3.x +- **功能**: 完整的游戏演示项目 +- **特性**: 展示ECS架构在实际游戏项目中的应用 + +## 📚 更多资源 + +- [快速开始指南](/guide/getting-started) +- [核心概念](/guide/) +- [API文档](/api/README) \ No newline at end of file diff --git a/docs/examples/worker-system-demo.md b/docs/examples/worker-system-demo.md new file mode 100644 index 00000000..6e8bdc62 --- /dev/null +++ b/docs/examples/worker-system-demo.md @@ -0,0 +1,13 @@ +# Worker系统演示 + +这是一个展示ECS框架Worker系统功能的交互式演示。 + +## 在线演示 + +
+ + 🚀 打开Worker系统演示 + +
+ +> **注意**: 演示将在新窗口中打开,展示完整的Worker系统功能,包括实体管理、物理模拟和性能监控。 \ No newline at end of file diff --git a/docs/public/demos/worker-system/assets/ecs-framework.umd.js b/docs/public/demos/worker-system/assets/ecs-framework.umd.js new file mode 100644 index 00000000..8abc622f --- /dev/null +++ b/docs/public/demos/worker-system/assets/ecs-framework.umd.js @@ -0,0 +1,4 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ECS={})}(this,(function(e){"use strict";function t(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,i=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function c(){return c=Object.assign?Object.assign.bind():function(e){for(var t=1;t3?(r=p===i)&&(c=o[(a=o[4])?5:(a=3,3)],o[4]=o[5]=e):o[0]<=f&&((r=n<2&&fi||i>p)&&(o[4]=n,o[5]=i,d.n=p,a=0))}if(r||n>1)return s;throw l=!0,i}return function(r,h,p){if(u>1)throw TypeError("Generator is already running");for(l&&1===h&&f(h,p),a=h,c=p;(t=a<2?e:c)||!l;){o||(a?a<3?(a>1&&(d.n=-1),f(a,c)):d.n=c:d.v=c);try{if(u=2,o){if(a||(r="next"),t=o[r]){if(!(t=t.call(o,c)))throw TypeError("iterator result is not an object");if(!t.done)return t;c=t.value,a<2&&(a=0)}else 1===a&&(t=o.return)&&t.call(o),a<2&&(c=TypeError("The iterator does not provide a '"+r+"' method"),a=1);o=e}else if((t=(l=d.n<0)?c:n.call(i,d))!==s)break}catch(t){o=e,a=1,c=t}finally{u=1}}return{value:t,done:l}}}(n,r,o),!0),u}var s={};function a(){}function c(){}function u(){}t=Object.getPrototypeOf;var h=[][i]?t(t([][i]())):(f(t={},i,(function(){return this})),t),l=u.prototype=a.prototype=Object.create(h);function p(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,u):(e.__proto__=u,f(e,r,"GeneratorFunction")),e.prototype=Object.create(l),e}return c.prototype=u,f(l,"constructor",u),f(u,"constructor",c),c.displayName="GeneratorFunction",f(u,r,"GeneratorFunction"),f(l),f(l,r,"Generator"),f(l,i,(function(){return this})),f(l,"toString",(function(){return"[object Generator]"})),(d=function(){return{w:o,m:p}})()}function f(e,t,n,i){var r=Object.defineProperty;try{r({},"",{})}catch(e){r=0}f=function(e,t,n,i){function o(t,n){f(e,t,(function(e){return this._invoke(t,n,e)}))}t?r?r(e,t,{value:n,enumerable:!i,configurable:!i,writable:!i}):e[t]=n:(o("next",0),o("throw",1),o("return",2))},f(e,t,n,i)}function p(e,t){return p=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},p(e,t)}function m(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var i=n.call(e,t);if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e,"string");return"symbol"==typeof t?t:t+""}function y(e){var t="function"==typeof Map?new Map:void 0;return y=function(e){if(null===e||!function(e){try{return-1!==Function.toString.call(e).indexOf("[native code]")}catch(t){return"function"==typeof e}}(e))return e;if("function"!=typeof e)throw new TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return r(e,arguments,u(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),p(n,e)},y(e)}var v=function(){function e(){this._enabled=!1}var t=e.prototype;return t.setEnabled=function(e){this._enabled!=e&&(this._enabled=e,this._enabled?this.onEnabled():this.onDisabled())},t.onEnabled=function(){},t.onDisabled=function(){},t.update=function(){},s(e,[{key:"enabled",get:function(){return this._enabled},set:function(e){this.setEnabled(e)}}])}(),g=function(){function e(){}return e.update=function(e){this.unscaledDeltaTime=e,this.deltaTime=e*this.timeScale,this.unscaledTotalTime+=this.unscaledDeltaTime,this.totalTime+=this.deltaTime,this.frameCount++},e.sceneChanged=function(){this.frameCount=0,this.totalTime=0,this.unscaledTotalTime=0,this.deltaTime=0,this.unscaledDeltaTime=0},e.checkEvery=function(e,t){return this.totalTime-t>=e},e}();g.deltaTime=0,g.unscaledDeltaTime=0,g.totalTime=0,g.unscaledTotalTime=0,g.timeScale=1,g.frameCount=0;var _,S=function(){function e(){this._timeInSeconds=0,this._repeats=!1,this._isDone=!1,this._elapsedTime=0}var t=e.prototype;return t.getContext=function(){return this.context},t.reset=function(){this._elapsedTime=0},t.stop=function(){this._isDone=!0},t.tick=function(){return!this._isDone&&this._elapsedTime>this._timeInSeconds&&(this._elapsedTime-=this._timeInSeconds,this._onTime(this),this._isDone||this._repeats||(this._isDone=!0)),this._elapsedTime+=g.deltaTime,this._isDone},t.initialize=function(e,t,n,i){this._timeInSeconds=e,this._repeats=t,this.context=n,this._onTime=i.bind(n)},t.unload=function(){this.context=null,this._onTime=null},s(e,[{key:"isDone",get:function(){return this._isDone}},{key:"elapsedTime",get:function(){return this._elapsedTime}}])}(),E=function(e){function t(){var t;return(t=e.apply(this,arguments)||this)._timers=[],t}h(t,e);var n=t.prototype;return n.update=function(){for(var e=this._timers.length-1;e>=0;e--)this._timers[e].tick()&&(this._timers[e].unload(),this._timers.splice(e,1))},n.schedule=function(e,t,n,i){var r=new S;return r.initialize(e,t,n,i),this._timers.push(r),r},t}(v);e.PerformanceWarningType=void 0,(_=e.PerformanceWarningType||(e.PerformanceWarningType={})).HIGH_EXECUTION_TIME="high_execution_time",_.HIGH_MEMORY_USAGE="high_memory_usage",_.HIGH_CPU_USAGE="high_cpu_usage",_.FREQUENT_GC="frequent_gc",_.LOW_FPS="low_fps",_.HIGH_ENTITY_COUNT="high_entity_count";var C=function(){function e(){this._systemData=new Map,this._systemStats=new Map,this._warnings=[],this._isEnabled=!1,this._maxRecentSamples=60,this._maxWarnings=100,this._thresholds={executionTime:{warning:16.67,critical:33.33},memoryUsage:{warning:100,critical:200},cpuUsage:{warning:70,critical:90},fps:{warning:45,critical:30},entityCount:{warning:1e3,critical:5e3}},this._fpsHistory=[],this._lastFrameTime=0,this._frameCount=0,this._fpsUpdateInterval=1e3,this._lastFpsUpdate=0,this._currentFps=60,this._memoryCheckInterval=5e3,this._lastMemoryCheck=0,this._memoryHistory=[],this._gcCount=0,this._lastGcCheck=0,this._gcCheckInterval=1e3}var t=e.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.startMonitoring=function(e){return this._isEnabled?performance.now():0},t.endMonitoring=function(e,t,n){if(void 0===n&&(n=0),this._isEnabled&&0!==t){var i=performance.now(),r=i-t,o={name:e,executionTime:r,entityCount:n,averageTimePerEntity:n>0?r/n:0,lastUpdateTime:i};this._systemData.set(e,o),this.updateStats(e,r)}},t.updateStats=function(e,t){var n=this._systemStats.get(e);n||(n={totalTime:0,averageTime:0,minTime:Number.MAX_VALUE,maxTime:0,executionCount:0,recentTimes:[],standardDeviation:0,percentile95:0,percentile99:0},this._systemStats.set(e,n)),n.totalTime+=t,n.executionCount++,n.averageTime=n.totalTime/n.executionCount,n.minTime=Math.min(n.minTime,t),n.maxTime=Math.max(n.maxTime,t),n.recentTimes.push(t),n.recentTimes.length>this._maxRecentSamples&&n.recentTimes.shift(),this.calculateAdvancedStats(n)},t.calculateAdvancedStats=function(e){if(0!==e.recentTimes.length){var t=e.recentTimes.reduce((function(e,t){return e+t}),0)/e.recentTimes.length,n=e.recentTimes.reduce((function(e,n){return e+Math.pow(n-t,2)}),0)/e.recentTimes.length;e.standardDeviation=Math.sqrt(n);var i=[].concat(e.recentTimes).sort((function(e,t){return e-t})),r=i.length;e.percentile95=i[Math.floor(.95*r)]||0,e.percentile99=i[Math.floor(.99*r)]||0}},t.getSystemData=function(e){return this._systemData.get(e)},t.getSystemStats=function(e){return this._systemStats.get(e)},t.getAllSystemData=function(){return new Map(this._systemData)},t.getAllSystemStats=function(){return new Map(this._systemStats)},t.getPerformanceReport=function(){if(!this._isEnabled)return"Performance monitoring is disabled.";var e=[];e.push("=== ECS Performance Report ==="),e.push("");for(var t,n=a(Array.from(this._systemStats.entries()).sort((function(e,t){return t[1].averageTime-e[1].averageTime})));!(t=n()).done;){var i=t.value,r=i[0],o=i[1],s=this._systemData.get(r);e.push("System: "+r),e.push(" Current: "+(null==s?void 0:s.executionTime.toFixed(2))+"ms ("+(null==s?void 0:s.entityCount)+" entities)"),e.push(" Average: "+o.averageTime.toFixed(2)+"ms"),e.push(" Min/Max: "+o.minTime.toFixed(2)+"ms / "+o.maxTime.toFixed(2)+"ms"),e.push(" Total: "+o.totalTime.toFixed(2)+"ms ("+o.executionCount+" calls)"),null!=s&&s.averageTimePerEntity&&s.averageTimePerEntity>0&&e.push(" Per Entity: "+s.averageTimePerEntity.toFixed(4)+"ms"),e.push("")}var c=Array.from(this._systemData.values()).reduce((function(e,t){return e+t.executionTime}),0);return e.push("Total Frame Time: "+c.toFixed(2)+"ms"),e.push("Systems Count: "+this._systemData.size),e.join("\n")},t.reset=function(){this._systemData.clear(),this._systemStats.clear()},t.resetSystem=function(e){this._systemData.delete(e),this._systemStats.delete(e)},t.getPerformanceWarnings=function(e){void 0===e&&(e=16.67);for(var t,n=[],i=a(this._systemData.entries());!(t=i()).done;){var r=t.value,o=r[0],s=r[1];s.executionTime>e&&n.push(o+": "+s.executionTime.toFixed(2)+"ms (>"+e+"ms)")}return n},t.setMaxRecentSamples=function(e){this._maxRecentSamples=e;for(var t,n=a(this._systemStats.values());!(t=n()).done;)for(var i=t.value;i.recentTimes.length>e;)i.recentTimes.shift()},s(e,[{key:"isEnabled",get:function(){return this._isEnabled}}],[{key:"instance",get:function(){return e._instance||(e._instance=new e),e._instance}}])}(),T=function(){function e(e,t,n){void 0===t&&(t=100),void 0===n&&(n=1024),this._objects=[],this._createFn=e,this._maxSize=t,this._objectSize=n,this._stats={size:0,maxSize:t,totalCreated:0,totalObtained:0,totalReleased:0,hitRate:0,estimatedMemoryUsage:0}}e.getPool=function(t,n,i){void 0===n&&(n=100),void 0===i&&(i=1024);var r=this._pools.get(t);return r||(r=new e((function(){return new t}),n,i),this._pools.set(t,r)),r};var t=e.prototype;return t.obtain=function(){if(this._stats.totalObtained++,this._objects.length>0){var e=this._objects.pop();return this._stats.size--,this._updateHitRate(),this._updateMemoryUsage(),e}return this._stats.totalCreated++,this._updateHitRate(),this._createFn()},t.release=function(e){e&&(this._stats.totalReleased++,this._stats.sizet;){var n=this._objects.pop();n&&(n.reset(),this._stats.size--)}this._updateMemoryUsage()},t.prewarm=function(e){for(var t=Math.min(e,this._maxSize-this._objects.length),n=0;ne&&this.compact(e)},t.getAvailableCount=function(){return this._objects.length},t.isEmpty=function(){return 0===this._objects.length},t.isFull=function(){return this._objects.length>=this._maxSize},e.getAllPoolTypes=function(){return Array.from(this._pools.keys())},e.getAllPoolStats=function(){for(var e,t={},n=a(this._pools);!(e=n()).done;){var i=e.value,r=i[0],o=i[1];t[r.name||r.toString()]=o.getStats()}return t},e.compactAllPools=function(){for(var e,t=a(this._pools.values());!(e=t()).done;){e.value.compact()}},e.clearAllPools=function(){for(var e,t=a(this._pools.values());!(e=t()).done;){e.value.clear()}this._pools.clear()},e.getGlobalStatsString=function(){var e=this.getAllPoolStats(),t=["=== Object Pool Global Statistics ===",""];if(0===Object.keys(e).length)return t.push("No pools registered"),t.join("\n");for(var n=0,i=Object.entries(e);nthis.autoCompactInterval&&(this.compactAllPools(),this.lastCompactTime=e)},t.createPool=function(e,t,n,i){void 0===n&&(n=100),void 0===i&&(i=1024);var r=this.pools.get(e);return r||(r=new T(t,n,i),this.pools.set(e,r)),r},t.removePool=function(e){var t=this.pools.get(e);return!!t&&(t.clear(),this.pools.delete(e),!0)},t.getPoolNames=function(){return Array.from(this.pools.keys())},t.getPoolCount=function(){return this.pools.size},t.compactAllPools=function(){for(var e,t=a(this.pools.values());!(e=t()).done;){e.value.compact()}},t.clearAllPools=function(){for(var e,t=a(this.pools.values());!(e=t()).done;){e.value.clear()}},t.getAllStats=function(){for(var e,t=new Map,n=a(this.pools);!(e=n()).done;){var i=e.value,r=i[0],o=i[1];t.set(r,o.getStats())}return t},t.getGlobalStats=function(){for(var e,t=0,n=0,i=0,r=0,o=0,s=0,c=a(this.pools.values());!(e=c()).done;){var u=e.value.getStats();t+=u.size,n+=u.maxSize,i+=u.totalCreated,r+=u.totalObtained,o+=u.totalReleased,s+=u.estimatedMemoryUsage}return{size:t,maxSize:n,totalCreated:i,totalObtained:r,totalReleased:o,hitRate:0===r?0:(r-i)/r,estimatedMemoryUsage:s}},t.getStatsString=function(){var e=["=== Pool Manager Statistics ===",""];if(0===this.pools.size)return e.push("No pools registered"),e.join("\n");var t=this.getGlobalStats();e.push("Total Pools: "+this.pools.size),e.push("Global Hit Rate: "+(100*t.hitRate).toFixed(1)+"%"),e.push("Global Memory Usage: "+(t.estimatedMemoryUsage/1024).toFixed(1)+" KB"),e.push("");for(var n,i=a(this.pools);!(n=i()).done;){var r=n.value,o=r[0],s=r[1].getStats();e.push(o+":"),e.push(" Size: "+s.size+"/"+s.maxSize),e.push(" Hit Rate: "+(100*s.hitRate).toFixed(1)+"%"),e.push(" Memory: "+(s.estimatedMemoryUsage/1024).toFixed(1)+" KB"),e.push("")}return e.join("\n")},t.setAutoCompactInterval=function(e){this.autoCompactInterval=e},t.prewarmAllPools=function(){for(var e,t=a(this.pools.values());!(e=t()).done;){var n=e.value,i=n.getStats(),r=Math.floor(.2*i.maxSize);n.prewarm(r)}},t.reset=function(){this.clearAllPools(),this.pools.clear(),this.lastCompactTime=0},e}(),w=function(){function e(){}return e.create=function(e){if(e<0||e>=64)throw new Error("Bit index "+e+" out of range [0, 63]");return e<32?{lo:1<>>0,hi:0}},e.hasAny=function(e,t){return 0!==(e.lo&t.lo)||0!==(e.hi&t.hi)},e.hasAll=function(e,t){return(e.lo&t.lo)===t.lo&&(e.hi&t.hi)===t.hi},e.hasNone=function(e,t){return 0===(e.lo&t.lo)&&0===(e.hi&t.hi)},e.isZero=function(e){return 0===e.lo&&0===e.hi},e.equals=function(e,t){return e.lo===t.lo&&e.hi===t.hi},e.setBit=function(e,t){if(t<0||t>=64)throw new Error("Bit index "+t+" out of range [0, 63]");t<32?e.lo|=1<=64)throw new Error("Bit index "+t+" out of range [0, 63]");t<32?e.lo&=~(1<1?n-1:0),r=1;r1?n-1:0),r=1;r1?n-1:0),r=1;r1?n-1:0),r=1;r1?n-1:0),r=1;r2?r-2:0),s=2;s2?r-2:0),s=2;s0?i=this.freeIndices.pop():(i=this._size)>=this._capacity&&this.resize(2*this._capacity),this.entityToIndex.set(e,i),this.indexToEntity[i]=e,this.updateComponentAtIndex(i,t),this._size++}},t.updateComponentAtIndex=function(e,t){var n=this.indexToEntity[e],i=new Map,r=this.type.__highPrecisionFields||new Set,o=this.type.__serializeMapFields||new Set,s=this.type.__serializeSetFields||new Set,a=this.type.__serializeArrayFields||new Set,c=this.type.__deepCopyFields||new Set;for(var u in t)if(t.hasOwnProperty(u)&&"id"!==u){var h=t[u],l=typeof h;if("number"===l)if(r.has(u)||!this.fields.has(u))i.set(u,h);else this.fields.get(u)[e]=h;else if("boolean"===l&&this.fields.has(u)){this.fields.get(u)[e]=h?1:0}else if(this.stringFields.has(u)){this.stringFields.get(u)[e]=String(h)}else if(this.serializedFields.has(u)){this.serializedFields.get(u)[e]=this.serializeValue(h,u,o,s,a)}else c.has(u)?i.set(u,this.deepClone(h)):i.set(u,h)}i.size>0&&this.complexFields.set(n,i)},t.serializeValue=function(t,n,i,r,o){try{return i.has(n)&&t instanceof Map?JSON.stringify(Array.from(t.entries())):r.has(n)&&t instanceof Set?JSON.stringify(Array.from(t)):(o.has(n)&&Array.isArray(t),JSON.stringify(t))}catch(t){return e._logger.warn("SoA序列化字段 "+n+" 失败:",t),"{}"}},t.deserializeValue=function(t,n,i,r,o){try{var s=JSON.parse(t);return i.has(n)?new Map(s):r.has(n)?new Set(s):(o.has(n),s)}catch(t){return e._logger.warn("SoA反序列化字段 "+n+" 失败:",t),null}},t.deepClone=function(e){var t=this;if(null===e||"object"!=typeof e)return e;if(e instanceof Date)return new Date(e.getTime());if(e instanceof Array)return e.map((function(e){return t.deepClone(e)}));if(e instanceof Map){for(var n,i=new Map,r=a(e.entries());!(n=r()).done;){var o=n.value,s=o[0],c=o[1];i.set(s,this.deepClone(c))}return i}if(e instanceof Set){for(var u,h=new Set,l=a(e.values());!(u=l()).done;){var d=u.value;h.add(this.deepClone(d))}return h}var f={};for(var p in e)e.hasOwnProperty(p)&&(f[p]=this.deepClone(e[p]));return f},t.getComponent=function(e){var t=this.entityToIndex.get(e);if(void 0===t)return null;for(var n,i=new this.type,r=this.type.__serializeMapFields||new Set,o=this.type.__serializeSetFields||new Set,s=this.type.__serializeArrayFields||new Set,c=a(this.fields.entries());!(n=c()).done;){var u=n.value,h=u[0],l=u[1][t],d=this.getFieldType(h);i[h]="boolean"===d?1===l:l}for(var f,p=a(this.stringFields.entries());!(f=p()).done;){var m=f.value,y=m[0],v=m[1];i[y]=v[t]}for(var g,_=a(this.serializedFields.entries());!(g=_()).done;){var S=g.value,E=S[0],C=S[1][t];C&&(i[E]=this.deserializeValue(C,E,r,o,s))}var T=this.complexFields.get(e);if(T)for(var b,M=a(T.entries());!(b=M()).done;){var w=b.value,A=w[0],I=w[1];i[A]=I}return i},t.getFieldType=function(e){return typeof(new this.type)[e]},t.hasComponent=function(e){return this.entityToIndex.has(e)},t.removeComponent=function(e){var t=this.entityToIndex.get(e);if(void 0===t)return null;var n=this.getComponent(e);return this.complexFields.delete(e),this.entityToIndex.delete(e),this.freeIndices.push(t),this._size--,n},t.resize=function(e){for(var t,n=a(this.fields.entries());!(t=n()).done;){var i=t.value,r=i[0],o=i[1],s=void 0;(s=o instanceof Float32Array?new Float32Array(e):o instanceof Float64Array?new Float64Array(e):new Int32Array(e)).set(o),this.fields.set(r,s)}for(var c,u=a(this.stringFields.entries());!(c=u()).done;){for(var h=c.value,l=h[0],d=h[1],f=new Array(e),p=0;p=this.maxComponents)throw new Error("Maximum number of component types ("+this.maxComponents+") exceeded");var n=this.nextBitIndex++;return this.componentTypes.set(e,n),this.componentNameToType.set(t,e),this.componentNameToId.set(t,n),n},e.getBitMask=function(e){var t=this.componentTypes.get(e);if(void 0===t){var n=O(e);throw new Error("Component type "+n+" is not registered")}return w.create(t)},e.getBitIndex=function(e){var t=this.componentTypes.get(e);if(void 0===t){var n=O(e);throw new Error("Component type "+n+" is not registered")}return t},e.isRegistered=function(e){return this.componentTypes.has(e)},e.getComponentType=function(e){return this.componentNameToType.get(e)||null},e.getAllRegisteredTypes=function(){return new Map(this.componentTypes)},e.getAllComponentNames=function(){return new Map(this.componentNameToType)},e.getComponentId=function(e){return this.componentNameToId.get(e)},e.registerComponentByName=function(e){if(this.componentNameToId.has(e))return this.componentNameToId.get(e);if(this.nextBitIndex>=this.maxComponents)throw new Error("Maximum number of component types ("+this.maxComponents+") exceeded");var t=this.nextBitIndex++;return this.componentNameToId.set(e,t),t},e.createSingleComponentMask=function(e){var t="single:"+e;if(this.maskCache.has(t))return this.maskCache.get(t);var n=this.getComponentId(e);if(void 0===n)throw new Error("Component type "+e+" is not registered");var i=w.create(n);return this.maskCache.set(t,i),i},e.createComponentMask=function(e){var t="multi:"+[].concat(e).sort().join(",");if(this.maskCache.has(t))return this.maskCache.get(t);for(var n,i=w.clone(w.ZERO),r=a(e);!(n=r()).done;){var o=n.value,s=this.getComponentId(o);if(void 0!==s){var c=w.create(s);w.orInPlace(i,c)}}return this.maskCache.set(t,i),i},e.clearMaskCache=function(){this.maskCache.clear()},e.reset=function(){this.componentTypes.clear(),this.componentNameToType.clear(),this.componentNameToId.clear(),this.maskCache.clear(),this.nextBitIndex=0},e}();F._logger=k("ComponentStorage"),F.componentTypes=new Map,F.componentNameToType=new Map,F.componentNameToId=new Map,F.maskCache=new Map,F.nextBitIndex=0,F.maxComponents=64;var W=function(){function e(e){this.dense=[],this.entityIds=[],this.entityToIndex=new Map,this.componentType=e,F.isRegistered(e)||F.register(e)}var t=e.prototype;return t.addComponent=function(e,t){if(this.entityToIndex.has(e))throw new Error("Entity "+e+" already has component "+O(this.componentType));var n=this.dense.length;this.dense.push(t),this.entityIds.push(e),this.entityToIndex.set(e,n)},t.getComponent=function(e){var t=this.entityToIndex.get(e);return void 0!==t?this.dense[t]:null},t.hasComponent=function(e){return this.entityToIndex.has(e)},t.removeComponent=function(e){var t=this.entityToIndex.get(e);if(void 0===t)return null;var n=this.dense[t],i=this.dense.length-1;if(t!==i){var r=this.dense[i],o=this.entityIds[i];this.dense[t]=r,this.entityIds[t]=o,this.entityToIndex.set(o,t)}return this.dense.pop(),this.entityIds.pop(),this.entityToIndex.delete(e),n},t.forEach=function(e){for(var t=0;t1?t-1:0),i=1;i1?n-1:0),r=1;r=0;t--)e.push(this.buffer[t].id),this.buffer[t].destroy();if(this._scene&&this._scene.identifierPool)for(var n,i=a(e);!(n=i()).done;){var r=n.value;this._scene.identifierPool.checkIn(r)}this.buffer.length=0,this._idToEntity.clear(),this._nameToEntities.clear(),this._entitiesToAdd.length=0,this._entitiesToRemove.length=0},t.updateLists=function(){if(this._entitiesToAdd.length>0){for(var e,t=a(this._entitiesToAdd);!(e=t()).done;){var n=e.value;this.addImmediate(n)}this._entitiesToAdd.length=0}if(this._entitiesToRemove.length>0){for(var i,r=a(this._entitiesToRemove);!(i=r()).done;){var o=i.value;this.removeImmediate(o)}this._entitiesToRemove.length=0}},t.update=function(){this._isUpdating=!0;try{if(this._enableEntityDirectUpdate)for(var e=0;e0?t[0]:null},t.findEntitiesByName=function(e){return this._nameToEntities.get(e)||[]},t.findEntityById=function(e){return this._idToEntity.get(e)||null},t.findEntitiesByTag=function(e){for(var t,n=[],i=a(this.buffer);!(t=i()).done;){var r=t.value;r.tag===e&&n.push(r)}return n},t.findEntitiesWithComponent=function(e){for(var t,n=[],i=a(this.buffer);!(t=i()).done;){var r=t.value;r.hasComponent(e)&&n.push(r)}return n},t.forEach=function(e){for(var t,n=a(this.buffer);!(t=n()).done;){e(t.value)}},t.forEachWhere=function(e,t){for(var n,i=a(this.buffer);!(n=i()).done;){var r=n.value;e(r)&&t(r)}},t.updateNameIndex=function(e,t){if(e.name)if(t){var n=this._nameToEntities.get(e.name);n||(n=[],this._nameToEntities.set(e.name,n)),n.push(e)}else{var i=this._nameToEntities.get(e.name);if(i){var r=i.indexOf(e);-1!==r&&(i.splice(r,1),0===i.length&&this._nameToEntities.delete(e.name))}}},t.getStats=function(){for(var e,t=0,n=a(this.buffer);!(e=n()).done;){var i=e.value;i.enabled&&!i.isDestroyed&&t++}return{totalEntities:this.buffer.length,activeEntities:t,pendingAdd:this._entitiesToAdd.length,pendingRemove:this._entitiesToRemove.length,nameIndexSize:this._nameToEntities.size}},s(e,[{key:"count",get:function(){return this.buffer.length}}])}(),Y=function(){function e(){this._processors=[],this._isDirty=!1}var t=e.prototype;return t.setDirty=function(){this._isDirty=!0},t.add=function(e){this._processors.push(e),this.setDirty()},t.remove=function(e){var t=this._processors.indexOf(e);-1!==t&&this._processors.splice(t,1)},t.getProcessor=function(e){for(var t,n=a(this._processors);!(t=n()).done;){var i=t.value;if(i instanceof e)return i}return null},t.begin=function(){this.sortProcessors()},t.end=function(){for(var t,n=a(this._processors);!(t=n()).done;){var i=t.value;try{i.reset()}catch(t){e._logger.error("Error in processor "+L(i)+":",t)}}this._isDirty=!1,this._processors.length=0},t.update=function(){this.sortProcessors();for(var t,n=a(this._processors);!(t=n()).done;){var i=t.value;try{i.update()}catch(t){e._logger.error("Error in processor "+L(i)+":",t)}}},t.lateUpdate=function(){for(var e,t=a(this._processors);!(e=t()).done;){e.value.lateUpdate()}},t.sortProcessors=function(){this._isDirty&&(this._processors.sort((function(e,t){return e.updateOrder-t.updateOrder})),this._isDirty=!1)},s(e,[{key:"processors",get:function(){return this._processors}},{key:"count",get:function(){return this._processors.length}}])}();Y._logger=k("EntityProcessorList");var Q=function(){function e(e,t){void 0===e&&(e=100),void 0===t&&(t=1024),this._nextAvailableIndex=0,this._freeIndices=[],this._generations=new Map,this._pendingRecycle=[],this._recycleDelay=100,this._stats={totalAllocated:0,totalRecycled:0,currentActive:0,memoryExpansions:0},this._recycleDelay=e,this._expansionBlockSize=t,this._preAllocateGenerations(0,this._expansionBlockSize)}var t=e.prototype;return t.checkOut=function(){var t;if(this._processDelayedRecycle(),this._freeIndices.length>0)t=this._freeIndices.pop();else{if(this._nextAvailableIndex>e.MAX_INDEX)throw new Error("实体索引已达到框架设计限制 ("+e.MAX_INDEX+")。这意味着您已经分配了超过65535个不同的实体索引。这是16位索引设计的限制,考虑优化实体回收策略或升级到64位ID设计。");t=this._nextAvailableIndex++,this._ensureGenerationCapacity(t)}var n=this._generations.get(t)||1;return this._stats.totalAllocated++,this._stats.currentActive++,this._packId(t,n)},t.checkIn=function(e){var t=this._unpackIndex(e),n=this._unpackGeneration(e);return!!this._isValidId(t,n)&&(!this._pendingRecycle.some((function(e){return e.index===t&&e.generation===n}))&&(this._pendingRecycle.push({index:t,generation:n,timestamp:Date.now()}),this._stats.currentActive--,this._stats.totalRecycled++,!0))},t.isValid=function(e){var t=this._unpackIndex(e),n=this._unpackGeneration(e);return this._isValidId(t,n)},t.getStats=function(){for(var t,n=0,i=0,r=a(this._generations);!(t=r()).done;){var o=t.value,s=o[0],c=o[1];s0?n/i:1;return{totalAllocated:this._stats.totalAllocated,totalRecycled:this._stats.totalRecycled,currentActive:this._stats.currentActive,currentlyFree:this._freeIndices.length,pendingRecycle:this._pendingRecycle.length,maxPossibleEntities:e.MAX_INDEX+1,maxUsedIndex:this._nextAvailableIndex-1,memoryUsage:this._calculateMemoryUsage(),memoryExpansions:this._stats.memoryExpansions,averageGeneration:Math.round(100*u)/100,generationStorageSize:this._generations.size}},t.forceProcessDelayedRecycle=function(){this._processDelayedRecycle(!0)},t._processDelayedRecycle=function(t){if(void 0===t&&(t=!1),0!==this._pendingRecycle.length){for(var n,i=Date.now(),r=[],o=[],s=a(this._pendingRecycle);!(n=s()).done;){var c=n.value;t||i-c.timestamp>=this._recycleDelay?r.push(c):o.push(c)}for(var u=0,h=r;ue.MAX_GENERATION&&(d=1),this._generations.set(l.index,d),this._freeIndices.push(l.index)}}this._pendingRecycle=o}},t._preAllocateGenerations=function(t,n){for(var i=0;i>>16&65535},t._isValidId=function(e,t){if(e<0||e>=this._nextAvailableIndex)return!1;var n=this._generations.get(e);return void 0!==n&&n===t},e}();Q.MAX_INDEX=65535,Q.MAX_GENERATION=65535;var V=function(){function e(){this._dense=[],this._sparse=new Map}var t=e.prototype;return t.add=function(e){if(this._sparse.has(e))return!1;var t=this._dense.length;return this._dense.push(e),this._sparse.set(e,t),!0},t.remove=function(e){var t=this._sparse.get(e);if(void 0===t)return!1;var n=this._dense.length-1;if(t!==n){var i=this._dense[n];this._dense[t]=i,this._sparse.set(i,t)}return this._dense.pop(),this._sparse.delete(e),!0},t.has=function(e){return this._sparse.has(e)},t.getIndex=function(e){return this._sparse.get(e)},t.getByIndex=function(e){return this._dense[e]},t.forEach=function(e){for(var t=0;t=this._dense.length||this._dense[s]!==o)return!1}return!0},s(e,[{key:"size",get:function(){return this._dense.length}},{key:"isEmpty",get:function(){return 0===this._dense.length}}])}(),X=function(e){function t(){return e.call(this)||this}return h(t,e),t.prototype.reset=function(){this.clear()},t}(y(Set)),Z=function(){function e(){this._componentMasks=[],this._componentToEntities=new Map,this._entities=new V}var t=e.prototype;return t.addEntity=function(e){this._entities.has(e)&&this.removeEntity(e);for(var t,n=w.clone(w.ZERO),i=new Set,r=a(e.components);!(t=r()).done;){var o=t.value.constructor;i.add(o),F.isRegistered(o)||F.register(o);var s=F.getBitMask(o);w.orInPlace(n,s)}this._entities.add(e);for(var c=this._entities.getIndex(e);this._componentMasks.length<=c;)this._componentMasks.push(w.clone(w.ZERO));this._componentMasks[c]=n,this.updateComponentMappings(e,i,!0)},t.removeEntity=function(e){var t=this._entities.getIndex(e);if(void 0!==t){var n=this.getEntityComponentTypes(e);this.updateComponentMappings(e,n,!1),this._entities.remove(e);var i=this._componentMasks.length-1;t!==i&&(this._componentMasks[t]=this._componentMasks[i]),this._componentMasks.pop()}},t.queryByComponent=function(e){var t=this._componentToEntities.get(e);return t?new Set(t):new Set},t.queryMultipleAnd=function(t){var n=this;if(0===t.length)return new Set;if(1===t.length)return this.queryByComponent(t[0]);for(var i,r=w.clone(w.ZERO),o=a(t);!(i=o()).done;){var s=i.value;if(!F.isRegistered(s))return new Set;var c=F.getBitMask(s);w.orInPlace(r,c)}var u=e._entitySetPool.obtain();return this._entities.forEach((function(e,t){var i=n._componentMasks[t];w.hasAll(i,r)&&u.add(e)})),u},t.queryMultipleOr=function(t){var n=this;if(0===t.length)return new Set;if(1===t.length)return this.queryByComponent(t[0]);for(var i,r=w.clone(w.ZERO),o=a(t);!(i=o()).done;){var s=i.value;if(F.isRegistered(s)){var c=F.getBitMask(s);w.orInPlace(r,c)}}if(w.equals(r,w.ZERO))return new Set;var u=e._entitySetPool.obtain();return this._entities.forEach((function(e,t){var i=n._componentMasks[t];w.hasAny(i,r)&&u.add(e)})),u},t.hasComponent=function(e,t){var n=this._entities.getIndex(e);if(void 0===n)return!1;if(!F.isRegistered(t))return!1;var i=this._componentMasks[n],r=F.getBitMask(t);return w.hasAny(i,r)},t.getEntityMask=function(e){var t=this._entities.getIndex(e);if(void 0!==t)return this._componentMasks[t]},t.getAllEntities=function(){return this._entities.toArray()},t.forEach=function(e){var t=this;this._entities.forEach((function(n,i){e(n,t._componentMasks[i],i)}))},t.clear=function(){this._entities.clear(),this._componentMasks.length=0;for(var t,n=a(this._componentToEntities.values());!(t=n()).done;){var i=t.value;e._entitySetPool.release(i)}this._componentToEntities.clear()},t.getMemoryStats=function(){for(var e,t=this._entities.getMemoryStats(),n=16*this._componentMasks.length,i=16*this._componentToEntities.size,r=a(this._componentToEntities.values());!(e=r()).done;){i+=8*e.value.size}return{entitiesMemory:t.totalMemory,masksMemory:n,mappingsMemory:i,totalMemory:t.totalMemory+n+i}},t.validate=function(){if(!this._entities.validate())return!1;if(this._componentMasks.length!==this._entities.size)return!1;for(var e,t=new Set,n=a(this._componentToEntities.values());!(e=n()).done;)for(var i,r=a(e.value);!(i=r()).done;){var o=i.value;t.add(o)}for(var s,c=a(t);!(s=c()).done;){var u=s.value;if(!this._entities.has(u))return!1}return!0},t.getEntityComponentTypes=function(e){for(var t,n=new Set,i=a(e.components);!(t=i()).done;){var r=t.value;n.add(r.constructor)}return n},t.updateComponentMappings=function(t,n,i){for(var r,o=a(n);!(r=o()).done;){var s=r.value,c=this._componentToEntities.get(s);i?(c||(c=e._entitySetPool.obtain(),this._componentToEntities.set(s,c)),c.add(t)):c&&(c.delete(t),0===c.size&&(this._componentToEntities.delete(s),e._entitySetPool.release(c)))}},s(e,[{key:"size",get:function(){return this._entities.size}},{key:"isEmpty",get:function(){return this._entities.isEmpty}}])}();Z._entitySetPool=T.getPool(X,50,512);var K,J=function(){function e(){this._queryCount=0,this._totalQueryTime=0,this._lastUpdated=Date.now(),this._sparseSet=new Z}var t=e.prototype;return t.addEntity=function(e){this._sparseSet.addEntity(e),this._lastUpdated=Date.now()},t.removeEntity=function(e){this._sparseSet.removeEntity(e),this._lastUpdated=Date.now()},t.query=function(e){var t=performance.now(),n=this._sparseSet.queryByComponent(e);return this._queryCount++,this._totalQueryTime+=performance.now()-t,n},t.queryMultiple=function(e,t){var n,i=performance.now();return n=0===e.length?new Set:1===e.length?this.query(e[0]):"AND"===t?this._sparseSet.queryMultipleAnd(e):this._sparseSet.queryMultipleOr(e),this._queryCount++,this._totalQueryTime+=performance.now()-i,n},t.clear=function(){this._sparseSet.clear(),this._lastUpdated=Date.now()},t.getStats=function(){var e=this._sparseSet.getMemoryStats();return{size:this._sparseSet.size,memoryUsage:e.totalMemory,queryCount:this._queryCount,avgQueryTime:this._queryCount>0?this._totalQueryTime/this._queryCount:0,lastUpdated:this._lastUpdated}},e}(),$=function(){function e(){this._index=new J}var t=e.prototype;return t.addEntity=function(e){this._index.addEntity(e)},t.removeEntity=function(e){this._index.removeEntity(e)},t.query=function(e){return this._index.query(e)},t.queryMultiple=function(e,t){return this._index.queryMultiple(e,t)},t.getStats=function(){return this._index.getStats()},t.clear=function(){this._index.clear()},e}(),ee=function(){function e(){this._archetypes=new Map,this._entityToArchetype=new Map,this._componentToArchetypes=new Map,this._queryCache=new Map,this._cacheTimeout=5e3,this._maxCacheSize=100}var t=e.prototype;return t.addEntity=function(e){var t=this.getEntityComponentTypes(e),n=this.generateArchetypeId(t),i=this._archetypes.get(n);i||(i=this.createArchetype(t)),i.entities.push(e),i.updatedAt=Date.now(),this._entityToArchetype.set(e,i),this.updateComponentIndexes(i,t,!0),this.invalidateQueryCache()},t.removeEntity=function(e){var t=this._entityToArchetype.get(e);if(t){var n=t.entities.indexOf(e);-1!==n&&(t.entities.splice(n,1),t.updatedAt=Date.now()),this._entityToArchetype.delete(e),this.invalidateQueryCache()}},t.updateEntity=function(e){var t=this._entityToArchetype.get(e),n=this.getEntityComponentTypes(e),i=this.generateArchetypeId(n);if(!t||t.id!==i){if(t){var r=t.entities.indexOf(e);-1!==r&&(t.entities.splice(r,1),t.updatedAt=Date.now())}var o=this._archetypes.get(i);o||(o=this.createArchetype(n)),o.entities.push(e),o.updatedAt=Date.now(),this._entityToArchetype.set(e,o),t&&this.updateComponentIndexes(t,t.componentTypes,!1),this.updateComponentIndexes(o,n,!0),this.invalidateQueryCache()}},t.queryArchetypes=function(e,t){void 0===t&&(t="AND");var n=performance.now(),i=t+":"+e.map((function(e){return O(e)})).sort().join(","),r=this._queryCache.get(i);if(r&&Date.now()-r.timestamp0&&this.clearQueryCache()}},t.addEntitiesUnchecked=function(e){if(0!==e.length){for(var t,n=a(e);!(t=n()).done;){var i=t.value;this.entities.push(i)}for(var r,o=a(e);!(r=o()).done;){var s=r.value;this.addEntityToIndexes(s),this.componentIndexManager.addEntity(s),this.archetypeSystem.addEntity(s)}this.clearQueryCache()}},t.removeEntity=function(e){var t=this.entities.indexOf(e);-1!==t&&(this.entities.splice(t,1),this.removeEntityFromIndexes(e),this.componentIndexManager.removeEntity(e),this.archetypeSystem.removeEntity(e),this.clearQueryCache(),this._version++)},t.updateEntity=function(e){this.entities.includes(e)?(this.removeEntityFromIndexes(e),this.archetypeSystem.updateEntity(e),this.componentIndexManager.removeEntity(e),this.componentIndexManager.addEntity(e),this.addEntityToIndexes(e),this.clearQueryCache(),this._version++):this.addEntity(e)},t.addEntityToIndexes=function(e){var t=e.componentMask.toString();(this.entityIndex.byMask.get(t)||this.createAndSetMaskIndex(t)).add(e);for(var n=e.components,i=0;i0){this.queryStats.archetypeHits++;for(var u,h=a(c.archetypes);!(u=h()).done;){var l,d=u.value;(l=s).push.apply(l,d.entities)}}else try{if(1===n.length){this.queryStats.indexHits++;var f=this.componentIndexManager.query(n[0]);s=Array.from(f)}else{var p=this.componentIndexManager.queryMultiple(n,"AND");s=Array.from(p)}}catch(e){s=[]}return this.addToCache(r,s),{entities:s,count:s.length,executionTime:performance.now()-e,fromCache:!1}},t.queryMultipleComponents=function(e){for(var t,n=null,i=1/0,r=a(e);!(t=r()).done;){var o=t.value,s=this.entityIndex.byComponentType.get(o);if(!s||0===s.size)return[];s.size0){this.queryStats.archetypeHits++,s=[];for(var u,h=a(c.archetypes);!(u=h()).done;){var l,d=u.value;(l=s).push.apply(l,d.entities)}}else{var f=this.componentIndexManager.queryMultiple(n,"OR");s=Array.from(f)}return this.addToCache(r,s),{entities:s,count:s.length,executionTime:performance.now()-e,fromCache:!1}},t.queryNone=function(){var e=performance.now();this.queryStats.totalQueries++;for(var t=arguments.length,n=new Array(t),i=0;ithis.cacheTimeout||t.version!==this._version?(this.queryCache.delete(e),null):(t.hitCount++,t.entities):null},t.addToCache=function(e,t){this.queryCache.size>=this.cacheMaxSize&&this.cleanupCache(),this.queryCache.set(e,{entities:t,timestamp:Date.now(),hitCount:0,version:this._version})},t.cleanupCache=function(){for(var e,t=Date.now(),n=a(this.queryCache.entries());!(e=n()).done;){var i=e.value,r=i[0];t-i[1].timestamp>this.cacheTimeout&&this.queryCache.delete(r)}if(this.queryCache.size>=this.cacheMaxSize){for(var o,s=1/0,c="",u=1/0,h=a(this.queryCache.entries());!(o=h()).done;){var l=o.value,d=l[0],f=l[1];(f.hitCount0?(this.queryStats.cacheHits/this.queryStats.totalQueries*100).toFixed(2)+"%":"0%"}),optimizationStats:{componentIndex:this.componentIndexManager.getStats(),archetypeSystem:this.archetypeSystem.getAllArchetypes().map((function(e){return{id:e.id,componentTypes:e.componentTypes.map((function(e){return O(e)})),entityCount:e.entities.length}}))},cacheStats:{size:this.queryCache.size,hitRate:this.queryStats.totalQueries>0?(this.queryStats.cacheHits/this.queryStats.totalQueries*100).toFixed(2)+"%":"0%"}}},t.getEntityArchetype=function(e){return this.archetypeSystem.getEntityArchetype(e)},s(e,[{key:"version",get:function(){return this._version}}])}(),re=function(){function e(e){this._logger=k("QueryBuilder"),this.conditions=[],this.querySystem=e}var t=e.prototype;return t.withAll=function(){for(var e=arguments.length,t=new Array(e),n=0;n0},t.getListenerCount=function(e){var t=this.listeners.get(e);return t?t.length:0},t.clear=function(){this.listeners.clear(),this.stats.clear(),this.clearAllBatches()},t.setMaxListeners=function(e){this.maxListeners=e},t.addListener=function(t,n,i){var r=this.listeners.get(t);if(r||(r=[],this.listeners.set(t,r)),r.length>=this.maxListeners)return e._logger.warn("事件类型 "+t+" 的监听器数量超过最大限制 ("+this.maxListeners+")"),"";var o="listener_"+this.nextListenerId++,s={handler:n,config:c({priority:0},i),id:o};return r.push(s),this.stats.has(t)||this.stats.set(t,this.createEmptyStats(t)),o},t.executeEvent=function(){var t=i(d().m((function t(n,r){var o,s,c,u,h,l,f,p,m,y;return d().w((function(t){for(;;)switch(t.n){case 0:if((o=this.listeners.get(n))&&0!==o.length){t.n=1;break}return t.a(2);case 1:for(s=performance.now(),c=[],u=this.sortListenersByPriority(o),h=u.filter((function(e){return!e.config.async})),l=u.filter((function(e){return e.config.async})),f=a(h);!(p=f()).done;){m=p.value;try{m.config.context?m.handler.call(m.config.context,r):m.handler(r),m.config.once&&c.push(m.id)}catch(t){e._logger.error("同步事件处理器执行错误 "+n+":",t)}}return y=l.map(function(){var t=i(d().m((function t(i){var o;return d().w((function(t){for(;;)switch(t.p=t.n){case 0:if(t.p=0,!i.config.context){t.n=2;break}return t.n=1,i.handler.call(i.config.context,r);case 1:t.n=3;break;case 2:return t.n=3,i.handler(r);case 3:i.config.once&&c.push(i.id),t.n=5;break;case 4:t.p=4,o=t.v,e._logger.error("异步事件处理器执行错误 "+n+":",o);case 5:return t.a(2)}}),t,null,[[0,4]])})));return function(e){return t.apply(this,arguments)}}()),t.n=2,Promise.all(y);case 2:this.removeListeners(n,c),this.updateStats(n,performance.now()-s);case 3:return t.a(2)}}),t,this)})));return function(e,n){return t.apply(this,arguments)}}(),t.sortListenersByPriority=function(e){return e.slice().sort((function(e,t){return(t.config.priority||0)-(e.config.priority||0)}))},t.removeListeners=function(e,t){if(0!==t.length){var n=this.listeners.get(e);if(n){for(var i,r=function(){var e=i.value,t=n.findIndex((function(t){return t.id===e}));-1!==t&&n.splice(t,1)},o=a(t);!(i=o()).done;)r();0===n.length&&(this.listeners.delete(e),this.stats.delete(e))}}},t.addToBatch=function(e,t){var n=this,i=this.batchQueue.get(e);i||(i=[],this.batchQueue.set(e,i)),i.push(t);var r=this.batchConfigs.get(e);if(i.length>=r.batchSize)this.flushBatch(e);else if(!this.batchTimers.has(e)){var o=setTimeout((function(){n.flushBatch(e)}),r.delay);this.batchTimers.set(e,o)}},t.processBatch=function(){var e=i(d().m((function e(t,n){var i;return d().w((function(e){for(;;)switch(e.n){case 0:return i={type:t,events:n,count:n.length,timestamp:Date.now()},e.n=1,this.executeEvent(t+":batch",i);case 1:return e.a(2)}}),e,this)})));return function(t,n){return e.apply(this,arguments)}}(),t.clearBatch=function(e){this.batchQueue.delete(e);var t=this.batchTimers.get(e);t&&(clearTimeout(t),this.batchTimers.delete(e))},t.clearAllBatches=function(){this.batchQueue.clear();for(var e,t=a(this.batchTimers.values());!(e=t()).done;){var n=e.value;clearTimeout(n)}this.batchTimers.clear(),this.batchConfigs.clear()},t.updateStats=function(e,t){var n=this.stats.get(e);n||(n=this.createEmptyStats(e),this.stats.set(e,n)),n.triggerCount++,n.totalExecutionTime+=t,n.averageExecutionTime=n.totalExecutionTime/n.triggerCount,n.lastTriggerTime=Date.now(),n.listenerCount=this.getListenerCount(e)},t.createEmptyStats=function(e){return{eventType:e,listenerCount:0,triggerCount:0,totalExecutionTime:0,averageExecutionTime:0,lastTriggerTime:0}},e}();oe._logger=k("EventSystem"),e.ECSEventType=void 0,(te=e.ECSEventType||(e.ECSEventType={})).ENTITY_CREATED="entity:created",te.ENTITY_DESTROYED="entity:destroyed",te.ENTITY_ENABLED="entity:enabled",te.ENTITY_DISABLED="entity:disabled",te.ENTITY_TAG_ADDED="entity:tag:added",te.ENTITY_TAG_REMOVED="entity:tag:removed",te.ENTITY_NAME_CHANGED="entity:name:changed",te.COMPONENT_ADDED="component:added",te.COMPONENT_REMOVED="component:removed",te.COMPONENT_MODIFIED="component:modified",te.COMPONENT_ENABLED="component:enabled",te.COMPONENT_DISABLED="component:disabled",te.SYSTEM_ADDED="system:added",te.SYSTEM_REMOVED="system:removed",te.SYSTEM_ENABLED="system:enabled",te.SYSTEM_DISABLED="system:disabled",te.SYSTEM_PROCESSING_START="system:processing:start",te.SYSTEM_PROCESSING_END="system:processing:end",te.SYSTEM_ERROR="system:error",te.SCENE_CREATED="scene:created",te.SCENE_DESTROYED="scene:destroyed",te.SCENE_ACTIVATED="scene:activated",te.SCENE_DEACTIVATED="scene:deactivated",te.SCENE_PAUSED="scene:paused",te.SCENE_RESUMED="scene:resumed",te.QUERY_EXECUTED="query:executed",te.QUERY_CACHE_HIT="query:cache:hit",te.QUERY_CACHE_MISS="query:cache:miss",te.QUERY_OPTIMIZED="query:optimized",te.PERFORMANCE_WARNING="performance:warning",te.PERFORMANCE_CRITICAL="performance:critical",te.MEMORY_USAGE_HIGH="memory:usage:high",te.FRAME_RATE_DROP="frame:rate:drop",te.INDEX_CREATED="index:created",te.INDEX_UPDATED="index:updated",te.INDEX_OPTIMIZED="index:optimized",te.ARCHETYPE_CREATED="archetype:created",te.ARCHETYPE_ENTITY_ADDED="archetype:entity:added",te.ARCHETYPE_ENTITY_REMOVED="archetype:entity:removed",te.DIRTY_MARK_ADDED="dirty:mark:added",te.DIRTY_BATCH_PROCESSED="dirty:batch:processed",te.ERROR_OCCURRED="error:occurred",te.WARNING_ISSUED="warning:issued",te.FRAMEWORK_INITIALIZED="framework:initialized",te.FRAMEWORK_SHUTDOWN="framework:shutdown",te.DEBUG_INFO="debug:info",te.DEBUG_STATS_UPDATED="debug:stats:updated",e.EventPriority=void 0,(ne=e.EventPriority||(e.EventPriority={}))[ne.LOWEST=0]="LOWEST",ne[ne.LOW=25]="LOW",ne[ne.NORMAL=50]="NORMAL",ne[ne.HIGH=75]="HIGH",ne[ne.HIGHEST=100]="HIGHEST",ne[ne.CRITICAL=200]="CRITICAL";var se={ENTITY:{CREATED:e.ECSEventType.ENTITY_CREATED,DESTROYED:e.ECSEventType.ENTITY_DESTROYED,ENABLED:e.ECSEventType.ENTITY_ENABLED,DISABLED:e.ECSEventType.ENTITY_DISABLED,TAG_ADDED:e.ECSEventType.ENTITY_TAG_ADDED,TAG_REMOVED:e.ECSEventType.ENTITY_TAG_REMOVED,NAME_CHANGED:e.ECSEventType.ENTITY_NAME_CHANGED},COMPONENT:{ADDED:e.ECSEventType.COMPONENT_ADDED,REMOVED:e.ECSEventType.COMPONENT_REMOVED,MODIFIED:e.ECSEventType.COMPONENT_MODIFIED,ENABLED:e.ECSEventType.COMPONENT_ENABLED,DISABLED:e.ECSEventType.COMPONENT_DISABLED},SYSTEM:{ADDED:e.ECSEventType.SYSTEM_ADDED,REMOVED:e.ECSEventType.SYSTEM_REMOVED,ENABLED:e.ECSEventType.SYSTEM_ENABLED,DISABLED:e.ECSEventType.SYSTEM_DISABLED,PROCESSING_START:e.ECSEventType.SYSTEM_PROCESSING_START,PROCESSING_END:e.ECSEventType.SYSTEM_PROCESSING_END,ERROR:e.ECSEventType.SYSTEM_ERROR},PERFORMANCE:{WARNING:e.ECSEventType.PERFORMANCE_WARNING,CRITICAL:e.ECSEventType.PERFORMANCE_CRITICAL,MEMORY_HIGH:e.ECSEventType.MEMORY_USAGE_HIGH,FRAME_DROP:e.ECSEventType.FRAME_RATE_DROP}},ae=function(){function e(){}return e.isValid=function(e){return this.validTypes.has(e)},e.getAllValidTypes=function(){return Array.from(this.validTypes)},e.addCustomType=function(e){this.validTypes.add(e)},e.removeCustomType=function(e){this.validTypes.delete(e)},e}();ae.validTypes=new Set([].concat(Object.values(e.ECSEventType),Object.values(se.ENTITY),Object.values(se.COMPONENT),Object.values(se.SYSTEM),Object.values(se.PERFORMANCE)));var ce=function(){function t(e){void 0===e&&(e=!1),this.eventIdCounter=0,this.isDebugMode=!1,this.eventSystem=new oe,this.isDebugMode=e}var n=t.prototype;return n.emit=function(e,n,i){void 0===i&&(i=!1),this.validateEventType(e);var r=i?this.enhanceEventData(e,n):n;this.isDebugMode&&t._logger.info("发射事件: "+e,r),this.eventSystem.emitSync(e,r)},n.emitAsync=function(){var e=i(d().m((function e(n,i,r){var o;return d().w((function(e){for(;;)switch(e.n){case 0:return void 0===r&&(r=!1),this.validateEventType(n),o=r?this.enhanceEventData(n,i):i,this.isDebugMode&&t._logger.info("发射异步事件: "+n,o),e.n=1,this.eventSystem.emit(n,o);case 1:return e.a(2)}}),e,this)})));return function(t,n,i){return e.apply(this,arguments)}}(),n.on=function(n,i,r){void 0===r&&(r={}),this.validateEventType(n);var o={once:r.once||!1,priority:r.priority||e.EventPriority.NORMAL,async:r.async||!1,context:r.context};return this.isDebugMode&&t._logger.info("添加监听器: "+n,o),this.eventSystem.on(n,i,o)},n.once=function(e,t,n){return void 0===n&&(n={}),this.on(e,t,c({},n,{once:!0}))},n.onAsync=function(e,t,n){return void 0===n&&(n={}),this.on(e,t,c({},n,{async:!0}))},n.off=function(e,n){return this.isDebugMode&&t._logger.info("移除监听器: "+n+" 事件: "+e),this.eventSystem.off(e,n)},n.offAll=function(e){this.isDebugMode&&t._logger.info("移除所有监听器: "+e),this.eventSystem.offAll(e)},n.hasListeners=function(e){return this.eventSystem.hasListeners(e)},n.getStats=function(e){var t=this,n=this.eventSystem.getStats(e);if(n instanceof Map){var i=new Map;return n.forEach((function(e,n){i.set(n,t.convertEventStats(e))})),i}return this.convertEventStats(n)},n.clear=function(){this.isDebugMode&&t._logger.info("清空所有监听器"),this.eventSystem.clear()},n.setEnabled=function(e){this.eventSystem.setEnabled(e)},n.setDebugMode=function(e){this.isDebugMode=e},n.setMaxListeners=function(e){this.eventSystem.setMaxListeners(e)},n.getListenerCount=function(e){return this.eventSystem.getListenerCount(e)},n.setBatchConfig=function(e,t,n){this.eventSystem.setBatchConfig(e,{batchSize:t,delay:n,enabled:!0})},n.flushBatch=function(e){this.eventSystem.flushBatch(e)},n.resetStats=function(e){this.eventSystem.resetStats(e)},n.emitEntityCreated=function(t){this.emit(e.ECSEventType.ENTITY_CREATED,t)},n.emitEntityDestroyed=function(t){this.emit(e.ECSEventType.ENTITY_DESTROYED,t)},n.emitComponentAdded=function(t){this.emit(e.ECSEventType.COMPONENT_ADDED,t)},n.emitComponentRemoved=function(t){this.emit(e.ECSEventType.COMPONENT_REMOVED,t)},n.emitSystemAdded=function(t){this.emit(e.ECSEventType.SYSTEM_ADDED,t)},n.emitSystemRemoved=function(t){this.emit(e.ECSEventType.SYSTEM_REMOVED,t)},n.emitSceneChanged=function(t){this.emit(e.ECSEventType.SCENE_ACTIVATED,t)},n.emitPerformanceWarning=function(t){this.emit(e.ECSEventType.PERFORMANCE_WARNING,t)},n.onEntityCreated=function(t,n){return this.on(e.ECSEventType.ENTITY_CREATED,t,n)},n.onComponentAdded=function(t,n){return this.on(e.ECSEventType.COMPONENT_ADDED,t,n)},n.onSystemError=function(t,n){return this.on(e.ECSEventType.SYSTEM_ERROR,t,n)},n.onPerformanceWarning=function(t,n){return this.on(e.ECSEventType.PERFORMANCE_WARNING,t,n)},n.validateEventType=function(e){this.isDebugMode&&(ae.isValid(e)||(t._logger.warn("未知事件类型: "+e),ae.addCustomType(e)))},n.enhanceEventData=function(e,t){if(null==t)return{timestamp:Date.now(),eventId:e+"_"+ ++this.eventIdCounter,source:"EventBus"};var n=t;return n.timestamp||(n.timestamp=Date.now()),n.eventId||(n.eventId=e+"_"+ ++this.eventIdCounter),n.source||(n.source="EventBus"),n},n.convertEventStats=function(e){return{eventType:e.eventType,listenerCount:e.listenerCount,triggerCount:e.triggerCount,totalExecutionTime:e.totalExecutionTime,averageExecutionTime:e.averageExecutionTime,lastTriggerTime:e.lastTriggerTime}},t}();ce._logger=k("EventBus");var ue=function(){function e(){}return e.getInstance=function(e){return void 0===e&&(e=!1),this.instance||(this.instance=new ce(e)),this.instance},e.reset=function(e){return void 0===e&&(e=!1),this.instance&&this.instance.clear(),this.instance=new ce(e),this.instance},e}();var he=function(){function e(e){var t=this;this.name="",this._didSceneBegin=!1,this.entities=new G(this),this.entityProcessors=new Y,this.identifierPool=new Q,this.componentStorageManager=new q,this.querySystem=new ie,this.eventSystem=new oe,null!=e&&e.name&&(this.name=e.name),void 0!==(null==e?void 0:e.enableEntityDirectUpdate)&&this.entities.setEnableEntityDirectUpdate(e.enableEntityDirectUpdate),U.eventBus||(U.eventBus=new ce(!1)),U.eventBus&&U.eventBus.onComponentAdded((function(e){t.eventSystem.emitSync("component:added",e)}))}var t=e.prototype;return t.initialize=function(){},t.onStart=function(){},t.unload=function(){},t.begin=function(){null!=this.entityProcessors&&this.entityProcessors.begin(),this._didSceneBegin=!0,this.onStart()},t.end=function(){this._didSceneBegin=!1,this.entities.removeAllEntities(),this.querySystem.setEntities([]),this.componentStorageManager.clear(),this.entityProcessors&&this.entityProcessors.end(),this.unload()},t.update=function(){this.entities.updateLists(),null!=this.entityProcessors&&this.entityProcessors.update(),this.entities.update(),null!=this.entityProcessors&&this.entityProcessors.lateUpdate()},t.createEntity=function(e){var t=new U(e,this.identifierPool.checkOut());return this.eventSystem.emitSync("entity:created",{entityName:e,entity:t,scene:this}),this.addEntity(t)},t.clearSystemEntityCaches=function(){for(var e,t=a(this.entityProcessors.processors);!(e=t()).done;){e.value.clearEntityCache()}},t.addEntity=function(e,t){return void 0===t&&(t=!1),this.entities.add(e),e.scene=this,this.querySystem.addEntity(e,t),t||this.clearSystemEntityCaches(),this.eventSystem.emitSync("entity:added",{entity:e,scene:this}),e},t.createEntities=function(e,t){void 0===t&&(t="Entity");for(var n=[],i=0;i1?t-1:0),i=1;i1?t-1:0),i=1;i0?t.entities[0]:null},t.findByName=function(e){return this.scene.findEntity(e)},t.findByTag=function(e){return this.scene.findEntitiesByTag(e)},t.emit=function(e,t){this.eventSystem.emitSync(e,t)},t.emitAsync=function(){var e=i(d().m((function e(t,n){return d().w((function(e){for(;;)switch(e.n){case 0:return e.n=1,this.eventSystem.emit(t,n);case 1:return e.a(2)}}),e,this)})));return function(t,n){return e.apply(this,arguments)}}(),t.on=function(e,t){return this.eventSystem.on(e,t)},t.once=function(e,t){return this.eventSystem.once(e,t)},t.off=function(e,t){this.eventSystem.off(e,t)},t.batch=function(e){return new fe(e)},t.getStats=function(){return{entityCount:this.scene.entities.count,systemCount:this.scene.systems.length,componentStats:this.scene.componentStorageManager.getAllStats(),queryStats:this.querySystem.getStats(),eventStats:this.eventSystem.getStats()}},e}();function me(e,t,n){return new pe(e,t,n)}var ye=k("World"),ve=function(){function e(e){void 0===e&&(e={}),this._scenes=new Map,this._activeScenes=new Set,this._globalSystems=[],this._isActive=!1,this._config=c({name:"World",debug:!1,maxScenes:10,autoCleanup:!0},e),this.name=this._config.name,this._createdAt=Date.now(),ye.info("创建World: "+this.name)}var t=e.prototype;return t.createScene=function(e,t){if(this._scenes.has(e))throw new Error("Scene ID '"+e+"' 已存在于World '"+this.name+"' 中");if(this._scenes.size>=this._config.maxScenes)throw new Error("World '"+this.name+"' 已达到最大Scene数量限制: "+this._config.maxScenes);var n=t||new he;return"id"in n&&(n.id=e),"name"in n&&!n.name&&(n.name=e),this._scenes.set(e,n),n.initialize(),ye.info("在World '"+this.name+"' 中创建Scene: "+e),n},t.removeScene=function(e){var t=this._scenes.get(e);return!!t&&(this._activeScenes.has(e)&&this.setSceneActive(e,!1),t.end(),this._scenes.delete(e),ye.info("从World '"+this.name+"' 中移除Scene: "+e),!0)},t.getScene=function(e){return this._scenes.get(e)||null},t.getSceneIds=function(){return Array.from(this._scenes.keys())},t.getAllScenes=function(){return Array.from(this._scenes.values())},t.setSceneActive=function(e,t){var n=this._scenes.get(e);n?t?(this._activeScenes.add(e),n.begin&&n.begin(),ye.debug("在World '"+this.name+"' 中激活Scene: "+e)):(this._activeScenes.delete(e),ye.debug("在World '"+this.name+"' 中停用Scene: "+e)):ye.warn("Scene '"+e+"' 不存在于World '"+this.name+"' 中")},t.isSceneActive=function(e){return this._activeScenes.has(e)},t.getActiveSceneCount=function(){return this._activeScenes.size},t.addGlobalSystem=function(e){return this._globalSystems.includes(e)||(this._globalSystems.push(e),e.initialize&&e.initialize(),ye.debug("在World '"+this.name+"' 中添加全局System: "+e.name)),e},t.removeGlobalSystem=function(e){var t=this._globalSystems.indexOf(e);return-1!==t&&(this._globalSystems.splice(t,1),e.reset&&e.reset(),ye.debug("从World '"+this.name+"' 中移除全局System: "+e.name),!0)},t.getGlobalSystem=function(e){for(var t,n=a(this._globalSystems);!(t=n()).done;){var i=t.value;if(i instanceof e)return i}return null},t.start=function(){if(!this._isActive){this._isActive=!0;for(var e,t=a(this._globalSystems);!(e=t()).done;){var n=e.value;n.initialize&&n.initialize()}ye.info("启动World: "+this.name)}},t.stop=function(){if(this._isActive){for(var e,t=a(this._activeScenes);!(e=t()).done;){var n=e.value;this.setSceneActive(n,!1)}for(var i,r=a(this._globalSystems);!(i=r()).done;){var o=i.value;o.reset&&o.reset()}this._isActive=!1,ye.info("停止World: "+this.name)}},t.updateGlobalSystems=function(){if(this._isActive)for(var e,t=a(this._globalSystems);!(e=t()).done;){var n=e.value;n.update&&n.update()}},t.updateScenes=function(){if(this._isActive){for(var e,t=a(this._activeScenes);!(e=t()).done;){var n=e.value,i=this._scenes.get(n);i&&i.update&&i.update()}this._config.autoCleanup&&this.shouldAutoCleanup()&&this.cleanup()}},t.destroy=function(){ye.info("销毁World: "+this.name),this.stop();for(var e=0,t=Array.from(this._scenes.keys());e3e5)return!0}return!1},t.cleanup=function(){for(var e=Array.from(this._scenes.keys()),t=Date.now(),n=0,i=e;n3e5&&(this.removeScene(r),ye.debug("自动清理空Scene: "+r+" from World "+this.name))}},s(e,[{key:"isActive",get:function(){return this._isActive}},{key:"sceneCount",get:function(){return this._scenes.size}},{key:"createdAt",get:function(){return this._createdAt}}])}(),ge=k("WorldManager"),_e=function(){function e(e){void 0===e&&(e={}),this._worlds=new Map,this._activeWorlds=new Set,this._cleanupTimer=null,this._isRunning=!1,this._config=c({maxWorlds:50,autoCleanup:!0,cleanupInterval:3e4,debug:!1},e),ge.info("WorldManager已初始化",{maxWorlds:this._config.maxWorlds,autoCleanup:this._config.autoCleanup,cleanupInterval:this._config.cleanupInterval}),this.startCleanupTimer()}e.getInstance=function(t){return this._instance||(this._instance=new e(t)),this._instance},e.reset=function(){this._instance&&(this._instance.destroy(),this._instance=null)};var t=e.prototype;return t.createWorld=function(e,t){if(!e||"string"!=typeof e||""===e.trim())throw new Error("World ID不能为空");if(this._worlds.has(e))throw new Error("World ID '"+e+"' 已存在");if(this._worlds.size>=this._config.maxWorlds)throw new Error("已达到最大World数量限制: "+this._config.maxWorlds);var n=c({name:e,debug:this._config.debug},t),i=new ve(n);return this._worlds.set(e,i),ge.info("创建World: "+e,{config:n}),i},t.removeWorld=function(e){var t=this._worlds.get(e);return!!t&&(this._activeWorlds.has(e)&&this.setWorldActive(e,!1),t.destroy(),this._worlds.delete(e),ge.info("移除World: "+e),!0)},t.getWorld=function(e){return this._worlds.get(e)||null},t.getWorldIds=function(){return Array.from(this._worlds.keys())},t.getAllWorlds=function(){return Array.from(this._worlds.values())},t.setWorldActive=function(e,t){var n=this._worlds.get(e);n?t?(this._activeWorlds.add(e),n.start(),ge.debug("激活World: "+e)):(this._activeWorlds.delete(e),n.stop(),ge.debug("停用World: "+e)):ge.warn("World '"+e+"' 不存在")},t.isWorldActive=function(e){return this._activeWorlds.has(e)},t.getActiveWorlds=function(){for(var e,t=[],n=a(this._activeWorlds);!(e=n()).done;){var i=e.value,r=this._worlds.get(i);r&&t.push(r)}return t},t.startAll=function(){this._isRunning=!0;for(var e,t=a(this._worlds.keys());!(e=t()).done;){var n=e.value;this.setWorldActive(n,!0)}ge.info("启动所有World")},t.stopAll=function(){this._isRunning=!1;for(var e,t=a(this._activeWorlds);!(e=t()).done;){var n=e.value;this.setWorldActive(n,!1)}ge.info("停止所有World")},t.findWorlds=function(e){for(var t,n=[],i=a(this._worlds.values());!(t=i()).done;){var r=t.value;e(r)&&n.push(r)}return n},t.findWorldByName=function(e){for(var t,n=a(this._worlds.values());!(t=n()).done;){var i=t.value;if(i.name===e)return i}return null},t.getStats=function(){for(var e,t={totalWorlds:this._worlds.size,activeWorlds:this._activeWorlds.size,totalScenes:0,totalEntities:0,totalSystems:0,memoryUsage:0,isRunning:this._isRunning,config:c({},this._config),worlds:[]},n=a(this._worlds);!(e=n()).done;){var i=e.value,r=i[0],o=i[1],s=o.getStats();t.totalScenes+=s.totalSystems,t.totalEntities+=s.totalEntities,t.totalSystems+=s.totalSystems,t.worlds.push(c({id:r,name:o.name,isActive:this._activeWorlds.has(r),sceneCount:o.sceneCount},s))}return t},t.getDetailedStatus=function(){var e=this;return c({},this.getStats(),{worlds:Array.from(this._worlds.entries()).map((function(t){var n=t[0],i=t[1];return{id:n,isActive:e._activeWorlds.has(n),status:i.getStatus()}}))})},t.cleanup=function(){for(var e,t=[],n=a(this._worlds);!(e=n()).done;){var i=e.value,r=i[0],o=i[1];this.shouldCleanupWorld(o)&&t.push(r)}for(var s=0,c=t;s0&&ge.debug("清理了 "+t.length+" 个World"),t.length},t.destroy=function(){ge.info("正在销毁WorldManager..."),this.stopCleanupTimer(),this.stopAll();for(var e=0,t=Array.from(this._worlds.keys());e0})))&&Date.now()-e.createdAt>6e5)},s(e,[{key:"worldCount",get:function(){return this._worlds.size}},{key:"activeWorldCount",get:function(){return this._activeWorlds.size}},{key:"isRunning",get:function(){return this._isRunning}},{key:"config",get:function(){return c({},this._config)}}])}();_e._instance=null;var Se=function(){function e(e){if(e&&"object"==typeof e)this._value=w.clone(e);else if("number"==typeof e)this._value=w.fromNumber(e);else if("string"==typeof e){var t=parseInt(e,10);this._value=w.fromNumber(t)}else this._value=w.clone(w.ZERO)}var t=e.prototype;return t.set=function(e){if(e<0)throw new Error("Bit index cannot be negative");if(e>=64)throw new Error("Bit index exceeds 64-bit limit. ECS framework supports max 64 component types.");w.setBit(this._value,e)},t.clear=function(e){if(e<0)throw new Error("Bit index cannot be negative");e>=64||w.clearBit(this._value,e)},t.get=function(e){if(e<0||e>=64)return!1;var t=w.create(e);return w.hasAny(this._value,t)},t.containsAll=function(e){return w.hasAll(this._value,e._value)},t.intersects=function(e){return w.hasAny(this._value,e._value)},t.excludes=function(e){return w.hasNone(this._value,e._value)},t.clearAll=function(){w.clear(this._value)},t.isEmpty=function(){return w.isZero(this._value)},t.cardinality=function(){return w.popCount(this._value)},t.and=function(t){var n=new e;return w.copy(this._value,n._value),w.andInPlace(n._value,t._value),n},t.or=function(t){var n=new e;return w.copy(this._value,n._value),w.orInPlace(n._value,t._value),n},t.xor=function(t){var n=new e;return w.copy(this._value,n._value),w.xorInPlace(n._value,t._value),n},t.not=function(t){void 0===t&&(t=64),t>64&&(t=64);var n=new e;if(w.copy(this._value,n._value),t<=32){var i=(1<64&&(e=64);for(var t="",n=e-1;n>=0;n--)t+=this.get(n)?"1":"0",n%8==0&&n>0&&(t+=" ");return t},t.toHexString=function(){return w.toString(this._value,16)},e.fromBinaryString=function(t){var n,i=t.replace(/\s/g,"");if(i.length<=32){n={lo:parseInt(i,2)>>>0,hi:0}}else{var r=i.substring(i.length-32),o=i.substring(0,i.length-32);n={lo:parseInt(r,2)>>>0,hi:parseInt(o,2)>>>0}}return new e(n)},e.fromHexString=function(t){var n,i=t.replace(/^0x/i,"");if(i.length<=8){n={lo:parseInt(i,16)>>>0,hi:0}}else{var r=i.substring(i.length-8),o=i.substring(0,i.length-8);n={lo:parseInt(r,16)>>>0,hi:parseInt(o,16)>>>0}}return new e(n)},t.equals=function(e){return w.equals(this._value,e._value)},t.getHighestBitIndex=function(){if(w.isZero(this._value))return-1;if(0!==this._value.hi)for(var e=31;e>=0;e--)if(this._value.hi&1<=0;t--)if(this._value.lo&1<0?i.sort().join(", "):"无组件",o=t.get(r);o?o.count++:t.set(r,{count:1,componentTypes:i})})),Array.from(t.entries()).map((function(e){return{signature:e[0],count:e[1].count,memory:0}})).sort((function(e,t){return t.count-e.count})).slice(0,20)},t.getTopEntitiesByComponentsFast=function(e){return e&&e.entities?e.entities.map((function(e){var t;return{id:e.id.toString(),name:e.name||"Entity_"+e.id,componentCount:(null===(t=e.components)||void 0===t?void 0:t.length)||0,memory:0}})).sort((function(e,t){return t.componentCount-e.componentCount})).slice(0,10):[]},t.collectArchetypeDataWithMemory=function(e){var t;if(e&&e.archetypeSystem&&"function"==typeof e.archetypeSystem.getAllArchetypes)return this.extractArchetypeStatisticsWithMemory(e.archetypeSystem);var n={entities:(null===(t=e.entities)||void 0===t?void 0:t.buffer)||[]};return{distribution:this.getArchetypeDistributionWithMemory(n),topEntities:this.getTopEntitiesByComponentsWithMemory(n)}},t.extractArchetypeStatistics=function(e){var t=e.getAllArchetypes(),n=[],i=[];return t.forEach((function(e){var t,r,o=(null===(t=e.componentTypes)||void 0===t?void 0:t.map((function(e){return e.name})).join(","))||"Unknown",s=(null===(r=e.entities)||void 0===r?void 0:r.length)||0;n.push({signature:o,count:s,memory:0}),e.entities&&e.entities.slice(0,5).forEach((function(e){var t;i.push({id:e.id.toString(),name:e.name||"Entity_"+e.id,componentCount:(null===(t=e.components)||void 0===t?void 0:t.length)||0,memory:0})}))})),n.sort((function(e,t){return t.count-e.count})),i.sort((function(e,t){return t.componentCount-e.componentCount})),{distribution:n,topEntities:i}},t.extractArchetypeStatisticsWithMemory=function(e){var t=this,n=e.getAllArchetypes(),i=[],r=[];return n.forEach((function(e){var n,o,s=(null===(n=e.componentTypes)||void 0===n?void 0:n.map((function(e){return e.name})).join(","))||"Unknown",a=(null===(o=e.entities)||void 0===o?void 0:o.length)||0,c=0;if(e.entities&&e.entities.length>0){for(var u=Math.min(5,e.entities.length),h=0,l=0;l0?r.sort().join(", "):"无组件",s=n.get(o),a=t.estimateEntityMemoryUsage(e);(isNaN(a)||a<0)&&(a=0),s?(s.count++,s.memory+=a):n.set(o,{count:1,memory:a,componentTypes:r})})),Array.from(n.entries()).map((function(e){var t=e[0],n=e[1];return{signature:t,count:n.count,memory:isNaN(n.memory)?0:n.memory}})).sort((function(e,t){return t.count-e.count}))},t.getTopEntitiesByComponents=function(e){return e&&e.entities?e.entities.map((function(e){var t;return{id:e.id.toString(),name:e.name||"Entity_"+e.id,componentCount:(null===(t=e.components)||void 0===t?void 0:t.length)||0,memory:0}})).sort((function(e,t){return t.componentCount-e.componentCount})):[]},t.getTopEntitiesByComponentsWithMemory=function(e){var t=this;return e&&e.entities?e.entities.map((function(e){var n;return{id:e.id.toString(),name:e.name||"Entity_"+e.id,componentCount:(null===(n=e.components)||void 0===n?void 0:n.length)||0,memory:t.estimateEntityMemoryUsage(e)}})).sort((function(e,t){return t.componentCount-e.componentCount})):[]},t.getEmptyEntityDebugData=function(){return{totalEntities:0,activeEntities:0,pendingAdd:0,pendingRemove:0,entitiesPerArchetype:[],topEntitiesByComponents:[],entityHierarchy:[],entityDetailsMap:{}}},t.calculateFallbackEntityStats=function(e){var t=e.buffer||[],n=t.filter((function(e){return e.enabled&&!e._isDestroyed}));return{totalEntities:t.length,activeEntities:n.length,pendingAdd:0,pendingRemove:0,averageComponentsPerEntity:n.length>0?t.reduce((function(e,t){var n;return e+((null===(n=t.components)||void 0===n?void 0:n.length)||0)}),0)/n.length:0}},t.estimateEntityMemoryUsage=function(e){var t=this;try{var n=0,i=this.calculateObjectSize(e,["components","children","parent"]);return!isNaN(i)&&i>0&&(n+=i),e.components&&Array.isArray(e.components)&&e.components.forEach((function(e){var i=t.calculateObjectSize(e,["entity"]);!isNaN(i)&&i>0&&(n+=i)})),isNaN(n)||n<0?0:n}catch(e){return 0}},t.calculateObjectSize=function(e,t){if(void 0===t&&(t=[]),!e||"object"!=typeof e)return 0;var n=new WeakSet,i=function(e,r){if(void 0===r&&(r=0),!e||"object"!=typeof e||r>=2)return 0;if(n.has(e))return 0;n.add(e);var o=32;try{for(var s=Object.keys(e),a=Math.min(s.length,20),c=0;ct.name?1:e.id-t.id})),n},t.buildEntityHierarchyNode=function(e){var t,n=this,i={id:e.id,name:e.name||"Entity_"+e.id,active:!1!==e.active,enabled:!1!==e.enabled,activeInHierarchy:!1!==e.activeInHierarchy,componentCount:e.components.length,componentTypes:e.components.map((function(e){return B(e)})),parentId:(null===(t=e.parent)||void 0===t?void 0:t.id)||null,children:[],depth:e.getDepth?e.getDepth():0,tag:e.tag||0,updateOrder:e.updateOrder||0};(e.children&&e.children.length>0&&(i.children=e.children.map((function(e){return n.buildEntityHierarchyNode(e)}))),"function"==typeof e.getDebugInfo)&&(i=c({},i,e.getDebugInfo()));return e.components&&e.components.length>0&&(i.componentDetails=this.extractComponentDetails(e.components)),i},t.buildEntityDetailsMap=function(e,t){var n=this;if(null==e||!e.buffer)return{};for(var i={},r=e.buffer,o=0;o=o.components.length)return{};var s=o.components[t],a={};return Object.keys(s).forEach((function(e){if(!e.startsWith("_")&&"entity"!==e){var t=s[e];null!=t&&(a[e]=i.formatPropertyValue(t))}})),a}catch(e){return{_error:"属性提取失败"}}},t.formatPropertyValue=function(e,t){return void 0===t&&(t=0),null==e?e:"object"!=typeof e?"string"==typeof e&&e.length>200?"[长字符串: "+e.length+"字符] "+e.substring(0,100)+"...":e:0===t?this.formatObjectFirstLevel(e):this.createLazyLoadPlaceholder(e)},t.formatObjectFirstLevel=function(e){var t=this;try{if(Array.isArray(e)){if(0===e.length)return[];if(e.length>10){var n=e.slice(0,3).map((function(e){return t.formatPropertyValue(e,1)}));return{_isLazyArray:!0,_arrayLength:e.length,_sample:n,_summary:"数组["+e.length+"个元素]"}}return e.map((function(e){return t.formatPropertyValue(e,1)}))}var i=Object.keys(e);if(0===i.length)return{};for(var r={},o=0,s=0,a=i;s=15){r._hasMoreProperties=!0,r._totalProperties=i.length,r._hiddenCount=i.length-o;break}if(!c.startsWith("_")&&!c.startsWith("$")&&"function"!=typeof e[c])try{var u=e[c];null!=u&&(r[c]=this.formatPropertyValue(u,1),o++)}catch(e){r[c]="[访问失败: "+(e instanceof Error?e.message:String(e))+"]",o++}}return r}catch(e){return"[对象解析失败: "+(e instanceof Error?e.message:String(e))+"]"}},t.createLazyLoadPlaceholder=function(e){try{var t,n=(null===(t=e.constructor)||void 0===t?void 0:t.name)||"Object";return{_isLazyObject:!0,_typeName:n,_summary:this.getObjectSummary(e,n),_objectId:this.generateObjectId(e)}}catch(e){return{_isLazyObject:!0,_typeName:"Unknown",_summary:"无法分析的对象: "+(e instanceof Error?e.message:String(e)),_objectId:Math.random().toString(36).substr(2,9)}}},t.getObjectSummary=function(e,t){try{if((t.toLowerCase().includes("vec")||t.toLowerCase().includes("vector"))&&void 0!==e.x&&void 0!==e.y){var n=void 0!==e.z?e.z:"";return t+"("+e.x+", "+e.y+(n?", "+n:"")+")"}if(t.toLowerCase().includes("color")&&void 0!==e.r&&void 0!==e.g&&void 0!==e.b){var i=void 0!==e.a?e.a:1;return t+"("+e.r+", "+e.g+", "+e.b+", "+i+")"}if(t.toLowerCase().includes("node"))return t+": "+(e.name||e._name||"未命名");if(t.toLowerCase().includes("component")){var r,o,s=(null===(r=e.node)||void 0===r?void 0:r.name)||(null===(o=e.node)||void 0===o?void 0:o._name)||"";return t+(s?" on "+s:"")}var a=Object.keys(e);return 0===a.length?t+" (空对象)":t+" ("+a.length+"个属性)"}catch(e){return t+" (无法分析)"}},t.generateObjectId=function(e){try{return void 0!==e.id?"obj_"+e.id:void 0!==e._id?"obj_"+e._id:void 0!==e.uuid?"obj_"+e.uuid:void 0!==e._uuid?"obj_"+e._uuid:"obj_"+Math.random().toString(36).substr(2,9)}catch(e){return"obj_"+Math.random().toString(36).substr(2,9)}},t.expandLazyObject=function(e,t,n,i){try{if(!i)return null;var r=i.entities;if(null==r||!r.buffer)return null;var o=r.buffer.find((function(t){return t.id===e}));if(!o)return null;if(t>=o.components.length)return null;var s=o.components[t],a=this.getObjectByPath(s,n);return a?this.formatObjectFirstLevel(a):null}catch(e){return{error:"展开失败: "+(e instanceof Error?e.message:String(e))}}},t.getObjectByPath=function(e,t){if(!t)return e;for(var n,i=e,r=a(t.split("."));!(n=r()).done;){var o=n.value;if(null==i)return null;if(o.includes("[")&&o.includes("]")){var s=o.substring(0,o.indexOf("[")),c=parseInt(o.substring(o.indexOf("[")+1,o.indexOf("]")));if(s&&(i=i[s]),!(Array.isArray(i)&&c>=0&&c0?Math.round(1/t):0,r=this.getECSPerformanceData(e),o=r.totalExecutionTime,s=n>0?o/n*100:0,a=0;performance.memory&&(a=performance.memory.usedJSHeapSize/1024/1024),this.frameTimeHistory.push(o),this.frameTimeHistory.length>this.maxHistoryLength&&this.frameTimeHistory.shift();var c=this.frameTimeHistory.filter((function(e){return e>=0}));return{frameTime:o,engineFrameTime:n,ecsPercentage:s,memoryUsage:a,fps:i,averageFrameTime:c.length>0?c.reduce((function(e,t){return e+t}),0)/c.length:o,minFrameTime:c.length>0?Math.min.apply(Math,c):o,maxFrameTime:c.length>0?Math.max.apply(Math,c):o,frameTimeHistory:[].concat(this.frameTimeHistory),systemPerformance:this.getSystemPerformance(e),systemBreakdown:r.systemBreakdown,memoryDetails:this.getMemoryDetails()}},t.getECSPerformanceData=function(e){if(!e)return{totalExecutionTime:0,systemBreakdown:[]};if(!e.enabled){try{e.enabled=!0}catch(e){}return{totalExecutionTime:0,systemBreakdown:[]}}try{var t=0,n=[],i=e.getAllSystemStats();if(0===i.size)return{totalExecutionTime:0,systemBreakdown:[]};for(var r,o=a(i.entries());!(r=o()).done;){var s=r.value,c=s[0],u=s[1],h=u.recentTimes&&u.recentTimes.length>0?u.recentTimes[u.recentTimes.length-1]:u.averageTime||0;t+=h,n.push({systemName:c,executionTime:h,percentage:0})}return n.forEach((function(e){e.percentage=t>0?e.executionTime/t*100:0})),n.sort((function(e,t){return t.executionTime-e.executionTime})),{totalExecutionTime:t,systemBreakdown:n}}catch(e){return{totalExecutionTime:0,systemBreakdown:[]}}},t.getSystemPerformance=function(e){if(!e)return[];try{var t=e.getAllSystemStats(),n=e.getAllSystemData();return Array.from(t.entries()).map((function(e){var t=e[0],i=e[1],r=n.get(t);return{systemName:t,averageTime:i.averageTime||0,maxTime:i.maxTime||0,minTime:i.minTime===Number.MAX_VALUE?0:i.minTime||0,samples:i.executionCount||0,percentage:0,entityCount:(null==r?void 0:r.entityCount)||0,lastExecutionTime:(null==r?void 0:r.executionTime)||0}}))}catch(e){return[]}},t.getMemoryDetails=function(){var e={entities:0,components:0,systems:0,pooled:0,totalMemory:0,usedMemory:0,freeMemory:0,gcCollections:this.updateGCCount()};try{if(performance.memory){var t=performance.memory;if(e.totalMemory=t.jsHeapSizeLimit||536870912,e.usedMemory=t.usedJSHeapSize||0,e.freeMemory=e.totalMemory-e.usedMemory,this.lastMemoryCheck>0)this.lastMemoryCheck-e.usedMemory>1048576&&this.gcCollections++;this.lastMemoryCheck=e.usedMemory}else e.totalMemory=536870912,e.freeMemory=536870912}catch(e){return{totalMemory:0,usedMemory:0,freeMemory:0,entityMemory:0,componentMemory:0,systemMemory:0,pooledMemory:0,gcCollections:this.gcCollections}}return e},t.updateGCCount=function(){try{return"undefined"!=typeof PerformanceObserver||performance.measureUserAgentSpecificMemory,this.gcCollections}catch(e){return this.gcCollections}},e}(),Me=function(){function e(e,t,n){void 0===n&&(n=1e3),this.pool=[],this.createFn=e,this.resetFn=t,this.maxSize=n}var t=e.prototype;return t.acquire=function(){return this.pool.length>0?this.pool.pop():this.createFn()},t.release=function(e){this.pool.length0?u/c*100:0;t.set(r,{used:u,total:c,utilization:h})}return t},t.getComponentUtilization=function(e){var t=this.pools.get(e);if(!t)return 0;var n=t.getAvailableCount(),i=t.getMaxSize();return i>0?(i-n)/i*100:0},e}(),Ae=function(){function e(){}var t=e.prototype;return t.collectComponentData=function(e){var t=this;if(!e)return{componentTypes:0,componentInstances:0,componentStats:[]};var n=e.entities;if(null==n||!n.buffer)return{componentTypes:0,componentInstances:0,componentStats:[]};var i=new Map,r=0;n.buffer.forEach((function(e){e.components&&e.components.forEach((function(e){var t=B(e),n=i.get(t)||{count:0,entities:0};n.count++,r++,i.set(t,n)}))}));var o=new Map,s=new Map;try{for(var c,u=we.getInstance(),h=u.getPoolStats(),l=u.getPoolUtilization(),d=a(h.entries());!(c=d()).done;){var f=c.value,p=f[0],m=f[1];s.set(p,m.maxSize)}for(var y,v=a(l.entries());!(y=v()).done;){var g=y.value,_=g[0],S=g[1];o.set(_,S.utilization)}}catch(e){}return{componentTypes:i.size,componentInstances:r,componentStats:Array.from(i.entries()).map((function(i){var r=i[0],a=i[1],c=s.get(r)||0,u=o.get(r)||0,h=t.getEstimatedComponentSize(r,e);return{typeName:r,instanceCount:a.count,memoryPerInstance:h,totalMemory:a.count*h,poolSize:c,poolUtilization:u,averagePerEntity:a.count/n.buffer.length}}))}},t.getEstimatedComponentSize=function(t,n){if(e.componentSizeCache.has(t))return e.componentSizeCache.get(t);if(!n)return 64;var i=n.entities;if(null==i||!i.buffer)return 64;var r=64;try{for(var o,s=a(i.buffer);!(o=s()).done;){var c=o.value;if(c.components){var u=c.components.find((function(e){return B(e)===t}));if(u){r=this.calculateQuickObjectSize(u);break}}}}catch(e){r=64}return e.componentSizeCache.set(t,r),r},t.calculateQuickObjectSize=function(e){if(!e||"object"!=typeof e)return 8;var t=32,n=new WeakSet,i=function(e,t){if(void 0===t&&(t=0),!e||"object"!=typeof e||n.has(e)||t>3)return 0;n.add(e);var r=0;try{for(var o=Object.keys(e),s=0;s10)return 0;if(t.has(e))return 0;var i=0;switch(typeof e){case"boolean":i=4;break;case"number":default:i=8;break;case"string":i=24+Math.min(2*e.length,1e3);break;case"object":if(t.add(e),Array.isArray(e)){i=40+8*e.length;for(var r=Math.min(e.length,50),o=0;o=this.sendInterval&&(this.sendDebugData(),this.lastSendTime=t)}},t.onSceneChanged=function(){this.isRunning&&this.config.enabled&&this.sendDebugData()},t.handleMessage=function(e){try{switch(e.type){case"capture_memory_snapshot":this.handleMemorySnapshotRequest();break;case"config_update":e.config&&this.updateConfig(c({},this.config,e.config));break;case"expand_lazy_object":this.handleExpandLazyObjectRequest(e);break;case"get_component_properties":this.handleGetComponentPropertiesRequest(e);break;case"get_raw_entity_list":this.handleGetRawEntityListRequest(e);break;case"get_entity_details":this.handleGetEntityDetailsRequest(e);break;case"ping":this.webSocketManager.send({type:"pong",timestamp:Date.now()})}}catch(t){e.requestId&&this.webSocketManager.send({type:"error_response",requestId:e.requestId,error:t instanceof Error?t.message:String(t)})}},t.handleExpandLazyObjectRequest=function(e){try{var t=e.entityId,n=e.componentIndex,i=e.propertyPath,r=e.requestId;if(void 0===t||void 0===n||!i)return void this.webSocketManager.send({type:"expand_lazy_object_response",requestId:r,error:"缺少必要参数"});var o=this.entityCollector.expandLazyObject(t,n,i);this.webSocketManager.send({type:"expand_lazy_object_response",requestId:r,data:o})}catch(t){this.webSocketManager.send({type:"expand_lazy_object_response",requestId:e.requestId,error:t instanceof Error?t.message:String(t)})}},t.handleGetComponentPropertiesRequest=function(e){try{var t=e.entityId,n=e.componentIndex,i=e.requestId;if(void 0===t||void 0===n)return void this.webSocketManager.send({type:"get_component_properties_response",requestId:i,error:"缺少必要参数"});var r=this.entityCollector.getComponentProperties(t,n);this.webSocketManager.send({type:"get_component_properties_response",requestId:i,data:r})}catch(t){this.webSocketManager.send({type:"get_component_properties_response",requestId:e.requestId,error:t instanceof Error?t.message:String(t)})}},t.handleGetRawEntityListRequest=function(e){try{var t=e.requestId,n=this.entityCollector.getRawEntityList();this.webSocketManager.send({type:"get_raw_entity_list_response",requestId:t,data:n})}catch(t){this.webSocketManager.send({type:"get_raw_entity_list_response",requestId:e.requestId,error:t instanceof Error?t.message:String(t)})}},t.handleGetEntityDetailsRequest=function(e){try{var t=e.entityId,n=e.requestId;if(void 0===t)return void this.webSocketManager.send({type:"get_entity_details_response",requestId:n,error:"缺少实体ID参数"});var i=this.entityCollector.getEntityDetails(t);this.webSocketManager.send({type:"get_entity_details_response",requestId:n,data:i})}catch(t){this.webSocketManager.send({type:"get_entity_details_response",requestId:e.requestId,error:t instanceof Error?t.message:String(t)})}},t.handleMemorySnapshotRequest=function(){try{var e=this.captureMemorySnapshot();this.webSocketManager.send({type:"memory_snapshot_response",data:e})}catch(e){this.webSocketManager.send({type:"memory_snapshot_error",error:e instanceof Error?e.message:"内存快照捕获失败"})}},t.captureMemorySnapshot=function(){var e=Date.now(),t=this.collectBaseMemoryInfo(),n=this.sceneProvider(),i=this.entityCollector.collectEntityDataWithMemory(n),r=null!=n&&n.entities?this.collectComponentMemoryStats(n.entities):{totalMemory:0,componentTypes:0,totalInstances:0,breakdown:[]},o=this.collectSystemMemoryStats(),s=this.collectPoolMemoryStats(),a=this.collectPerformanceStats(),c=i.entitiesPerArchetype.reduce((function(e,t){return e+t.memory}),0);return{timestamp:e,version:"2.0",summary:{totalEntities:i.totalEntities,totalMemoryUsage:t.usedMemory,totalMemoryLimit:t.totalMemory,memoryUtilization:t.usedMemory/t.totalMemory*100,gcCollections:t.gcCollections,entityMemory:c,componentMemory:r.totalMemory,systemMemory:o.totalMemory,poolMemory:s.totalMemory},baseMemory:t,entities:{totalMemory:c,entityCount:i.totalEntities,archetypes:i.entitiesPerArchetype,largestEntities:i.topEntitiesByComponents},components:r,systems:o,pools:s,performance:a}},t.collectBaseMemoryInfo=function(){var e={totalMemory:0,usedMemory:0,freeMemory:0,gcCollections:0,heapInfo:null,detailedMemory:void 0};try{var t=performance;if(t.memory){var n=t.memory;e.totalMemory=n.jsHeapSizeLimit||536870912,e.usedMemory=n.usedJSHeapSize||0,e.freeMemory=e.totalMemory-e.usedMemory,e.heapInfo={totalJSHeapSize:n.totalJSHeapSize||0,usedJSHeapSize:n.usedJSHeapSize||0,jsHeapSizeLimit:n.jsHeapSizeLimit||0}}else e.totalMemory=536870912,e.freeMemory=536870912;t.measureUserAgentSpecificMemory&&t.measureUserAgentSpecificMemory().then((function(t){e.detailedMemory=t})).catch((function(){}))}catch(e){}return e},t.collectComponentMemoryStats=function(e){for(var t,n=new Map,i=0,r=new Map,o=a(e.buffer);!(t=o()).done;){var s=t.value;if(s&&!s.destroyed&&s.components)for(var c,u=a(s.components);!(c=u()).done;){var h=B(c.value);r.set(h,(r.get(h)||0)+1)}}for(var l,d=a(r.entries());!(l=d()).done;){var f=l.value,p=f[0],m=f[1],y=this.componentCollector.calculateDetailedComponentMemory(p),v=y*m;i+=v;for(var g,_=[],S=0,E=a(e.buffer);!(g=E()).done;){var C=g.value;if(C&&!C.destroyed&&C.components){for(var T,b=a(C.components);!(T=b()).done;){if(B(T.value)===p&&(_.push({entityId:C.id,entityName:C.name||"Entity_"+C.id,memory:y}),++S>=100))break}if(S>=100)break}}n.set(p,{count:m,totalMemory:v,instances:_.slice(0,10)})}var M=Array.from(n.entries()).map((function(e){var t=e[0],n=e[1];return{typeName:t,instanceCount:n.count,totalMemory:n.totalMemory,averageMemory:n.totalMemory/n.count,percentage:i>0?n.totalMemory/i*100:0,largestInstances:n.instances.sort((function(e,t){return t.memory-e.memory})).slice(0,3)}})).sort((function(e,t){return t.totalMemory-e.totalMemory}));return{totalMemory:i,componentTypes:n.size,totalInstances:Array.from(n.values()).reduce((function(e,t){return e+t.count}),0),breakdown:M}},t.collectSystemMemoryStats=function(){var e=this.sceneProvider(),t=0,n=[];try{var i=null==e?void 0:e.entityProcessors;if(i&&i.processors)for(var r,o=new Map,s=a(i.processors);!(r=s()).done;){var c=r.value,u=L(c),h=void 0;o.has(u)?h=o.get(u):(h=this.calculateQuickSystemSize(c),o.set(u,h)),t+=h,n.push({name:u,memory:h,enabled:!1!==c.enabled,updateOrder:c.updateOrder||0})}}catch(e){}return{totalMemory:t,systemCount:n.length,breakdown:n.sort((function(e,t){return t.memory-e.memory}))}},t.calculateQuickSystemSize=function(e){if(!e||"object"!=typeof e)return 64;var t=128;try{for(var n=Object.keys(e),i=0;i1?n-1:0),r=1;r0&&e.push("all("+this.condition.all.map((function(e){return O(e)})).join(", ")+")"),this.condition.any.length>0&&e.push("any("+this.condition.any.map((function(e){return O(e)})).join(", ")+")"),this.condition.none.length>0&&e.push("none("+this.condition.none.map((function(e){return O(e)})).join(", ")+")"),void 0!==this.condition.tag&&e.push("tag("+this.condition.tag+")"),void 0!==this.condition.name&&e.push("name("+this.condition.name+")"),void 0!==this.condition.component&&e.push("component("+O(this.condition.component)+")"),"Matcher["+e.join(" & ")+"]"},e}(),ze=function(){function e(e){this._updateOrder=0,this._enabled=!0,this._performanceMonitor=C.instance,this._systemName=L(this),this._initialized=!1,this._matcher=e||Oe.empty(),this._eventListeners=[],this._scene=null,this._entityIdMap=null,this._entityIdMapVersion=-1,this._entityIdMapSize=0,this._entityCache={frame:null,persistent:null,tracked:new Set,invalidate:function(){this.persistent=null},clearFrame:function(){this.frame=null},clearAll:function(){this.frame=null,this.persistent=null,this.tracked.clear()}}}var t=e.prototype;return t.setUpdateOrder=function(e){this._updateOrder=e,this.scene&&this.scene.entityProcessors&&this.scene.entityProcessors.setDirty()},t.initialize=function(){this._initialized||(this._initialized=!0,this.scene&&(this._entityCache.invalidate(),this.queryEntities()),this.onInitialize())},t.onInitialize=function(){},t.clearEntityCache=function(){this._entityCache.invalidate()},t.reset=function(){this.scene=null,this._initialized=!1,this._entityCache.clearAll(),this._entityIdMap=null,this._entityIdMapVersion=-1,this._entityIdMapSize=0,this.cleanupEventListeners(),this.onDestroy()},t.queryEntities=function(){var e;if(null===(e=this.scene)||void 0===e||!e.querySystem||!this._matcher)return[];var t=this._matcher.getCondition(),n=this.scene.querySystem,i=[];return i=this._matcher.isEmpty()?n.getAllEntities():this.isSingleCondition(t)?this.executeSingleConditionQuery(t,n):this.executeComplexQuery(t,n),this.updateEntityTracking(i),i},t.isSingleCondition=function(e){var t=(e.all.length>0?1:0)|(e.any.length>0?2:0)|(e.none.length>0?4:0)|(void 0!==e.tag?8:0)|(void 0!==e.name?16:0)|(void 0!==e.component?32:0);return 0!==t&&!(t&t-1)},t.executeSingleConditionQuery=function(e,t){return void 0!==e.tag?t.queryByTag(e.tag).entities:void 0!==e.name?t.queryByName(e.name).entities:void 0!==e.component?t.queryByComponent(e.component).entities:e.all.length>0&&0===e.any.length&&0===e.none.length?t.queryAll.apply(t,e.all).entities:0===e.all.length&&e.any.length>0&&0===e.none.length?t.queryAny.apply(t,e.any).entities:0===e.all.length&&0===e.any.length&&e.none.length>0?t.queryNone.apply(t,e.none).entities:[]},t.executeComplexQueryWithIdSets=function(e,t){var n=null;if(void 0!==e.tag){var i=t.queryByTag(e.tag);n=this.extractEntityIds(i.entities)}if(void 0!==e.name){var r=this.extractEntityIds(t.queryByName(e.name).entities);n=n?this.intersectIdSets(n,r):r}if(void 0!==e.component){var o=this.extractEntityIds(t.queryByComponent(e.component).entities);n=n?this.intersectIdSets(n,o):o}if(e.all.length>0){var s=this.extractEntityIds(t.queryAll.apply(t,e.all).entities);n=n?this.intersectIdSets(n,s):s}if(e.any.length>0){var a=this.extractEntityIds(t.queryAny.apply(t,e.any).entities);n=n?this.intersectIdSets(n,a):a}if(e.none.length>0){n||(n=this.extractEntityIds(t.getAllEntities()));var c=t.queryAny.apply(t,e.none),u=this.extractEntityIds(c.entities);n=this.differenceIdSets(n,u)}return n?this.idSetToEntityArray(n,t.getAllEntities()):[]},t.extractEntityIds=function(e){for(var t=e.length,n=new Set,i=0;i=0){var i=this._eventListeners[n];i.eventSystem.off(e,i.listenerRef),this._eventListeners.splice(n,1)}},t.cleanupEventListeners=function(){for(var e,t=a(this._eventListeners);!(e=t()).done;){var n=e.value;try{n.eventSystem.off(n.eventType,n.listenerRef)}catch(e){console.warn("["+this.systemName+'] Failed to remove event listener for "'+n.eventType+'":',e)}}this._eventListeners.length=0},t.onDestroy=function(){},s(e,[{key:"entities",get:function(){return null!==this._entityCache.frame?this._entityCache.frame:(null===this._entityCache.persistent&&(this._entityCache.persistent=this.queryEntities()),this._entityCache.persistent)}},{key:"updateOrder",get:function(){return this._updateOrder},set:function(e){this.setUpdateOrder(e)}},{key:"enabled",get:function(){return this._enabled},set:function(e){this._enabled=e}},{key:"systemName",get:function(){return this._systemName}},{key:"scene",get:function(){return this._scene},set:function(e){this._scene=e}},{key:"matcher",get:function(){return this._matcher}}])}(),Be=function(e){function t(t){return e.call(this,t)||this}return h(t,e),t.prototype.process=function(e){this.processSystem()},t}(ze),Le=function(e){function t(t){return e.call(this,t)||this}return h(t,e),t.prototype.process=function(e){},t}(ze),Fe=function(e){function t(t,n){var i;return(i=e.call(this,n)||this).acc=0,i.intervalRemainder=0,i.interval=t,i}h(t,e);var n=t.prototype;return n.onCheckProcessing=function(){return this.acc+=g.deltaTime,this.acc>=this.interval&&(this.intervalRemainder=this.acc-this.interval,this.acc=0,!0)},n.getIntervalDelta=function(){return this.interval+this.intervalRemainder},t}(ze),We=function(e){function t(t,n){var i,r,o,s,a,c;return void 0===n&&(n={}),(c=e.call(this,t)||this).workerPool=null,c.isProcessing=!1,c.sharedBuffer=null,c.sharedFloatArray=null,c.config={enableWorker:null===(i=n.enableWorker)||void 0===i||i,workerCount:null!==(r=n.workerCount)&&void 0!==r?r:c.getOptimalWorkerCount(),systemConfig:n.systemConfig,useSharedArrayBuffer:null!==(o=n.useSharedArrayBuffer)&&void 0!==o?o:c.isSharedArrayBufferSupported(),entityDataSize:null!==(s=n.entityDataSize)&&void 0!==s?s:c.getDefaultEntityDataSize(),maxEntities:null!==(a=n.maxEntities)&&void 0!==a?a:1e4},c.config.enableWorker&&c.isWorkerSupported()&&(c.config.useSharedArrayBuffer&&c.initializeSharedArrayBuffer(),c.initializeWorkerPool()),c}h(t,e);var n=t.prototype;return n.isWorkerSupported=function(){return"undefined"!=typeof Worker&&"undefined"!=typeof Blob},n.isSharedArrayBufferSupported=function(){return"undefined"!=typeof SharedArrayBuffer&&self.crossOriginIsolated},n.getOptimalWorkerCount=function(){return"undefined"!=typeof navigator&&navigator.hardwareConcurrency?Math.min(navigator.hardwareConcurrency,4):2},n.initializeSharedArrayBuffer=function(){try{var e=this.config.maxEntities*this.config.entityDataSize*4;this.sharedBuffer=new SharedArrayBuffer(e),this.sharedFloatArray=new Float32Array(this.sharedBuffer)}catch(e){console.warn("["+this.systemName+"] SharedArrayBuffer init failed:",e),this.config.useSharedArrayBuffer=!1}},n.initializeWorkerPool=function(){try{var e=this.createWorkerScript();this.workerPool=new qe(this.config.workerCount,e,this.sharedBuffer)}catch(e){console.error("["+this.systemName+"] Failed to initialize worker pool:",e),this.config.enableWorker=!1}},n.createWorkerScript=function(){var e,t=this.workerProcess.toString().match(/\{([\s\S]*)\}/);if(!t)throw new Error("无法解析workerProcess方法");var n=t[1],i=this.config.entityDataSize,r=(null===(e=this.getSharedArrayBufferProcessFunction)||void 0===e?void 0:e.call(this))||null,o="";if(r){var s=r.toString().match(/\{([\s\S]*)\}/);s&&(o=s[1])}return"\n // Worker脚本 - 支持SharedArrayBuffer\n let sharedFloatArray = null;\n const ENTITY_DATA_SIZE = "+i+";\n\n self.onmessage = function(e) {\n const { type, id, entities, deltaTime, systemConfig, startIndex, endIndex, sharedBuffer } = e.data;\n\n\n try {\n // 处理SharedArrayBuffer初始化\n if (type === 'init' && sharedBuffer) {\n sharedFloatArray = new Float32Array(sharedBuffer);\n self.postMessage({ type: 'init', success: true });\n return;\n }\n\n // 处理SharedArrayBuffer数据\n if (type === 'shared' && sharedFloatArray) {\n processSharedArrayBuffer(startIndex, endIndex, deltaTime, systemConfig);\n self.postMessage({ id, result: null }); // SharedArrayBuffer不需要返回数据\n return;\n }\n\n // 传统处理方式\n if (entities) {\n // 定义处理函数\n function workerProcess(entities, deltaTime, systemConfig) {\n "+n+"\n }\n\n // 执行处理\n const result = workerProcess(entities, deltaTime, systemConfig);\n\n // 处理Promise返回值\n if (result && typeof result.then === 'function') {\n result.then(finalResult => {\n self.postMessage({ id, result: finalResult });\n }).catch(error => {\n self.postMessage({ id, error: error.message });\n });\n } else {\n self.postMessage({ id, result });\n }\n }\n } catch (error) {\n self.postMessage({ id, error: error.message });\n }\n };\n\n // SharedArrayBuffer处理函数 - 由子类定义\n function processSharedArrayBuffer(startIndex, endIndex, deltaTime, systemConfig) {\n if (!sharedFloatArray) return;\n\n "+(o?"\n // 用户定义的处理函数\n const userProcessFunction = function(sharedFloatArray, startIndex, endIndex, deltaTime, systemConfig) {\n "+o+"\n };\n userProcessFunction(sharedFloatArray, startIndex, endIndex, deltaTime, systemConfig);\n ":"")+"\n }\n "},n.process=function(e){var t=this;if(!this.isProcessing){this.isProcessing=!0;try{this.config.enableWorker&&this.workerPool?this.config.useSharedArrayBuffer&&this.sharedFloatArray?this.processWithSharedArrayBuffer(e).finally((function(){t.isProcessing=!1})):this.processWithWorker(e).finally((function(){t.isProcessing=!1})):(this.processSynchronously(e),this.isProcessing=!1)}catch(e){throw this.isProcessing=!1,e}}},n.processWithSharedArrayBuffer=function(){var e=i(d().m((function e(t){var n;return d().w((function(e){for(;;)switch(e.n){case 0:if(this.sharedFloatArray){e.n=1;break}throw new Error("SharedArrayBuffer not initialized");case 1:return this.writeEntitiesToSharedBuffer(t),n=this.createSharedArrayBufferTasks(t.length),e.n=2,Promise.all(n);case 2:this.readResultsFromSharedBuffer(t);case 3:return e.a(2)}}),e,this)})));return function(t){return e.apply(this,arguments)}}(),n.processWithWorker=function(){var e=i(d().m((function e(t){var n,i,r,o,s,c,u,h,l,f,p,m,y,v,_=this;return d().w((function(e){for(;;)switch(e.n){case 0:for(n=[],i=0;i0){var t=this.taskQueue.shift();this.busyWorkers.add(e),this.workers[e].postMessage(c({id:t.id},t.data)),this.workers[e]._currentTask=t}},t.handleWorkerMessage=function(e,t){var n=this.workers[e],i=n._currentTask;i&&(this.busyWorkers.delete(e),n._currentTask=null,t.error?i.reject(new Error(t.error)):i.resolve(t.result),this.processQueue())},t.handleWorkerError=function(e,t){var n=this.workers[e],i=n._currentTask;i&&(this.busyWorkers.delete(e),n._currentTask=null,i.reject(new Error(t.message))),this.processQueue()},t.destroy=function(){for(var e,t=a(this.workers);!(e=t()).done;){e.value.terminate()}this.workers.length=0,this.taskQueue.length=0,this.busyWorkers.clear()},e}(),je=function(){function e(){}return e.getType=function(e){return e.constructor},e}(),Ue=function(){function e(){}return e.toNumber=function(e){return null==e?0:Number(e)},e}();e.AsyncEventHandler=function(e,t){return void 0===t&&(t={}),function(n,i,r){var o=r.value,s=n.constructor.prototype.initEventListeners||function(){};return n.constructor.prototype.initEventListeners=function(){s.call(this),ue.getInstance().onAsync(e,o.bind(this),t)},r}},e.BitMask64Utils=w,e.Bits=Se,e.COMPONENT_TYPE_NAME=R,e.Colors=A,e.Component=Ne,e.ComponentDataCollector=Ae,e.ComponentPool=Me,e.ComponentPoolManager=we,e.ComponentRegistry=F,e.ComponentSparseSet=Z,e.ComponentStorage=W,e.ComponentTypeManager=Ee,e.ConsoleLogger=I,e.Core=ke,e.DebugManager=De,e.ECSComponent=function(e){return function(t){if(!e||"string"!=typeof e)throw new Error("ECSComponent装饰器必须提供有效的类型名称");return t[R]=e,t}},e.ECSFluentAPI=pe,e.ECSSystem=function(e){return function(t){if(!e||"string"!=typeof e)throw new Error("ECSSystem装饰器必须提供有效的类型名称");return t[N]=e,t}},e.EVENT_TYPES=se,e.Emitter=Re,e.EnableSoA=function(e){return e.__enableSoA=!0,e},e.Entity=U,e.EntityDataCollector=Ce,e.EntityList=G,e.EntityProcessorList=Y,e.EntitySystem=ze,e.EventBus=ce,e.EventHandler=function(e,t){return void 0===t&&(t={}),function(n,i,r){var o=r.value,s=n.constructor.prototype.initEventListeners||function(){};return n.constructor.prototype.initEventListeners=function(){s.call(this),ue.getInstance().on(e,o.bind(this),t)},r}},e.EventTypeValidator=ae,e.Float32=function(e,t){var n=String(t);e.constructor.__float32Fields||(e.constructor.__float32Fields=new Set),e.constructor.__float32Fields.add(n)},e.Float64=function(e,t){var n=String(t);e.constructor.__float64Fields||(e.constructor.__float64Fields=new Set),e.constructor.__float64Fields.add(n)},e.FuncPack=Pe,e.GlobalEventBus=ue,e.GlobalManager=v,e.HighPrecision=function(e,t){var n=String(t);e.constructor.__highPrecisionFields||(e.constructor.__highPrecisionFields=new Set),e.constructor.__highPrecisionFields.add(n)},e.IdentifierPool=Q,e.Int32=function(e,t){var n=String(t);e.constructor.__int32Fields||(e.constructor.__int32Fields=new Set),e.constructor.__int32Fields.add(n)},e.IntervalSystem=Fe,e.Logger=D,e.LoggerManager=x,e.Matcher=Oe,e.NumberExtension=Ue,e.PassiveSystem=Le,e.PerformanceDataCollector=be,e.PerformanceMonitor=C,e.Pool=T,e.PoolManager=M,e.ProcessingSystem=Be,e.QuerySystem=ie,e.SYSTEM_TYPE_NAME=N,e.Scene=he,e.SceneDataCollector=Ie,e.SerializeMap=function(e,t){var n=String(t);e.constructor.__serializeMapFields||(e.constructor.__serializeMapFields=new Set),e.constructor.__serializeMapFields.add(n)},e.SoAStorage=P,e.SparseSet=V,e.SystemDataCollector=Te,e.Time=g,e.Timer=S,e.TimerManager=E,e.TypeSafeEventSystem=oe,e.TypeUtils=je,e.WebSocketManager=xe,e.WorkerEntitySystem=We,e.World=ve,e.WorldManager=_e,e.createECSAPI=me,e.createLogger=k,e.getComponentInstanceTypeName=B,e.getComponentTypeName=O,e.getSystemInstanceTypeName=L,e.getSystemTypeName=z,e.resetLoggerColors=function(){x.getInstance().resetColors()},e.setGlobalLogLevel=function(e){x.getInstance().setGlobalLevel(e)},e.setLoggerColors=function(e){x.getInstance().setGlobalColors(e)}})); +//# sourceMappingURL=index.umd.js.map diff --git a/docs/public/demos/worker-system/assets/index-a4a166b2.js b/docs/public/demos/worker-system/assets/index-a4a166b2.js new file mode 100644 index 00000000..b004eca1 --- /dev/null +++ b/docs/public/demos/worker-system/assets/index-a4a166b2.js @@ -0,0 +1,12754 @@ +(function polyfill() { + const relList = document.createElement("link").relList; + if (relList && relList.supports && relList.supports("modulepreload")) { + return; + } + for (const link of document.querySelectorAll('link[rel="modulepreload"]')) { + processPreload(link); + } + new MutationObserver((mutations) => { + for (const mutation of mutations) { + if (mutation.type !== "childList") { + continue; + } + for (const node of mutation.addedNodes) { + if (node.tagName === "LINK" && node.rel === "modulepreload") + processPreload(node); + } + } + }).observe(document, { childList: true, subtree: true }); + function getFetchOpts(link) { + const fetchOpts = {}; + if (link.integrity) + fetchOpts.integrity = link.integrity; + if (link.referrerPolicy) + fetchOpts.referrerPolicy = link.referrerPolicy; + if (link.crossOrigin === "use-credentials") + fetchOpts.credentials = "include"; + else if (link.crossOrigin === "anonymous") + fetchOpts.credentials = "omit"; + else + fetchOpts.credentials = "same-origin"; + return fetchOpts; + } + function processPreload(link) { + if (link.ep) + return; + link.ep = true; + const fetchOpts = getFetchOpts(link); + fetch(link.href, fetchOpts); + } +})(); +class GlobalManager { + constructor() { + this._enabled = false; + } + /** + * 获取或设置管理器是否启用 + */ + get enabled() { + return this._enabled; + } + set enabled(value) { + this.setEnabled(value); + } + /** + * 设置管理器是否启用 + * @param isEnabled 如果为true,则启用管理器;否则禁用管理器 + */ + setEnabled(isEnabled) { + if (this._enabled != isEnabled) { + this._enabled = isEnabled; + if (this._enabled) { + this.onEnabled(); + } else { + this.onDisabled(); + } + } + } + /** + * 在启用管理器时调用的回调方法 + */ + onEnabled() { + } + /** + * 在禁用管理器时调用的回调方法 + */ + onDisabled() { + } + /** + * 更新管理器状态的方法 + */ + update() { + } +} +class Time { + /** + * 使用外部引擎提供的deltaTime更新时间信息 + * @param deltaTime 外部引擎提供的帧时间间隔(秒) + */ + static update(deltaTime) { + this.unscaledDeltaTime = deltaTime; + this.deltaTime = deltaTime * this.timeScale; + this.unscaledTotalTime += this.unscaledDeltaTime; + this.totalTime += this.deltaTime; + this.frameCount++; + } + /** + * 场景改变时重置时间 + */ + static sceneChanged() { + this.frameCount = 0; + this.totalTime = 0; + this.unscaledTotalTime = 0; + this.deltaTime = 0; + this.unscaledDeltaTime = 0; + } + /** + * 检查指定的时间间隔是否已经过去 + * @param interval 时间间隔(秒) + * @param lastTime 上次检查的时间 + * @returns 是否已经过去指定时间 + */ + static checkEvery(interval, lastTime) { + return this.totalTime - lastTime >= interval; + } +} +Time.deltaTime = 0; +Time.unscaledDeltaTime = 0; +Time.totalTime = 0; +Time.unscaledTotalTime = 0; +Time.timeScale = 1; +Time.frameCount = 0; +class Timer { + constructor() { + this._timeInSeconds = 0; + this._repeats = false; + this._isDone = false; + this._elapsedTime = 0; + } + getContext() { + return this.context; + } + /** + * 定时器是否已完成 + */ + get isDone() { + return this._isDone; + } + /** + * 定时器已运行的时间 + */ + get elapsedTime() { + return this._elapsedTime; + } + reset() { + this._elapsedTime = 0; + } + stop() { + this._isDone = true; + } + tick() { + if (!this._isDone && this._elapsedTime > this._timeInSeconds) { + this._elapsedTime -= this._timeInSeconds; + this._onTime(this); + if (!this._isDone && !this._repeats) + this._isDone = true; + } + this._elapsedTime += Time.deltaTime; + return this._isDone; + } + initialize(timeInsSeconds, repeats, context, onTime) { + this._timeInSeconds = timeInsSeconds; + this._repeats = repeats; + this.context = context; + this._onTime = onTime.bind(context); + } + /** + * 空出对象引用,以便在js需要时GC可以清理它们的引用 + */ + unload() { + this.context = null; + this._onTime = null; + } +} +class TimerManager extends GlobalManager { + constructor() { + super(...arguments); + this._timers = []; + } + update() { + for (let i = this._timers.length - 1; i >= 0; i--) { + if (this._timers[i].tick()) { + this._timers[i].unload(); + this._timers.splice(i, 1); + } + } + } + /** + * 调度一个一次性或重复的计时器,该计时器将调用已传递的动作 + * @param timeInSeconds + * @param repeats + * @param context + * @param onTime + */ + schedule(timeInSeconds, repeats, context, onTime) { + let timer = new Timer(); + timer.initialize(timeInSeconds, repeats, context, onTime); + this._timers.push(timer); + return timer; + } +} +var PerformanceWarningType; +(function(PerformanceWarningType2) { + PerformanceWarningType2["HIGH_EXECUTION_TIME"] = "high_execution_time"; + PerformanceWarningType2["HIGH_MEMORY_USAGE"] = "high_memory_usage"; + PerformanceWarningType2["HIGH_CPU_USAGE"] = "high_cpu_usage"; + PerformanceWarningType2["FREQUENT_GC"] = "frequent_gc"; + PerformanceWarningType2["LOW_FPS"] = "low_fps"; + PerformanceWarningType2["HIGH_ENTITY_COUNT"] = "high_entity_count"; +})(PerformanceWarningType || (PerformanceWarningType = {})); +class PerformanceMonitor { + /** + * 获取单例实例 + */ + static get instance() { + if (!PerformanceMonitor._instance) { + PerformanceMonitor._instance = new PerformanceMonitor(); + } + return PerformanceMonitor._instance; + } + constructor() { + this._systemData = /* @__PURE__ */ new Map(); + this._systemStats = /* @__PURE__ */ new Map(); + this._warnings = []; + this._isEnabled = false; + this._maxRecentSamples = 60; + this._maxWarnings = 100; + this._thresholds = { + executionTime: { warning: 16.67, critical: 33.33 }, + // 60fps和30fps对应的帧时间 + memoryUsage: { warning: 100, critical: 200 }, + // MB + cpuUsage: { warning: 70, critical: 90 }, + // 百分比 + fps: { warning: 45, critical: 30 }, + entityCount: { warning: 1e3, critical: 5e3 } + }; + this._fpsHistory = []; + this._lastFrameTime = 0; + this._frameCount = 0; + this._fpsUpdateInterval = 1e3; + this._lastFpsUpdate = 0; + this._currentFps = 60; + this._memoryCheckInterval = 5e3; + this._lastMemoryCheck = 0; + this._memoryHistory = []; + this._gcCount = 0; + this._lastGcCheck = 0; + this._gcCheckInterval = 1e3; + } + /** + * 启用性能监控 + */ + enable() { + this._isEnabled = true; + } + /** + * 禁用性能监控 + */ + disable() { + this._isEnabled = false; + } + /** + * 检查是否启用了性能监控 + */ + get isEnabled() { + return this._isEnabled; + } + /** + * 开始监控系统性能 + * @param systemName 系统名称 + * @returns 开始时间戳 + */ + startMonitoring(systemName) { + if (!this._isEnabled) { + return 0; + } + return performance.now(); + } + /** + * 结束监控并记录性能数据 + * @param systemName 系统名称 + * @param startTime 开始时间戳 + * @param entityCount 处理的实体数量 + */ + endMonitoring(systemName, startTime, entityCount = 0) { + if (!this._isEnabled || startTime === 0) { + return; + } + const endTime = performance.now(); + const executionTime = endTime - startTime; + const averageTimePerEntity = entityCount > 0 ? executionTime / entityCount : 0; + const data = { + name: systemName, + executionTime, + entityCount, + averageTimePerEntity, + lastUpdateTime: endTime + }; + this._systemData.set(systemName, data); + this.updateStats(systemName, executionTime); + } + /** + * 更新系统统计信息 + * @param systemName 系统名称 + * @param executionTime 执行时间 + */ + updateStats(systemName, executionTime) { + let stats = this._systemStats.get(systemName); + if (!stats) { + stats = { + totalTime: 0, + averageTime: 0, + minTime: Number.MAX_VALUE, + maxTime: 0, + executionCount: 0, + recentTimes: [], + standardDeviation: 0, + percentile95: 0, + percentile99: 0 + }; + this._systemStats.set(systemName, stats); + } + stats.totalTime += executionTime; + stats.executionCount++; + stats.averageTime = stats.totalTime / stats.executionCount; + stats.minTime = Math.min(stats.minTime, executionTime); + stats.maxTime = Math.max(stats.maxTime, executionTime); + stats.recentTimes.push(executionTime); + if (stats.recentTimes.length > this._maxRecentSamples) { + stats.recentTimes.shift(); + } + this.calculateAdvancedStats(stats); + } + /** + * 计算高级统计信息 + * @param stats 统计信息对象 + */ + calculateAdvancedStats(stats) { + if (stats.recentTimes.length === 0) + return; + const mean = stats.recentTimes.reduce((a, b) => a + b, 0) / stats.recentTimes.length; + const variance = stats.recentTimes.reduce((acc, time) => acc + Math.pow(time - mean, 2), 0) / stats.recentTimes.length; + stats.standardDeviation = Math.sqrt(variance); + const sortedTimes = [...stats.recentTimes].sort((a, b) => a - b); + const len = sortedTimes.length; + stats.percentile95 = sortedTimes[Math.floor(len * 0.95)] || 0; + stats.percentile99 = sortedTimes[Math.floor(len * 0.99)] || 0; + } + /** + * 获取系统的当前性能数据 + * @param systemName 系统名称 + * @returns 性能数据或undefined + */ + getSystemData(systemName) { + return this._systemData.get(systemName); + } + /** + * 获取系统的统计信息 + * @param systemName 系统名称 + * @returns 统计信息或undefined + */ + getSystemStats(systemName) { + return this._systemStats.get(systemName); + } + /** + * 获取所有系统的性能数据 + * @returns 所有系统的性能数据 + */ + getAllSystemData() { + return new Map(this._systemData); + } + /** + * 获取所有系统的统计信息 + * @returns 所有系统的统计信息 + */ + getAllSystemStats() { + return new Map(this._systemStats); + } + /** + * 获取性能报告 + * @returns 格式化的性能报告字符串 + */ + getPerformanceReport() { + if (!this._isEnabled) { + return "Performance monitoring is disabled."; + } + const lines = []; + lines.push("=== ECS Performance Report ==="); + lines.push(""); + const sortedSystems = Array.from(this._systemStats.entries()).sort((a, b) => b[1].averageTime - a[1].averageTime); + for (const [systemName, stats] of sortedSystems) { + const data = this._systemData.get(systemName); + lines.push(`System: ${systemName}`); + lines.push(` Current: ${data?.executionTime.toFixed(2)}ms (${data?.entityCount} entities)`); + lines.push(` Average: ${stats.averageTime.toFixed(2)}ms`); + lines.push(` Min/Max: ${stats.minTime.toFixed(2)}ms / ${stats.maxTime.toFixed(2)}ms`); + lines.push(` Total: ${stats.totalTime.toFixed(2)}ms (${stats.executionCount} calls)`); + if (data?.averageTimePerEntity && data.averageTimePerEntity > 0) { + lines.push(` Per Entity: ${data.averageTimePerEntity.toFixed(4)}ms`); + } + lines.push(""); + } + const totalCurrentTime = Array.from(this._systemData.values()).reduce((sum, data) => sum + data.executionTime, 0); + lines.push(`Total Frame Time: ${totalCurrentTime.toFixed(2)}ms`); + lines.push(`Systems Count: ${this._systemData.size}`); + return lines.join("\n"); + } + /** + * 重置所有性能数据 + */ + reset() { + this._systemData.clear(); + this._systemStats.clear(); + } + /** + * 重置指定系统的性能数据 + * @param systemName 系统名称 + */ + resetSystem(systemName) { + this._systemData.delete(systemName); + this._systemStats.delete(systemName); + } + /** + * 获取性能警告 + * @param thresholdMs 警告阈值(毫秒) + * @returns 超过阈值的系统列表 + */ + getPerformanceWarnings(thresholdMs = 16.67) { + const warnings = []; + for (const [systemName, data] of this._systemData.entries()) { + if (data.executionTime > thresholdMs) { + warnings.push(`${systemName}: ${data.executionTime.toFixed(2)}ms (>${thresholdMs}ms)`); + } + } + return warnings; + } + /** + * 设置最大保留样本数 + * @param maxSamples 最大样本数 + */ + setMaxRecentSamples(maxSamples) { + this._maxRecentSamples = maxSamples; + for (const stats of this._systemStats.values()) { + while (stats.recentTimes.length > maxSamples) { + stats.recentTimes.shift(); + } + } + } +} +class Pool { + /** + * 构造函数 + * @param createFn 创建对象的函数 + * @param maxSize 池的最大大小,默认100 + * @param estimatedObjectSize 估算的单个对象大小(字节),默认1024 + */ + constructor(createFn, maxSize = 100, estimatedObjectSize = 1024) { + this._objects = []; + this._createFn = createFn; + this._maxSize = maxSize; + this._objectSize = estimatedObjectSize; + this._stats = { + size: 0, + maxSize, + totalCreated: 0, + totalObtained: 0, + totalReleased: 0, + hitRate: 0, + estimatedMemoryUsage: 0 + }; + } + /** + * 获取指定类型的对象池 + * @param type 对象类型 + * @param maxSize 池的最大大小 + * @param estimatedObjectSize 估算的单个对象大小 + * @returns 对象池实例 + */ + static getPool(type, maxSize = 100, estimatedObjectSize = 1024) { + let pool = this._pools.get(type); + if (!pool) { + pool = new Pool(() => new type(), maxSize, estimatedObjectSize); + this._pools.set(type, pool); + } + return pool; + } + /** + * 从池中获取对象 + * @returns 对象实例 + */ + obtain() { + this._stats.totalObtained++; + if (this._objects.length > 0) { + const obj = this._objects.pop(); + this._stats.size--; + this._updateHitRate(); + this._updateMemoryUsage(); + return obj; + } + this._stats.totalCreated++; + this._updateHitRate(); + return this._createFn(); + } + /** + * 释放对象回池中 + * @param obj 要释放的对象 + */ + release(obj) { + if (!obj) + return; + this._stats.totalReleased++; + if (this._stats.size < this._maxSize) { + obj.reset(); + this._objects.push(obj); + this._stats.size++; + this._updateMemoryUsage(); + } + } + /** + * 获取池统计信息 + * @returns 统计信息对象 + */ + getStats() { + return { ...this._stats }; + } + /** + * 清空池 + */ + clear() { + for (const obj of this._objects) { + obj.reset(); + } + this._objects.length = 0; + this._stats.size = 0; + this._updateMemoryUsage(); + } + /** + * 压缩池(移除多余的对象) + * @param targetSize 目标大小,默认为当前大小的一半 + */ + compact(targetSize) { + const target = targetSize ?? Math.floor(this._objects.length / 2); + while (this._objects.length > target) { + const obj = this._objects.pop(); + if (obj) { + obj.reset(); + this._stats.size--; + } + } + this._updateMemoryUsage(); + } + /** + * 预填充池 + * @param count 预填充的对象数量 + */ + prewarm(count) { + const actualCount = Math.min(count, this._maxSize - this._objects.length); + for (let i = 0; i < actualCount; i++) { + const obj = this._createFn(); + obj.reset(); + this._objects.push(obj); + this._stats.totalCreated++; + this._stats.size++; + } + this._updateMemoryUsage(); + } + /** + * 设置最大池大小 + * @param maxSize 新的最大大小 + */ + setMaxSize(maxSize) { + this._maxSize = maxSize; + this._stats.maxSize = maxSize; + if (this._objects.length > maxSize) { + this.compact(maxSize); + } + } + /** + * 获取池中可用对象数量 + * @returns 可用对象数量 + */ + getAvailableCount() { + return this._objects.length; + } + /** + * 检查池是否为空 + * @returns 如果池为空返回true + */ + isEmpty() { + return this._objects.length === 0; + } + /** + * 检查池是否已满 + * @returns 如果池已满返回true + */ + isFull() { + return this._objects.length >= this._maxSize; + } + /** + * 获取所有已注册的池类型 + * @returns 所有池类型的数组 + */ + static getAllPoolTypes() { + return Array.from(this._pools.keys()); + } + /** + * 获取所有池的统计信息 + * @returns 包含所有池统计信息的对象 + */ + static getAllPoolStats() { + const stats = {}; + for (const [type, pool] of this._pools) { + const typeName = type.name || type.toString(); + stats[typeName] = pool.getStats(); + } + return stats; + } + /** + * 压缩所有池 + */ + static compactAllPools() { + for (const pool of this._pools.values()) { + pool.compact(); + } + } + /** + * 清空所有池 + */ + static clearAllPools() { + for (const pool of this._pools.values()) { + pool.clear(); + } + this._pools.clear(); + } + /** + * 获取全局池统计信息的格式化字符串 + * @returns 格式化的统计信息字符串 + */ + static getGlobalStatsString() { + const stats = this.getAllPoolStats(); + const lines = ["=== Object Pool Global Statistics ===", ""]; + if (Object.keys(stats).length === 0) { + lines.push("No pools registered"); + return lines.join("\n"); + } + for (const [typeName, stat] of Object.entries(stats)) { + lines.push(`${typeName}:`); + lines.push(` Size: ${stat.size}/${stat.maxSize}`); + lines.push(` Hit Rate: ${(stat.hitRate * 100).toFixed(1)}%`); + lines.push(` Total Created: ${stat.totalCreated}`); + lines.push(` Total Obtained: ${stat.totalObtained}`); + lines.push(` Memory: ${(stat.estimatedMemoryUsage / 1024).toFixed(1)} KB`); + lines.push(""); + } + return lines.join("\n"); + } + /** + * 更新命中率 + */ + _updateHitRate() { + if (this._stats.totalObtained === 0) { + this._stats.hitRate = 0; + } else { + const hits = this._stats.totalObtained - this._stats.totalCreated; + this._stats.hitRate = hits / this._stats.totalObtained; + } + } + /** + * 更新内存使用估算 + */ + _updateMemoryUsage() { + this._stats.estimatedMemoryUsage = this._stats.size * this._objectSize; + } +} +Pool._pools = /* @__PURE__ */ new Map(); +class PoolManager { + constructor() { + this.pools = /* @__PURE__ */ new Map(); + this.autoCompactInterval = 6e4; + this.lastCompactTime = 0; + } + static getInstance() { + if (!PoolManager.instance) { + PoolManager.instance = new PoolManager(); + } + return PoolManager.instance; + } + /** + * 注册池 + * @param name 池名称 + * @param pool 池实例 + */ + registerPool(name, pool) { + this.pools.set(name, pool); + } + /** + * 获取池 + * @param name 池名称 + * @returns 池实例 + */ + getPool(name) { + return this.pools.get(name) || null; + } + /** + * 更新池管理器(应在游戏循环中调用) + */ + update() { + const now = Date.now(); + if (now - this.lastCompactTime > this.autoCompactInterval) { + this.compactAllPools(); + this.lastCompactTime = now; + } + } + /** + * 创建或获取标准池 + * @param name 池名称 + * @param createFn 创建函数 + * @param maxSize 最大大小 + * @param estimatedObjectSize 估算对象大小 + * @returns 池实例 + */ + createPool(name, createFn, maxSize = 100, estimatedObjectSize = 1024) { + let pool = this.pools.get(name); + if (!pool) { + pool = new Pool(createFn, maxSize, estimatedObjectSize); + this.pools.set(name, pool); + } + return pool; + } + /** + * 移除池 + * @param name 池名称 + * @returns 是否成功移除 + */ + removePool(name) { + const pool = this.pools.get(name); + if (pool) { + pool.clear(); + this.pools.delete(name); + return true; + } + return false; + } + /** + * 获取所有池名称 + * @returns 池名称数组 + */ + getPoolNames() { + return Array.from(this.pools.keys()); + } + /** + * 获取池数量 + * @returns 池数量 + */ + getPoolCount() { + return this.pools.size; + } + /** + * 压缩所有池 + */ + compactAllPools() { + for (const pool of this.pools.values()) { + pool.compact(); + } + } + /** + * 清空所有池 + */ + clearAllPools() { + for (const pool of this.pools.values()) { + pool.clear(); + } + } + /** + * 获取所有池的统计信息 + * @returns 统计信息映射 + */ + getAllStats() { + const stats = /* @__PURE__ */ new Map(); + for (const [name, pool] of this.pools) { + stats.set(name, pool.getStats()); + } + return stats; + } + /** + * 获取总体统计信息 + * @returns 总体统计信息 + */ + getGlobalStats() { + let totalSize = 0; + let totalMaxSize = 0; + let totalCreated = 0; + let totalObtained = 0; + let totalReleased = 0; + let totalMemoryUsage = 0; + for (const pool of this.pools.values()) { + const stats = pool.getStats(); + totalSize += stats.size; + totalMaxSize += stats.maxSize; + totalCreated += stats.totalCreated; + totalObtained += stats.totalObtained; + totalReleased += stats.totalReleased; + totalMemoryUsage += stats.estimatedMemoryUsage; + } + const hitRate = totalObtained === 0 ? 0 : (totalObtained - totalCreated) / totalObtained; + return { + size: totalSize, + maxSize: totalMaxSize, + totalCreated, + totalObtained, + totalReleased, + hitRate, + estimatedMemoryUsage: totalMemoryUsage + }; + } + /** + * 获取格式化的统计信息字符串 + * @returns 格式化字符串 + */ + getStatsString() { + const lines = ["=== Pool Manager Statistics ===", ""]; + if (this.pools.size === 0) { + lines.push("No pools registered"); + return lines.join("\n"); + } + const globalStats = this.getGlobalStats(); + lines.push(`Total Pools: ${this.pools.size}`); + lines.push(`Global Hit Rate: ${(globalStats.hitRate * 100).toFixed(1)}%`); + lines.push(`Global Memory Usage: ${(globalStats.estimatedMemoryUsage / 1024).toFixed(1)} KB`); + lines.push(""); + for (const [name, pool] of this.pools) { + const stats = pool.getStats(); + lines.push(`${name}:`); + lines.push(` Size: ${stats.size}/${stats.maxSize}`); + lines.push(` Hit Rate: ${(stats.hitRate * 100).toFixed(1)}%`); + lines.push(` Memory: ${(stats.estimatedMemoryUsage / 1024).toFixed(1)} KB`); + lines.push(""); + } + return lines.join("\n"); + } + /** + * 设置自动压缩间隔 + * @param intervalMs 间隔毫秒数 + */ + setAutoCompactInterval(intervalMs) { + this.autoCompactInterval = intervalMs; + } + /** + * 预填充所有池 + */ + prewarmAllPools() { + for (const pool of this.pools.values()) { + const stats = pool.getStats(); + const prewarmCount = Math.floor(stats.maxSize * 0.2); + pool.prewarm(prewarmCount); + } + } + /** + * 重置池管理器 + */ + reset() { + this.clearAllPools(); + this.pools.clear(); + this.lastCompactTime = 0; + } +} +class BitMask64Utils { + /** + * 根据位索引创建64位掩码 + * @param bitIndex 位索引,范围 [0, 63] + * @returns 包含指定位设置为1的掩码 + * @throws 当位索引超出范围时抛出错误 + */ + static create(bitIndex) { + if (bitIndex < 0 || bitIndex >= 64) { + throw new Error(`Bit index ${bitIndex} out of range [0, 63]`); + } + if (bitIndex < 32) { + return { lo: 1 << bitIndex, hi: 0 }; + } else { + return { lo: 0, hi: 1 << bitIndex - 32 }; + } + } + /** + * 从32位数字创建64位掩码 + * @param value 32位数字值 + * @returns 低32位为输入值、高32位为0的掩码 + */ + static fromNumber(value) { + return { lo: value >>> 0, hi: 0 }; + } + /** + * 检查掩码是否包含任意指定的位 + * @param mask 要检查的掩码 + * @param bits 指定的位模式 + * @returns 如果掩码包含bits中的任意位则返回true + */ + static hasAny(mask, bits) { + return (mask.lo & bits.lo) !== 0 || (mask.hi & bits.hi) !== 0; + } + /** + * 检查掩码是否包含所有指定的位 + * @param mask 要检查的掩码 + * @param bits 指定的位模式 + * @returns 如果掩码包含bits中的所有位则返回true + */ + static hasAll(mask, bits) { + return (mask.lo & bits.lo) === bits.lo && (mask.hi & bits.hi) === bits.hi; + } + /** + * 检查掩码是否不包含任何指定的位 + * @param mask 要检查的掩码 + * @param bits 指定的位模式 + * @returns 如果掩码不包含bits中的任何位则返回true + */ + static hasNone(mask, bits) { + return (mask.lo & bits.lo) === 0 && (mask.hi & bits.hi) === 0; + } + /** + * 检查掩码是否为零 + * @param mask 要检查的掩码 + * @returns 如果掩码所有位都为0则返回true + */ + static isZero(mask) { + return mask.lo === 0 && mask.hi === 0; + } + /** + * 检查两个掩码是否相等 + * @param a 第一个掩码 + * @param b 第二个掩码 + * @returns 如果两个掩码完全相等则返回true + */ + static equals(a, b) { + return a.lo === b.lo && a.hi === b.hi; + } + /** + * 设置掩码中指定位为1 + * @param mask 要修改的掩码(原地修改) + * @param bitIndex 位索引,范围 [0, 63] + * @throws 当位索引超出范围时抛出错误 + */ + static setBit(mask, bitIndex) { + if (bitIndex < 0 || bitIndex >= 64) { + throw new Error(`Bit index ${bitIndex} out of range [0, 63]`); + } + if (bitIndex < 32) { + mask.lo |= 1 << bitIndex; + } else { + mask.hi |= 1 << bitIndex - 32; + } + } + /** + * 清除掩码中指定位为0 + * @param mask 要修改的掩码(原地修改) + * @param bitIndex 位索引,范围 [0, 63] + * @throws 当位索引超出范围时抛出错误 + */ + static clearBit(mask, bitIndex) { + if (bitIndex < 0 || bitIndex >= 64) { + throw new Error(`Bit index ${bitIndex} out of range [0, 63]`); + } + if (bitIndex < 32) { + mask.lo &= ~(1 << bitIndex); + } else { + mask.hi &= ~(1 << bitIndex - 32); + } + } + /** + * 对目标掩码执行按位或操作 + * @param target 目标掩码(原地修改) + * @param other 用于按位或的掩码 + */ + static orInPlace(target, other) { + target.lo |= other.lo; + target.hi |= other.hi; + } + /** + * 对目标掩码执行按位与操作 + * @param target 目标掩码(原地修改) + * @param other 用于按位与的掩码 + */ + static andInPlace(target, other) { + target.lo &= other.lo; + target.hi &= other.hi; + } + /** + * 对目标掩码执行按位异或操作 + * @param target 目标掩码(原地修改) + * @param other 用于按位异或的掩码 + */ + static xorInPlace(target, other) { + target.lo ^= other.lo; + target.hi ^= other.hi; + } + /** + * 清除掩码的所有位为0 + * @param mask 要清除的掩码(原地修改) + */ + static clear(mask) { + mask.lo = 0; + mask.hi = 0; + } + /** + * 将源掩码的值复制到目标掩码 + * @param source 源掩码 + * @param target 目标掩码(原地修改) + */ + static copy(source, target) { + target.lo = source.lo; + target.hi = source.hi; + } + /** + * 创建掩码的深拷贝 + * @param mask 要拷贝的掩码 + * @returns 新的掩码对象,内容与源掩码相同 + */ + static clone(mask) { + return { lo: mask.lo, hi: mask.hi }; + } + /** + * 将掩码转换为字符串表示 + * @param mask 要转换的掩码 + * @param radix 进制,支持2(二进制)或16(十六进制),默认为2 + * @returns 掩码的字符串表示,二进制不带前缀,十六进制带0x前缀 + * @throws 当进制不支持时抛出错误 + */ + static toString(mask, radix = 2) { + if (radix === 2) { + if (mask.hi === 0) { + return mask.lo.toString(2); + } else { + const hiBits = mask.hi.toString(2); + const loBits = mask.lo.toString(2).padStart(32, "0"); + return hiBits + loBits; + } + } else if (radix === 16) { + if (mask.hi === 0) { + return "0x" + mask.lo.toString(16).toUpperCase(); + } else { + const hiBits = mask.hi.toString(16).toUpperCase(); + const loBits = mask.lo.toString(16).toUpperCase().padStart(8, "0"); + return "0x" + hiBits + loBits; + } + } else { + throw new Error("Only radix 2 and 16 are supported"); + } + } + /** + * 计算掩码中设置为1的位数 + * @param mask 要计算的掩码 + * @returns 掩码中1的位数 + */ + static popCount(mask) { + let count = 0; + let lo = mask.lo; + let hi = mask.hi; + while (lo) { + lo &= lo - 1; + count++; + } + while (hi) { + hi &= hi - 1; + count++; + } + return count; + } +} +BitMask64Utils.ZERO = { lo: 0, hi: 0 }; +var LogLevel; +(function(LogLevel2) { + LogLevel2[LogLevel2["Debug"] = 0] = "Debug"; + LogLevel2[LogLevel2["Info"] = 1] = "Info"; + LogLevel2[LogLevel2["Warn"] = 2] = "Warn"; + LogLevel2[LogLevel2["Error"] = 3] = "Error"; + LogLevel2[LogLevel2["Fatal"] = 4] = "Fatal"; + LogLevel2[LogLevel2["None"] = 5] = "None"; +})(LogLevel || (LogLevel = {})); +const Colors = { + // 基础颜色 + BLACK: "\x1B[30m", + RED: "\x1B[31m", + GREEN: "\x1B[32m", + YELLOW: "\x1B[33m", + BLUE: "\x1B[34m", + MAGENTA: "\x1B[35m", + CYAN: "\x1B[36m", + WHITE: "\x1B[37m", + // 亮色版本 + BRIGHT_BLACK: "\x1B[90m", + BRIGHT_RED: "\x1B[91m", + BRIGHT_GREEN: "\x1B[92m", + BRIGHT_YELLOW: "\x1B[93m", + BRIGHT_BLUE: "\x1B[94m", + BRIGHT_MAGENTA: "\x1B[95m", + BRIGHT_CYAN: "\x1B[96m", + BRIGHT_WHITE: "\x1B[97m", + // 特殊 + RESET: "\x1B[0m", + BOLD: "\x1B[1m", + UNDERLINE: "\x1B[4m" +}; +class ConsoleLogger { + constructor(config = {}) { + this._config = { + level: LogLevel.Info, + enableTimestamp: true, + enableColors: typeof window === "undefined", + ...config + }; + } + /** + * 输出调试级别日志 + * @param message 日志消息 + * @param args 附加参数 + */ + debug(message, ...args) { + this.log(LogLevel.Debug, message, ...args); + } + /** + * 输出信息级别日志 + * @param message 日志消息 + * @param args 附加参数 + */ + info(message, ...args) { + this.log(LogLevel.Info, message, ...args); + } + /** + * 输出警告级别日志 + * @param message 日志消息 + * @param args 附加参数 + */ + warn(message, ...args) { + this.log(LogLevel.Warn, message, ...args); + } + /** + * 输出错误级别日志 + * @param message 日志消息 + * @param args 附加参数 + */ + error(message, ...args) { + this.log(LogLevel.Error, message, ...args); + } + /** + * 输出致命错误级别日志 + * @param message 日志消息 + * @param args 附加参数 + */ + fatal(message, ...args) { + this.log(LogLevel.Fatal, message, ...args); + } + /** + * 设置日志级别 + * @param level 日志级别 + */ + setLevel(level) { + this._config.level = level; + } + /** + * 设置颜色配置 + * @param colors 颜色配置 + */ + setColors(colors) { + if (Object.keys(colors).length === 0) { + delete this._config.colors; + } else { + this._config.colors = { + ...this._config.colors, + ...colors + }; + } + } + /** + * 设置日志前缀 + * @param prefix 前缀字符串 + */ + setPrefix(prefix) { + this._config.prefix = prefix; + } + /** + * 内部日志输出方法 + * @param level 日志级别 + * @param message 日志消息 + * @param args 附加参数 + */ + log(level, message, ...args) { + if (level < this._config.level) { + return; + } + let formattedMessage = message; + if (this._config.enableTimestamp) { + const timestamp = (/* @__PURE__ */ new Date()).toISOString(); + formattedMessage = `[${timestamp}] ${formattedMessage}`; + } + if (this._config.prefix) { + formattedMessage = `[${this._config.prefix}] ${formattedMessage}`; + } + const levelName = LogLevel[level].toUpperCase(); + formattedMessage = `[${levelName}] ${formattedMessage}`; + if (this._config.output) { + this._config.output(level, formattedMessage); + } else { + this.outputToConsole(level, formattedMessage, ...args); + } + } + /** + * 输出到控制台 + * @param level 日志级别 + * @param message 格式化后的消息 + * @param args 附加参数 + */ + outputToConsole(level, message, ...args) { + const colors = this._config.enableColors ? this.getColors() : null; + switch (level) { + case LogLevel.Debug: + if (colors) { + console.debug(`${colors.debug}${message}${colors.reset}`, ...args); + } else { + console.debug(message, ...args); + } + break; + case LogLevel.Info: + if (colors) { + console.info(`${colors.info}${message}${colors.reset}`, ...args); + } else { + console.info(message, ...args); + } + break; + case LogLevel.Warn: + if (colors) { + console.warn(`${colors.warn}${message}${colors.reset}`, ...args); + } else { + console.warn(message, ...args); + } + break; + case LogLevel.Error: + if (colors) { + console.error(`${colors.error}${message}${colors.reset}`, ...args); + } else { + console.error(message, ...args); + } + break; + case LogLevel.Fatal: + if (colors) { + console.error(`${colors.fatal}${message}${colors.reset}`, ...args); + } else { + console.error(message, ...args); + } + break; + } + } + /** + * 获取控制台颜色配置 + * @returns 颜色配置对象 + */ + getColors() { + const defaultColors = { + debug: Colors.BRIGHT_BLACK, + // 灰色 + info: Colors.GREEN, + // 绿色 + warn: Colors.YELLOW, + // 黄色 + error: Colors.RED, + // 红色 + fatal: Colors.BRIGHT_RED, + // 亮红色 + reset: Colors.RESET + // 重置 + }; + return { + ...defaultColors, + ...this._config.colors + }; + } +} +class LoggerManager { + constructor() { + this._loggers = /* @__PURE__ */ new Map(); + this._defaultLevel = LogLevel.Info; + this._defaultLogger = new ConsoleLogger({ + level: this._defaultLevel + }); + } + /** + * 获取日志管理器实例 + * @returns 日志管理器实例 + */ + static getInstance() { + if (!LoggerManager._instance) { + LoggerManager._instance = new LoggerManager(); + } + return LoggerManager._instance; + } + /** + * 获取或创建日志器 + * @param name 日志器名称 + * @returns 日志器实例 + */ + getLogger(name) { + if (!name) { + return this._defaultLogger; + } + if (!this._loggers.has(name)) { + const logger2 = new ConsoleLogger({ + prefix: name, + level: this._defaultLevel + }); + this._loggers.set(name, logger2); + } + return this._loggers.get(name); + } + /** + * 设置日志器 + * @param name 日志器名称 + * @param logger 日志器实例 + */ + setLogger(name, logger2) { + this._loggers.set(name, logger2); + } + /** + * 设置全局日志级别 + * @param level 日志级别 + */ + setGlobalLevel(level) { + this._defaultLevel = level; + if (this._defaultLogger instanceof ConsoleLogger) { + this._defaultLogger.setLevel(level); + } + for (const logger2 of this._loggers.values()) { + if (logger2 instanceof ConsoleLogger) { + logger2.setLevel(level); + } + } + } + /** + * 创建子日志器 + * @param parentName 父日志器名称 + * @param childName 子日志器名称 + * @returns 子日志器实例 + */ + createChildLogger(parentName, childName) { + const fullName = `${parentName}.${childName}`; + return this.getLogger(fullName); + } + /** + * 设置全局颜色配置 + * @param colors 颜色配置 + */ + setGlobalColors(colors) { + if (this._defaultLogger instanceof ConsoleLogger) { + this._defaultLogger.setColors(colors); + } + for (const logger2 of this._loggers.values()) { + if (logger2 instanceof ConsoleLogger) { + logger2.setColors(colors); + } + } + } + /** + * 重置为默认颜色配置 + */ + resetColors() { + if (this._defaultLogger instanceof ConsoleLogger) { + this._defaultLogger.setColors({}); + } + for (const logger2 of this._loggers.values()) { + if (logger2 instanceof ConsoleLogger) { + logger2.setColors({}); + } + } + } +} +LoggerManager.getInstance().getLogger(); +function createLogger(name) { + return LoggerManager.getInstance().getLogger(name); +} +class SoAStorage { + constructor(componentType) { + this.fields = /* @__PURE__ */ new Map(); + this.stringFields = /* @__PURE__ */ new Map(); + this.serializedFields = /* @__PURE__ */ new Map(); + this.complexFields = /* @__PURE__ */ new Map(); + this.entityToIndex = /* @__PURE__ */ new Map(); + this.indexToEntity = []; + this.freeIndices = []; + this._size = 0; + this._capacity = 1e3; + this.type = componentType; + this.initializeFields(componentType); + } + initializeFields(componentType) { + const instance = new componentType(); + const highPrecisionFields = componentType.__highPrecisionFields || /* @__PURE__ */ new Set(); + const float64Fields = componentType.__float64Fields || /* @__PURE__ */ new Set(); + const float32Fields = componentType.__float32Fields || /* @__PURE__ */ new Set(); + const int32Fields = componentType.__int32Fields || /* @__PURE__ */ new Set(); + const serializeMapFields = componentType.__serializeMapFields || /* @__PURE__ */ new Set(); + const serializeSetFields = componentType.__serializeSetFields || /* @__PURE__ */ new Set(); + const serializeArrayFields = componentType.__serializeArrayFields || /* @__PURE__ */ new Set(); + for (const key in instance) { + if (instance.hasOwnProperty(key) && key !== "id") { + const value = instance[key]; + const type = typeof value; + if (type === "number") { + if (highPrecisionFields.has(key)) + ; + else if (float64Fields.has(key)) { + this.fields.set(key, new Float64Array(this._capacity)); + } else if (int32Fields.has(key)) { + this.fields.set(key, new Int32Array(this._capacity)); + } else if (float32Fields.has(key)) { + this.fields.set(key, new Float32Array(this._capacity)); + } else { + this.fields.set(key, new Float32Array(this._capacity)); + } + } else if (type === "boolean") { + this.fields.set(key, new Float32Array(this._capacity)); + } else if (type === "string") { + this.stringFields.set(key, new Array(this._capacity)); + } else if (type === "object" && value !== null) { + if (serializeMapFields.has(key) || serializeSetFields.has(key) || serializeArrayFields.has(key)) { + this.serializedFields.set(key, new Array(this._capacity)); + } + } + } + } + } + addComponent(entityId, component) { + if (this.entityToIndex.has(entityId)) { + const index2 = this.entityToIndex.get(entityId); + this.updateComponentAtIndex(index2, component); + return; + } + let index; + if (this.freeIndices.length > 0) { + index = this.freeIndices.pop(); + } else { + index = this._size; + if (index >= this._capacity) { + this.resize(this._capacity * 2); + } + } + this.entityToIndex.set(entityId, index); + this.indexToEntity[index] = entityId; + this.updateComponentAtIndex(index, component); + this._size++; + } + updateComponentAtIndex(index, component) { + const entityId = this.indexToEntity[index]; + const complexFieldMap = /* @__PURE__ */ new Map(); + const highPrecisionFields = this.type.__highPrecisionFields || /* @__PURE__ */ new Set(); + const serializeMapFields = this.type.__serializeMapFields || /* @__PURE__ */ new Set(); + const serializeSetFields = this.type.__serializeSetFields || /* @__PURE__ */ new Set(); + const serializeArrayFields = this.type.__serializeArrayFields || /* @__PURE__ */ new Set(); + const deepCopyFields = this.type.__deepCopyFields || /* @__PURE__ */ new Set(); + for (const key in component) { + if (component.hasOwnProperty(key) && key !== "id") { + const value = component[key]; + const type = typeof value; + if (type === "number") { + if (highPrecisionFields.has(key) || !this.fields.has(key)) { + complexFieldMap.set(key, value); + } else { + const array = this.fields.get(key); + array[index] = value; + } + } else if (type === "boolean" && this.fields.has(key)) { + const array = this.fields.get(key); + array[index] = value ? 1 : 0; + } else if (this.stringFields.has(key)) { + const stringArray = this.stringFields.get(key); + stringArray[index] = String(value); + } else if (this.serializedFields.has(key)) { + const serializedArray = this.serializedFields.get(key); + serializedArray[index] = this.serializeValue(value, key, serializeMapFields, serializeSetFields, serializeArrayFields); + } else { + if (deepCopyFields.has(key)) { + complexFieldMap.set(key, this.deepClone(value)); + } else { + complexFieldMap.set(key, value); + } + } + } + } + if (complexFieldMap.size > 0) { + this.complexFields.set(entityId, complexFieldMap); + } + } + /** + * 序列化值为JSON字符串 + */ + serializeValue(value, key, mapFields, setFields, arrayFields) { + try { + if (mapFields.has(key) && value instanceof Map) { + return JSON.stringify(Array.from(value.entries())); + } else if (setFields.has(key) && value instanceof Set) { + return JSON.stringify(Array.from(value)); + } else if (arrayFields.has(key) && Array.isArray(value)) { + return JSON.stringify(value); + } else { + return JSON.stringify(value); + } + } catch (error) { + SoAStorage._logger.warn(`SoA序列化字段 ${key} 失败:`, error); + return "{}"; + } + } + /** + * 反序列化JSON字符串为值 + */ + deserializeValue(serialized, key, mapFields, setFields, arrayFields) { + try { + const parsed = JSON.parse(serialized); + if (mapFields.has(key)) { + return new Map(parsed); + } else if (setFields.has(key)) { + return new Set(parsed); + } else if (arrayFields.has(key)) { + return parsed; + } else { + return parsed; + } + } catch (error) { + SoAStorage._logger.warn(`SoA反序列化字段 ${key} 失败:`, error); + return null; + } + } + /** + * 深拷贝对象 + */ + deepClone(obj) { + if (obj === null || typeof obj !== "object") { + return obj; + } + if (obj instanceof Date) { + return new Date(obj.getTime()); + } + if (obj instanceof Array) { + return obj.map((item) => this.deepClone(item)); + } + if (obj instanceof Map) { + const cloned2 = /* @__PURE__ */ new Map(); + for (const [key, value] of obj.entries()) { + cloned2.set(key, this.deepClone(value)); + } + return cloned2; + } + if (obj instanceof Set) { + const cloned2 = /* @__PURE__ */ new Set(); + for (const value of obj.values()) { + cloned2.add(this.deepClone(value)); + } + return cloned2; + } + const cloned = {}; + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + cloned[key] = this.deepClone(obj[key]); + } + } + return cloned; + } + getComponent(entityId) { + const index = this.entityToIndex.get(entityId); + if (index === void 0) { + return null; + } + const component = new this.type(); + const serializeMapFields = this.type.__serializeMapFields || /* @__PURE__ */ new Set(); + const serializeSetFields = this.type.__serializeSetFields || /* @__PURE__ */ new Set(); + const serializeArrayFields = this.type.__serializeArrayFields || /* @__PURE__ */ new Set(); + for (const [fieldName, array] of this.fields.entries()) { + const value = array[index]; + const fieldType = this.getFieldType(fieldName); + if (fieldType === "boolean") { + component[fieldName] = value === 1; + } else { + component[fieldName] = value; + } + } + for (const [fieldName, stringArray] of this.stringFields.entries()) { + component[fieldName] = stringArray[index]; + } + for (const [fieldName, serializedArray] of this.serializedFields.entries()) { + const serialized = serializedArray[index]; + if (serialized) { + component[fieldName] = this.deserializeValue(serialized, fieldName, serializeMapFields, serializeSetFields, serializeArrayFields); + } + } + const complexFieldMap = this.complexFields.get(entityId); + if (complexFieldMap) { + for (const [fieldName, value] of complexFieldMap.entries()) { + component[fieldName] = value; + } + } + return component; + } + getFieldType(fieldName) { + const tempInstance = new this.type(); + const value = tempInstance[fieldName]; + return typeof value; + } + hasComponent(entityId) { + return this.entityToIndex.has(entityId); + } + removeComponent(entityId) { + const index = this.entityToIndex.get(entityId); + if (index === void 0) { + return null; + } + const component = this.getComponent(entityId); + this.complexFields.delete(entityId); + this.entityToIndex.delete(entityId); + this.freeIndices.push(index); + this._size--; + return component; + } + resize(newCapacity) { + for (const [fieldName, oldArray] of this.fields.entries()) { + let newArray; + if (oldArray instanceof Float32Array) { + newArray = new Float32Array(newCapacity); + } else if (oldArray instanceof Float64Array) { + newArray = new Float64Array(newCapacity); + } else { + newArray = new Int32Array(newCapacity); + } + newArray.set(oldArray); + this.fields.set(fieldName, newArray); + } + for (const [fieldName, oldArray] of this.stringFields.entries()) { + const newArray = new Array(newCapacity); + for (let i = 0; i < oldArray.length; i++) { + newArray[i] = oldArray[i]; + } + this.stringFields.set(fieldName, newArray); + } + for (const [fieldName, oldArray] of this.serializedFields.entries()) { + const newArray = new Array(newCapacity); + for (let i = 0; i < oldArray.length; i++) { + newArray[i] = oldArray[i]; + } + this.serializedFields.set(fieldName, newArray); + } + this._capacity = newCapacity; + } + getActiveIndices() { + return Array.from(this.entityToIndex.values()); + } + getFieldArray(fieldName) { + return this.fields.get(fieldName) || null; + } + getTypedFieldArray(fieldName) { + return this.fields.get(String(fieldName)) || null; + } + getEntityIndex(entityId) { + return this.entityToIndex.get(entityId); + } + getEntityIdByIndex(index) { + return this.indexToEntity[index]; + } + size() { + return this._size; + } + clear() { + this.entityToIndex.clear(); + this.indexToEntity = []; + this.freeIndices = []; + this.complexFields.clear(); + this._size = 0; + for (const array of this.fields.values()) { + array.fill(0); + } + for (const stringArray of this.stringFields.values()) { + for (let i = 0; i < stringArray.length; i++) { + stringArray[i] = void 0; + } + } + for (const serializedArray of this.serializedFields.values()) { + for (let i = 0; i < serializedArray.length; i++) { + serializedArray[i] = void 0; + } + } + } + compact() { + if (this.freeIndices.length === 0) { + return; + } + const activeEntries = Array.from(this.entityToIndex.entries()).sort((a, b) => a[1] - b[1]); + const newEntityToIndex = /* @__PURE__ */ new Map(); + const newIndexToEntity = []; + for (let newIndex = 0; newIndex < activeEntries.length; newIndex++) { + const [entityId, oldIndex] = activeEntries[newIndex]; + newEntityToIndex.set(entityId, newIndex); + newIndexToEntity[newIndex] = entityId; + if (newIndex !== oldIndex) { + for (const [, array] of this.fields.entries()) { + array[newIndex] = array[oldIndex]; + } + for (const [, stringArray] of this.stringFields.entries()) { + stringArray[newIndex] = stringArray[oldIndex]; + } + for (const [, serializedArray] of this.serializedFields.entries()) { + serializedArray[newIndex] = serializedArray[oldIndex]; + } + } + } + this.entityToIndex = newEntityToIndex; + this.indexToEntity = newIndexToEntity; + this.freeIndices = []; + this._size = activeEntries.length; + } + getStats() { + let totalMemory = 0; + const fieldStats = /* @__PURE__ */ new Map(); + for (const [fieldName, array] of this.fields.entries()) { + let bytesPerElement; + let typeName; + if (array instanceof Float32Array) { + bytesPerElement = 4; + typeName = "float32"; + } else if (array instanceof Float64Array) { + bytesPerElement = 8; + typeName = "float64"; + } else { + bytesPerElement = 4; + typeName = "int32"; + } + const memory = array.length * bytesPerElement; + totalMemory += memory; + fieldStats.set(fieldName, { + size: this._size, + capacity: array.length, + type: typeName, + memory + }); + } + return { + size: this._size, + capacity: this._capacity, + usedSlots: this._size, + // 兼容原测试 + fragmentation: this.freeIndices.length / this._capacity, + memoryUsage: totalMemory, + fieldStats + }; + } + /** + * 执行向量化批量操作 + * @param operation 操作函数,接收字段数组和活跃索引 + */ + performVectorizedOperation(operation) { + const activeIndices = this.getActiveIndices(); + operation(this.fields, activeIndices); + } +} +SoAStorage._logger = createLogger("SoAStorage"); +const COMPONENT_TYPE_NAME = Symbol("ComponentTypeName"); +const SYSTEM_TYPE_NAME = Symbol("SystemTypeName"); +function ECSComponent(typeName) { + return function(target) { + if (!typeName || typeof typeName !== "string") { + throw new Error("ECSComponent装饰器必须提供有效的类型名称"); + } + target[COMPONENT_TYPE_NAME] = typeName; + return target; + }; +} +function ECSSystem(typeName) { + return function(target) { + if (!typeName || typeof typeName !== "string") { + throw new Error("ECSSystem装饰器必须提供有效的类型名称"); + } + target[SYSTEM_TYPE_NAME] = typeName; + return target; + }; +} +function getComponentTypeName(componentType) { + const decoratorName = componentType[COMPONENT_TYPE_NAME]; + if (decoratorName) { + return decoratorName; + } + return componentType.name || "UnknownComponent"; +} +function getSystemTypeName(systemType) { + const decoratorName = systemType[SYSTEM_TYPE_NAME]; + if (decoratorName) { + return decoratorName; + } + return systemType.name || "UnknownSystem"; +} +function getComponentInstanceTypeName(component) { + return getComponentTypeName(component.constructor); +} +function getSystemInstanceTypeName(system) { + return getSystemTypeName(system.constructor); +} +class ComponentRegistry { + /** + * 注册组件类型并分配位掩码 + * @param componentType 组件类型 + * @returns 分配的位索引 + */ + static register(componentType) { + const typeName = getComponentTypeName(componentType); + if (this.componentTypes.has(componentType)) { + const existingIndex = this.componentTypes.get(componentType); + return existingIndex; + } + if (this.nextBitIndex >= this.maxComponents) { + throw new Error(`Maximum number of component types (${this.maxComponents}) exceeded`); + } + const bitIndex = this.nextBitIndex++; + this.componentTypes.set(componentType, bitIndex); + this.componentNameToType.set(typeName, componentType); + this.componentNameToId.set(typeName, bitIndex); + return bitIndex; + } + /** + * 获取组件类型的位掩码 + * @param componentType 组件类型 + * @returns 位掩码 + */ + static getBitMask(componentType) { + const bitIndex = this.componentTypes.get(componentType); + if (bitIndex === void 0) { + const typeName = getComponentTypeName(componentType); + throw new Error(`Component type ${typeName} is not registered`); + } + return BitMask64Utils.create(bitIndex); + } + /** + * 获取组件类型的位索引 + * @param componentType 组件类型 + * @returns 位索引 + */ + static getBitIndex(componentType) { + const bitIndex = this.componentTypes.get(componentType); + if (bitIndex === void 0) { + const typeName = getComponentTypeName(componentType); + throw new Error(`Component type ${typeName} is not registered`); + } + return bitIndex; + } + /** + * 检查组件类型是否已注册 + * @param componentType 组件类型 + * @returns 是否已注册 + */ + static isRegistered(componentType) { + return this.componentTypes.has(componentType); + } + /** + * 通过名称获取组件类型 + * @param componentName 组件名称 + * @returns 组件类型构造函数 + */ + static getComponentType(componentName) { + return this.componentNameToType.get(componentName) || null; + } + /** + * 获取所有已注册的组件类型 + * @returns 组件类型映射 + */ + static getAllRegisteredTypes() { + return new Map(this.componentTypes); + } + /** + * 获取所有组件名称到类型的映射 + * @returns 名称到类型的映射 + */ + static getAllComponentNames() { + return new Map(this.componentNameToType); + } + /** + * 通过名称获取组件类型ID + * @param componentName 组件名称 + * @returns 组件类型ID + */ + static getComponentId(componentName) { + return this.componentNameToId.get(componentName); + } + /** + * 注册组件类型(通过名称) + * @param componentName 组件名称 + * @returns 分配的组件ID + */ + static registerComponentByName(componentName) { + if (this.componentNameToId.has(componentName)) { + return this.componentNameToId.get(componentName); + } + if (this.nextBitIndex >= this.maxComponents) { + throw new Error(`Maximum number of component types (${this.maxComponents}) exceeded`); + } + const bitIndex = this.nextBitIndex++; + this.componentNameToId.set(componentName, bitIndex); + return bitIndex; + } + /** + * 创建单个组件的掩码 + * @param componentName 组件名称 + * @returns 组件掩码 + */ + static createSingleComponentMask(componentName) { + const cacheKey = `single:${componentName}`; + if (this.maskCache.has(cacheKey)) { + return this.maskCache.get(cacheKey); + } + const componentId = this.getComponentId(componentName); + if (componentId === void 0) { + throw new Error(`Component type ${componentName} is not registered`); + } + const mask = BitMask64Utils.create(componentId); + this.maskCache.set(cacheKey, mask); + return mask; + } + /** + * 创建多个组件的掩码 + * @param componentNames 组件名称数组 + * @returns 组合掩码 + */ + static createComponentMask(componentNames) { + const sortedNames = [...componentNames].sort(); + const cacheKey = `multi:${sortedNames.join(",")}`; + if (this.maskCache.has(cacheKey)) { + return this.maskCache.get(cacheKey); + } + let mask = BitMask64Utils.clone(BitMask64Utils.ZERO); + for (const name of componentNames) { + const componentId = this.getComponentId(name); + if (componentId !== void 0) { + const componentMask = BitMask64Utils.create(componentId); + BitMask64Utils.orInPlace(mask, componentMask); + } + } + this.maskCache.set(cacheKey, mask); + return mask; + } + /** + * 清除掩码缓存 + */ + static clearMaskCache() { + this.maskCache.clear(); + } + /** + * 重置注册表(用于测试) + */ + static reset() { + this.componentTypes.clear(); + this.componentNameToType.clear(); + this.componentNameToId.clear(); + this.maskCache.clear(); + this.nextBitIndex = 0; + } +} +ComponentRegistry._logger = createLogger("ComponentStorage"); +ComponentRegistry.componentTypes = /* @__PURE__ */ new Map(); +ComponentRegistry.componentNameToType = /* @__PURE__ */ new Map(); +ComponentRegistry.componentNameToId = /* @__PURE__ */ new Map(); +ComponentRegistry.maskCache = /* @__PURE__ */ new Map(); +ComponentRegistry.nextBitIndex = 0; +ComponentRegistry.maxComponents = 64; +class ComponentStorage { + constructor(componentType) { + this.dense = []; + this.entityIds = []; + this.entityToIndex = /* @__PURE__ */ new Map(); + this.componentType = componentType; + if (!ComponentRegistry.isRegistered(componentType)) { + ComponentRegistry.register(componentType); + } + } + /** + * 添加组件 + * @param entityId 实体ID + * @param component 组件实例 + */ + addComponent(entityId, component) { + if (this.entityToIndex.has(entityId)) { + throw new Error(`Entity ${entityId} already has component ${getComponentTypeName(this.componentType)}`); + } + const index = this.dense.length; + this.dense.push(component); + this.entityIds.push(entityId); + this.entityToIndex.set(entityId, index); + } + /** + * 获取组件 + * @param entityId 实体ID + * @returns 组件实例或null + */ + getComponent(entityId) { + const index = this.entityToIndex.get(entityId); + return index !== void 0 ? this.dense[index] : null; + } + /** + * 检查实体是否有此组件 + * @param entityId 实体ID + * @returns 是否有组件 + */ + hasComponent(entityId) { + return this.entityToIndex.has(entityId); + } + /** + * 移除组件 + * @param entityId 实体ID + * @returns 被移除的组件或null + */ + removeComponent(entityId) { + const index = this.entityToIndex.get(entityId); + if (index === void 0) { + return null; + } + const component = this.dense[index]; + const lastIndex = this.dense.length - 1; + if (index !== lastIndex) { + const lastComponent = this.dense[lastIndex]; + const lastEntityId = this.entityIds[lastIndex]; + this.dense[index] = lastComponent; + this.entityIds[index] = lastEntityId; + this.entityToIndex.set(lastEntityId, index); + } + this.dense.pop(); + this.entityIds.pop(); + this.entityToIndex.delete(entityId); + return component; + } + /** + * 高效遍历所有组件 + * @param callback 回调函数 + */ + forEach(callback) { + for (let i = 0; i < this.dense.length; i++) { + callback(this.dense[i], this.entityIds[i], i); + } + } + /** + * 获取所有组件 + * @returns 组件数组 + */ + getDenseArray() { + return { + components: [...this.dense], + entityIds: [...this.entityIds] + }; + } + /** + * 清空所有组件 + */ + clear() { + this.dense.length = 0; + this.entityIds.length = 0; + this.entityToIndex.clear(); + } + /** + * 获取组件数量 + */ + get size() { + return this.dense.length; + } + /** + * 获取组件类型 + */ + get type() { + return this.componentType; + } + /** + * 获取存储统计信息 + */ + getStats() { + const totalSlots = this.dense.length; + const usedSlots = this.dense.length; + const freeSlots = 0; + const fragmentation = 0; + return { + totalSlots, + usedSlots, + freeSlots, + fragmentation + }; + } +} +class ComponentStorageManager { + constructor() { + this.storages = /* @__PURE__ */ new Map(); + } + /** + * 检查组件类型是否启用SoA存储 + * @param componentType 组件类型 + * @returns 是否为SoA存储 + */ + isSoAStorage(componentType) { + const storage = this.storages.get(componentType); + return storage instanceof SoAStorage; + } + /** + * 获取SoA存储器(类型安全) + * @param componentType 组件类型 + * @returns SoA存储器或null + */ + getSoAStorage(componentType) { + const storage = this.getStorage(componentType); + return storage instanceof SoAStorage ? storage : null; + } + /** + * 直接获取SoA字段数组(类型安全) + * @param componentType 组件类型 + * @param fieldName 字段名 + * @returns TypedArray或null + */ + getFieldArray(componentType, fieldName) { + const soaStorage = this.getSoAStorage(componentType); + return soaStorage ? soaStorage.getFieldArray(fieldName) : null; + } + /** + * 直接获取SoA字段数组(类型安全,带字段名检查) + * @param componentType 组件类型 + * @param fieldName 字段名(类型检查) + * @returns TypedArray或null + */ + getTypedFieldArray(componentType, fieldName) { + const soaStorage = this.getSoAStorage(componentType); + return soaStorage ? soaStorage.getTypedFieldArray(fieldName) : null; + } + /** + * 获取SoA存储的活跃索引 + * @param componentType 组件类型 + * @returns 活跃索引数组或空数组 + */ + getActiveIndices(componentType) { + const soaStorage = this.getSoAStorage(componentType); + return soaStorage ? soaStorage.getActiveIndices() : []; + } + /** + * 获取实体在SoA存储中的索引 + * @param componentType 组件类型 + * @param entityId 实体ID + * @returns 存储索引或undefined + */ + getEntityIndex(componentType, entityId) { + const soaStorage = this.getSoAStorage(componentType); + return soaStorage ? soaStorage.getEntityIndex(entityId) : void 0; + } + /** + * 根据索引获取实体ID + * @param componentType 组件类型 + * @param index 存储索引 + * @returns 实体ID或undefined + */ + getEntityIdByIndex(componentType, index) { + const soaStorage = this.getSoAStorage(componentType); + return soaStorage ? soaStorage.getEntityIdByIndex(index) : void 0; + } + /** + * 获取或创建组件存储器(默认原始存储) + * @param componentType 组件类型 + * @returns 组件存储器 + */ + getStorage(componentType) { + let storage = this.storages.get(componentType); + if (!storage) { + const enableSoA = componentType.__enableSoA; + if (enableSoA) { + storage = new SoAStorage(componentType); + ComponentStorageManager._logger.info(`为 ${getComponentTypeName(componentType)} 启用SoA优化(适用于大规模批量操作)`); + } else { + storage = new ComponentStorage(componentType); + } + this.storages.set(componentType, storage); + } + return storage; + } + /** + * 添加组件 + * @param entityId 实体ID + * @param component 组件实例 + */ + addComponent(entityId, component) { + const componentType = component.constructor; + const storage = this.getStorage(componentType); + storage.addComponent(entityId, component); + } + /** + * 获取组件 + * @param entityId 实体ID + * @param componentType 组件类型 + * @returns 组件实例或null + */ + getComponent(entityId, componentType) { + const storage = this.storages.get(componentType); + return storage ? storage.getComponent(entityId) : null; + } + /** + * 检查实体是否有组件 + * @param entityId 实体ID + * @param componentType 组件类型 + * @returns 是否有组件 + */ + hasComponent(entityId, componentType) { + const storage = this.storages.get(componentType); + return storage ? storage.hasComponent(entityId) : false; + } + /** + * 移除组件 + * @param entityId 实体ID + * @param componentType 组件类型 + * @returns 被移除的组件或null + */ + removeComponent(entityId, componentType) { + const storage = this.storages.get(componentType); + return storage ? storage.removeComponent(entityId) : null; + } + /** + * 移除实体的所有组件 + * @param entityId 实体ID + */ + removeAllComponents(entityId) { + for (const storage of this.storages.values()) { + storage.removeComponent(entityId); + } + } + /** + * 获取实体的组件位掩码 + * @param entityId 实体ID + * @returns 组件位掩码 + */ + getComponentMask(entityId) { + let mask = BitMask64Utils.clone(BitMask64Utils.ZERO); + for (const [componentType, storage] of this.storages.entries()) { + if (storage.hasComponent(entityId)) { + const componentMask = ComponentRegistry.getBitMask(componentType); + BitMask64Utils.orInPlace(mask, componentMask); + } + } + return mask; + } + /** + * 获取所有存储器的统计信息 + */ + getAllStats() { + const stats = /* @__PURE__ */ new Map(); + for (const [componentType, storage] of this.storages.entries()) { + const typeName = getComponentTypeName(componentType); + stats.set(typeName, storage.getStats()); + } + return stats; + } + /** + * 清空所有存储器 + */ + clear() { + for (const storage of this.storages.values()) { + storage.clear(); + } + this.storages.clear(); + } +} +ComponentStorageManager._logger = createLogger("ComponentStorage"); +class EntityComparer { + /** + * 比较两个实体 + * + * @param self - 第一个实体 + * @param other - 第二个实体 + * @returns 比较结果,负数表示self优先级更高,正数表示other优先级更高,0表示相等 + */ + compare(self2, other) { + let compare = self2.updateOrder - other.updateOrder; + if (compare == 0) + compare = self2.id - other.id; + return compare; + } +} +class Entity { + /** + * 通知Scene中的QuerySystem实体组件发生变动 + * + * @param entity 发生组件变动的实体 + */ + static notifyQuerySystems(entity) { + if (entity.scene && entity.scene.querySystem) { + entity.scene.querySystem.updateEntity(entity); + entity.scene.clearSystemEntityCaches(); + } + } + /** + * 构造函数 + * + * @param name - 实体名称 + * @param id - 实体唯一标识符 + */ + constructor(name, id) { + this.components = []; + this.scene = null; + this.updateInterval = 1; + this._isDestroyed = false; + this._parent = null; + this._children = []; + this._active = true; + this._tag = 0; + this._enabled = true; + this._updateOrder = 0; + this._componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO); + this._componentsByTypeId = []; + this._componentDenseIndexByTypeId = []; + this.name = name; + this.id = id; + } + /** + * 获取销毁状态 + * @returns 如果实体已被销毁则返回true + */ + get isDestroyed() { + return this._isDestroyed; + } + /** + * 获取父实体 + * @returns 父实体,如果没有父实体则返回null + */ + get parent() { + return this._parent; + } + /** + * 获取子实体数组的只读副本 + * + * @returns 子实体数组的副本 + */ + get children() { + return [...this._children]; + } + /** + * 获取子实体数量 + * + * @returns 子实体的数量 + */ + get childCount() { + return this._children.length; + } + /** + * 获取活跃状态 + * + * @returns 如果实体处于活跃状态则返回true + */ + get active() { + return this._active; + } + /** + * 设置活跃状态 + * + * 设置实体的活跃状态,会影响子实体的有效活跃状态。 + * + * @param value - 新的活跃状态 + */ + set active(value) { + if (this._active !== value) { + this._active = value; + this.onActiveChanged(); + } + } + /** + * 获取实体的有效活跃状态 + * + * 考虑父实体的活跃状态,只有当实体本身和所有父实体都处于活跃状态时才返回true。 + * + * @returns 有效的活跃状态 + */ + get activeInHierarchy() { + if (!this._active) + return false; + if (this._parent) + return this._parent.activeInHierarchy; + return true; + } + /** + * 获取实体标签 + * + * @returns 实体的数字标签 + */ + get tag() { + return this._tag; + } + /** + * 设置实体标签 + * + * @param value - 新的标签值 + */ + set tag(value) { + this._tag = value; + } + /** + * 获取启用状态 + * + * @returns 如果实体已启用则返回true + */ + get enabled() { + return this._enabled; + } + /** + * 设置启用状态 + * + * @param value - 新的启用状态 + */ + set enabled(value) { + this._enabled = value; + } + /** + * 获取更新顺序 + * + * @returns 实体的更新顺序值 + */ + get updateOrder() { + return this._updateOrder; + } + /** + * 设置更新顺序 + * + * @param value - 新的更新顺序值 + */ + set updateOrder(value) { + this._updateOrder = value; + } + /** + * 获取组件位掩码 + * + * @returns 实体的组件位掩码 + */ + get componentMask() { + return this._componentMask; + } + /** + * 创建并添加组件 + * + * @param componentType - 组件类型 + * @param args - 组件构造函数参数 + * @returns 创建的组件实例 + */ + createComponent(componentType, ...args) { + const component = new componentType(...args); + return this.addComponent(component); + } + /** + * 内部添加组件方法(不进行重复检查,用于初始化) + * + * @param component - 要添加的组件实例 + * @returns 添加的组件实例 + */ + addComponentInternal(component) { + const componentType = component.constructor; + if (!ComponentRegistry.isRegistered(componentType)) { + ComponentRegistry.register(componentType); + } + const typeId = ComponentRegistry.getBitIndex(componentType); + component.entity = this; + this._componentsByTypeId[typeId] = component; + const denseIndex = this.components.length; + this._componentDenseIndexByTypeId[typeId] = denseIndex; + this.components.push(component); + const componentMask = ComponentRegistry.getBitMask(componentType); + BitMask64Utils.orInPlace(this._componentMask, componentMask); + return component; + } + /** + * 添加组件到实体 + * + * @param component - 要添加的组件实例 + * @returns 添加的组件实例 + * @throws {Error} 如果组件类型已存在 + */ + addComponent(component) { + const componentType = component.constructor; + if (this.hasComponent(componentType)) { + throw new Error(`Entity ${this.name} already has component ${getComponentTypeName(componentType)}`); + } + this.addComponentInternal(component); + if (this.scene && this.scene.componentStorageManager) { + this.scene.componentStorageManager.addComponent(this.id, component); + } + component.onAddedToEntity(); + if (Entity.eventBus) { + Entity.eventBus.emitComponentAdded({ + timestamp: Date.now(), + source: "Entity", + entityId: this.id, + entityName: this.name, + entityTag: this.tag?.toString(), + componentType: getComponentTypeName(componentType), + component + }); + } + Entity.notifyQuerySystems(this); + return component; + } + /** + * 获取指定类型的组件 + * + * @param type - 组件类型 + * @returns 组件实例或null + */ + getComponent(type) { + if (!ComponentRegistry.isRegistered(type)) { + return null; + } + const mask = ComponentRegistry.getBitMask(type); + if (BitMask64Utils.hasNone(this._componentMask, mask)) { + return null; + } + const typeId = ComponentRegistry.getBitIndex(type); + const component = this._componentsByTypeId[typeId]; + if (component && component.constructor === type) { + return component; + } + if (this.scene && this.scene.componentStorageManager) { + const storageComponent = this.scene.componentStorageManager.getComponent(this.id, type); + if (storageComponent) { + this._componentsByTypeId[typeId] = storageComponent; + if (!this.components.includes(storageComponent)) { + const denseIndex = this.components.length; + this._componentDenseIndexByTypeId[typeId] = denseIndex; + this.components.push(storageComponent); + } + return storageComponent; + } + } + for (let i = 0; i < this.components.length; i++) { + const component2 = this.components[i]; + if (component2 instanceof type) { + this._componentsByTypeId[typeId] = component2; + this._componentDenseIndexByTypeId[typeId] = i; + return component2; + } + } + return null; + } + /** + * 检查实体是否有指定类型的组件 + * + * @param type - 组件类型 + * @returns 如果有该组件则返回true + */ + hasComponent(type) { + if (!ComponentRegistry.isRegistered(type)) { + return false; + } + const mask = ComponentRegistry.getBitMask(type); + return BitMask64Utils.hasAny(this._componentMask, mask); + } + /** + * 获取或创建指定类型的组件 + * + * @param type - 组件类型 + * @param args - 组件构造函数参数(仅在创建时使用) + * @returns 组件实例 + */ + getOrCreateComponent(type, ...args) { + let component = this.getComponent(type); + if (!component) { + component = this.createComponent(type, ...args); + } + return component; + } + /** + * 移除指定的组件 + * + * @param component - 要移除的组件实例 + */ + removeComponent(component) { + const componentType = component.constructor; + if (!ComponentRegistry.isRegistered(componentType)) { + return; + } + const typeId = ComponentRegistry.getBitIndex(componentType); + this._componentsByTypeId[typeId] = void 0; + BitMask64Utils.clearBit(this._componentMask, typeId); + const denseIndex = this._componentDenseIndexByTypeId[typeId]; + if (denseIndex !== void 0 && denseIndex < this.components.length) { + const lastIndex = this.components.length - 1; + if (denseIndex !== lastIndex) { + const lastComponent = this.components[lastIndex]; + this.components[denseIndex] = lastComponent; + const lastComponentType = lastComponent.constructor; + const lastTypeId = ComponentRegistry.getBitIndex(lastComponentType); + this._componentDenseIndexByTypeId[lastTypeId] = denseIndex; + } + this.components.pop(); + } + this._componentDenseIndexByTypeId[typeId] = -1; + if (this.scene && this.scene.componentStorageManager) { + this.scene.componentStorageManager.removeComponent(this.id, componentType); + } + if (component.onRemovedFromEntity) { + component.onRemovedFromEntity(); + } + if (Entity.eventBus) { + Entity.eventBus.emitComponentRemoved({ + timestamp: Date.now(), + source: "Entity", + entityId: this.id, + entityName: this.name, + entityTag: this.tag?.toString(), + componentType: getComponentTypeName(componentType), + component + }); + } + component.entity = null; + Entity.notifyQuerySystems(this); + } + /** + * 移除指定类型的组件 + * + * @param type - 组件类型 + * @returns 被移除的组件实例或null + */ + removeComponentByType(type) { + const component = this.getComponent(type); + if (component) { + this.removeComponent(component); + return component; + } + return null; + } + /** + * 移除所有组件 + */ + removeAllComponents() { + const componentsToRemove = [...this.components]; + this._componentsByTypeId.length = 0; + this._componentDenseIndexByTypeId.length = 0; + BitMask64Utils.clear(this._componentMask); + for (const component of componentsToRemove) { + const componentType = component.constructor; + if (this.scene && this.scene.componentStorageManager) { + this.scene.componentStorageManager.removeComponent(this.id, componentType); + } + component.onRemovedFromEntity(); + component.entity = null; + } + this.components.length = 0; + Entity.notifyQuerySystems(this); + } + /** + * 批量添加组件 + * + * @param components - 要添加的组件数组 + * @returns 添加的组件数组 + */ + addComponents(components) { + const addedComponents = []; + for (const component of components) { + try { + addedComponents.push(this.addComponent(component)); + } catch (error) { + Entity._logger.warn(`添加组件失败 ${getComponentInstanceTypeName(component)}:`, error); + } + } + return addedComponents; + } + /** + * 批量移除组件类型 + * + * @param componentTypes - 要移除的组件类型数组 + * @returns 被移除的组件数组 + */ + removeComponentsByTypes(componentTypes) { + const removedComponents = []; + for (const componentType of componentTypes) { + removedComponents.push(this.removeComponentByType(componentType)); + } + return removedComponents; + } + /** + * 获取所有指定类型的组件 + * + * @param type - 组件类型 + * @returns 组件实例数组 + */ + getComponents(type) { + const result = []; + for (const component of this.components) { + if (component instanceof type) { + result.push(component); + } + } + return result; + } + /** + * 添加子实体 + * + * @param child - 要添加的子实体 + * @returns 添加的子实体 + */ + addChild(child) { + if (child === this) { + throw new Error("Entity cannot be its own child"); + } + if (child._parent === this) { + return child; + } + if (child._parent) { + child._parent.removeChild(child); + } + child._parent = this; + this._children.push(child); + if (!child.scene && this.scene) { + child.scene = this.scene; + this.scene.addEntity(child); + } + return child; + } + /** + * 移除子实体 + * + * @param child - 要移除的子实体 + * @returns 是否成功移除 + */ + removeChild(child) { + const index = this._children.indexOf(child); + if (index === -1) { + return false; + } + this._children.splice(index, 1); + child._parent = null; + return true; + } + /** + * 移除所有子实体 + */ + removeAllChildren() { + const childrenToRemove = [...this._children]; + for (const child of childrenToRemove) { + this.removeChild(child); + } + } + /** + * 根据名称查找子实体 + * + * @param name - 子实体名称 + * @param recursive - 是否递归查找 + * @returns 找到的子实体或null + */ + findChild(name, recursive = false) { + for (const child of this._children) { + if (child.name === name) { + return child; + } + } + if (recursive) { + for (const child of this._children) { + const found = child.findChild(name, true); + if (found) { + return found; + } + } + } + return null; + } + /** + * 根据标签查找子实体 + * + * @param tag - 标签 + * @param recursive - 是否递归查找 + * @returns 找到的子实体数组 + */ + findChildrenByTag(tag, recursive = false) { + const result = []; + for (const child of this._children) { + if (child.tag === tag) { + result.push(child); + } + } + if (recursive) { + for (const child of this._children) { + result.push(...child.findChildrenByTag(tag, true)); + } + } + return result; + } + /** + * 获取根实体 + * + * @returns 层次结构的根实体 + */ + getRoot() { + let root = this; + while (root._parent) { + root = root._parent; + } + return root; + } + /** + * 检查是否是指定实体的祖先 + * + * @param entity - 要检查的实体 + * @returns 如果是祖先则返回true + */ + isAncestorOf(entity) { + let current = entity._parent; + while (current) { + if (current === this) { + return true; + } + current = current._parent; + } + return false; + } + /** + * 检查是否是指定实体的后代 + * + * @param entity - 要检查的实体 + * @returns 如果是后代则返回true + */ + isDescendantOf(entity) { + return entity.isAncestorOf(this); + } + /** + * 获取层次深度 + * + * @returns 在层次结构中的深度(根实体为0) + */ + getDepth() { + let depth = 0; + let current = this._parent; + while (current) { + depth++; + current = current._parent; + } + return depth; + } + /** + * 遍历所有子实体(深度优先) + * + * @param callback - 对每个子实体执行的回调函数 + * @param recursive - 是否递归遍历 + */ + forEachChild(callback, recursive = false) { + this._children.forEach((child, index) => { + callback(child, index); + if (recursive) { + child.forEachChild(callback, true); + } + }); + } + /** + * 活跃状态改变时的回调 + */ + onActiveChanged() { + for (const component of this.components) { + if ("onActiveChanged" in component && typeof component.onActiveChanged === "function") { + component.onActiveChanged(); + } + } + if (this.scene && this.scene.eventSystem) { + this.scene.eventSystem.emitSync("entity:activeChanged", { + entity: this, + active: this._active, + activeInHierarchy: this.activeInHierarchy + }); + } + } + /** + * 更新实体 + * + * 调用所有组件的更新方法,并更新子实体。 + */ + update() { + if (!this.activeInHierarchy || this._isDestroyed) { + return; + } + for (const component of this.components) { + if (component.enabled) { + component.update(); + } + } + for (const child of this._children) { + child.update(); + } + } + /** + * 销毁实体 + * + * 移除所有组件、子实体并标记为已销毁。 + */ + destroy() { + if (this._isDestroyed) { + return; + } + this._isDestroyed = true; + const childrenToDestroy = [...this._children]; + for (const child of childrenToDestroy) { + child.destroy(); + } + if (this._parent) { + this._parent.removeChild(this); + } + this.removeAllComponents(); + if (this.scene) { + if (this.scene.querySystem) { + this.scene.querySystem.removeEntity(this); + } + if (this.scene.entities) { + this.scene.entities.remove(this); + } + } + } + /** + * 比较实体 + * + * @param other - 另一个实体 + * @returns 比较结果 + */ + compareTo(other) { + return EntityComparer.prototype.compare(this, other); + } + /** + * 获取实体的字符串表示 + * + * @returns 实体的字符串描述 + */ + toString() { + return `Entity[${this.name}:${this.id}]`; + } + /** + * 获取实体的调试信息(包含组件缓存信息) + * + * @returns 包含实体详细信息的对象 + */ + getDebugInfo() { + return { + name: this.name, + id: this.id, + enabled: this._enabled, + active: this._active, + activeInHierarchy: this.activeInHierarchy, + destroyed: this._isDestroyed, + componentCount: this.components.length, + componentTypes: this.components.map((c) => getComponentInstanceTypeName(c)), + componentMask: BitMask64Utils.toString(this._componentMask, 2), + // 二进制表示 + parentId: this._parent?.id || null, + childCount: this._children.length, + childIds: this._children.map((c) => c.id), + depth: this.getDepth(), + indexMappingSize: this._componentsByTypeId.filter((c) => c !== void 0).length, + denseIndexMappingSize: this._componentDenseIndexByTypeId.filter((idx) => idx !== -1 && idx !== void 0).length + }; + } +} +Entity._logger = createLogger("Entity"); +Entity.entityComparer = new EntityComparer(); +Entity.eventBus = null; +class EntityBuilder { + constructor(scene, storageManager) { + this.scene = scene; + this.storageManager = storageManager; + this.entity = new Entity("", scene.identifierPool.checkOut()); + } + /** + * 设置实体名称 + * @param name 实体名称 + * @returns 实体构建器 + */ + named(name) { + this.entity.name = name; + return this; + } + /** + * 设置实体标签 + * @param tag 标签 + * @returns 实体构建器 + */ + tagged(tag) { + this.entity.tag = tag; + return this; + } + /** + * 添加组件 + * @param component 组件实例 + * @returns 实体构建器 + */ + with(component) { + this.entity.addComponent(component); + return this; + } + /** + * 添加多个组件 + * @param components 组件数组 + * @returns 实体构建器 + */ + withComponents(...components) { + for (const component of components) { + this.entity.addComponent(component); + } + return this; + } + /** + * 条件性添加组件 + * @param condition 条件 + * @param component 组件实例 + * @returns 实体构建器 + */ + withIf(condition, component) { + if (condition) { + this.entity.addComponent(component); + } + return this; + } + /** + * 使用工厂函数创建并添加组件 + * @param factory 组件工厂函数 + * @returns 实体构建器 + */ + withFactory(factory) { + const component = factory(); + this.entity.addComponent(component); + return this; + } + /** + * 配置组件属性 + * @param componentType 组件类型 + * @param configurator 配置函数 + * @returns 实体构建器 + */ + configure(componentType, configurator) { + const component = this.entity.getComponent(componentType); + if (component) { + configurator(component); + } + return this; + } + /** + * 设置实体为启用状态 + * @param enabled 是否启用 + * @returns 实体构建器 + */ + enabled(enabled = true) { + this.entity.enabled = enabled; + return this; + } + /** + * 设置实体为活跃状态 + * @param active 是否活跃 + * @returns 实体构建器 + */ + active(active = true) { + this.entity.active = active; + return this; + } + /** + * 添加子实体 + * @param childBuilder 子实体构建器 + * @returns 实体构建器 + */ + withChild(childBuilder) { + const child = childBuilder.build(); + this.entity.addChild(child); + return this; + } + /** + * 批量添加子实体 + * @param childBuilders 子实体构建器数组 + * @returns 实体构建器 + */ + withChildren(...childBuilders) { + for (const childBuilder of childBuilders) { + const child = childBuilder.build(); + this.entity.addChild(child); + } + return this; + } + /** + * 使用工厂函数创建子实体 + * @param childFactory 子实体工厂函数 + * @returns 实体构建器 + */ + withChildFactory(childFactory) { + const childBuilder = childFactory(this.entity); + const child = childBuilder.build(); + this.entity.addChild(child); + return this; + } + /** + * 条件性添加子实体 + * @param condition 条件 + * @param childBuilder 子实体构建器 + * @returns 实体构建器 + */ + withChildIf(condition, childBuilder) { + if (condition) { + const child = childBuilder.build(); + this.entity.addChild(child); + } + return this; + } + /** + * 构建并返回实体 + * @returns 构建的实体 + */ + build() { + return this.entity; + } + /** + * 构建实体并添加到场景 + * @returns 构建的实体 + */ + spawn() { + this.scene.addEntity(this.entity); + return this.entity; + } + /** + * 克隆当前构建器 + * @returns 新的实体构建器 + */ + clone() { + const newBuilder = new EntityBuilder(this.scene, this.storageManager); + newBuilder.entity = this.entity; + return newBuilder; + } +} +class EntityList { + get count() { + return this.buffer.length; + } + constructor(scene) { + this.buffer = []; + this._idToEntity = /* @__PURE__ */ new Map(); + this._nameToEntities = /* @__PURE__ */ new Map(); + this._entitiesToAdd = []; + this._entitiesToRemove = []; + this._isUpdating = false; + this._enableEntityDirectUpdate = false; + this._scene = scene; + } + /** + * 设置是否启用实体直接更新 + */ + setEnableEntityDirectUpdate(enabled) { + this._enableEntityDirectUpdate = enabled; + } + /** + * 添加实体(立即添加或延迟添加) + * @param entity 要添加的实体 + */ + add(entity) { + if (this._isUpdating) { + this._entitiesToAdd.push(entity); + } else { + this.addImmediate(entity); + } + } + /** + * 立即添加实体 + * @param entity 要添加的实体 + */ + addImmediate(entity) { + if (this._idToEntity.has(entity.id)) { + return; + } + this.buffer.push(entity); + this._idToEntity.set(entity.id, entity); + this.updateNameIndex(entity, true); + } + /** + * 移除实体(立即移除或延迟移除) + * @param entity 要移除的实体 + */ + remove(entity) { + if (this._isUpdating) { + this._entitiesToRemove.push(entity); + } else { + this.removeImmediate(entity); + } + } + /** + * 立即移除实体 + * @param entity 要移除的实体 + */ + removeImmediate(entity) { + const index = this.buffer.indexOf(entity); + if (index !== -1) { + this.buffer.splice(index, 1); + this._idToEntity.delete(entity.id); + this.updateNameIndex(entity, false); + if (this._scene && this._scene.identifierPool) { + this._scene.identifierPool.checkIn(entity.id); + } + } + } + /** + * 移除所有实体 + */ + removeAllEntities() { + const idsToRecycle = []; + for (let i = this.buffer.length - 1; i >= 0; i--) { + idsToRecycle.push(this.buffer[i].id); + this.buffer[i].destroy(); + } + if (this._scene && this._scene.identifierPool) { + for (const id of idsToRecycle) { + this._scene.identifierPool.checkIn(id); + } + } + this.buffer.length = 0; + this._idToEntity.clear(); + this._nameToEntities.clear(); + this._entitiesToAdd.length = 0; + this._entitiesToRemove.length = 0; + } + /** + * 更新实体列表,处理延迟操作 + */ + updateLists() { + if (this._entitiesToAdd.length > 0) { + for (const entity of this._entitiesToAdd) { + this.addImmediate(entity); + } + this._entitiesToAdd.length = 0; + } + if (this._entitiesToRemove.length > 0) { + for (const entity of this._entitiesToRemove) { + this.removeImmediate(entity); + } + this._entitiesToRemove.length = 0; + } + } + /** + * 更新实体列表和实体 + */ + update() { + this._isUpdating = true; + try { + if (this._enableEntityDirectUpdate) { + for (let i = 0; i < this.buffer.length; i++) { + const entity = this.buffer[i]; + if (entity.enabled && !entity.isDestroyed) { + entity.update(); + } + } + } + } finally { + this._isUpdating = false; + } + this.updateLists(); + } + /** + * 根据名称查找实体(使用索引,O(1)复杂度) + * @param name 实体名称 + * @returns 找到的第一个实体或null + */ + findEntity(name) { + const entities = this._nameToEntities.get(name); + return entities && entities.length > 0 ? entities[0] : null; + } + /** + * 根据名称查找所有实体 + * @param name 实体名称 + * @returns 找到的所有实体数组 + */ + findEntitiesByName(name) { + return this._nameToEntities.get(name) || []; + } + /** + * 根据ID查找实体(使用索引,O(1)复杂度) + * @param id 实体ID + * @returns 找到的实体或null + */ + findEntityById(id) { + return this._idToEntity.get(id) || null; + } + /** + * 根据标签查找实体 + * @param tag 标签 + * @returns 找到的所有实体数组 + */ + findEntitiesByTag(tag) { + const result = []; + for (const entity of this.buffer) { + if (entity.tag === tag) { + result.push(entity); + } + } + return result; + } + /** + * 根据组件类型查找实体 + * @param componentType 组件类型 + * @returns 找到的所有实体数组 + */ + findEntitiesWithComponent(componentType) { + const result = []; + for (const entity of this.buffer) { + if (entity.hasComponent(componentType)) { + result.push(entity); + } + } + return result; + } + /** + * 批量操作:对所有实体执行指定操作 + * @param action 要执行的操作 + */ + forEach(action) { + for (const entity of this.buffer) { + action(entity); + } + } + /** + * 批量操作:对符合条件的实体执行指定操作 + * @param predicate 筛选条件 + * @param action 要执行的操作 + */ + forEachWhere(predicate, action) { + for (const entity of this.buffer) { + if (predicate(entity)) { + action(entity); + } + } + } + /** + * 更新名称索引 + * @param entity 实体 + * @param isAdd 是否为添加操作 + */ + updateNameIndex(entity, isAdd) { + if (!entity.name) { + return; + } + if (isAdd) { + let entities = this._nameToEntities.get(entity.name); + if (!entities) { + entities = []; + this._nameToEntities.set(entity.name, entities); + } + entities.push(entity); + } else { + const entities = this._nameToEntities.get(entity.name); + if (entities) { + const index = entities.indexOf(entity); + if (index !== -1) { + entities.splice(index, 1); + if (entities.length === 0) { + this._nameToEntities.delete(entity.name); + } + } + } + } + } + /** + * 获取实体列表的统计信息 + * @returns 统计信息 + */ + getStats() { + let activeCount = 0; + for (const entity of this.buffer) { + if (entity.enabled && !entity.isDestroyed) { + activeCount++; + } + } + return { + totalEntities: this.buffer.length, + activeEntities: activeCount, + pendingAdd: this._entitiesToAdd.length, + pendingRemove: this._entitiesToRemove.length, + nameIndexSize: this._nameToEntities.size + }; + } +} +class EntityProcessorList { + constructor() { + this._processors = []; + this._isDirty = false; + } + /** + * 设置为脏状态,需要重新排序 + */ + setDirty() { + this._isDirty = true; + } + /** + * 添加实体处理器 + * @param processor 要添加的处理器 + */ + add(processor) { + this._processors.push(processor); + this.setDirty(); + } + /** + * 移除实体处理器 + * @param processor 要移除的处理器 + */ + remove(processor) { + const index = this._processors.indexOf(processor); + if (index !== -1) { + this._processors.splice(index, 1); + } + } + /** + * 获取指定类型的处理器 + * @param type 处理器类型 + */ + getProcessor(type) { + for (const processor of this._processors) { + if (processor instanceof type) { + return processor; + } + } + return null; + } + /** + * 开始处理 + * + * 对所有处理器进行排序以确保正确的执行顺序。 + */ + begin() { + this.sortProcessors(); + } + /** + * 结束处理 + */ + end() { + for (const processor of this._processors) { + try { + processor.reset(); + } catch (error) { + EntityProcessorList._logger.error(`Error in processor ${getSystemInstanceTypeName(processor)}:`, error); + } + } + this._isDirty = false; + this._processors.length = 0; + } + /** + * 更新所有处理器 + */ + update() { + this.sortProcessors(); + for (const processor of this._processors) { + try { + processor.update(); + } catch (error) { + EntityProcessorList._logger.error(`Error in processor ${getSystemInstanceTypeName(processor)}:`, error); + } + } + } + /** + * 后期更新所有处理器 + */ + lateUpdate() { + for (const processor of this._processors) { + processor.lateUpdate(); + } + } + /** + * 排序处理器 + */ + sortProcessors() { + if (this._isDirty) { + this._processors.sort((a, b) => a.updateOrder - b.updateOrder); + this._isDirty = false; + } + } + /** 获取处理器列表 */ + get processors() { + return this._processors; + } + /** 获取处理器数量 */ + get count() { + return this._processors.length; + } +} +EntityProcessorList._logger = createLogger("EntityProcessorList"); +class IdentifierPool { + /** + * 构造函数 + * + * @param recycleDelay 延迟回收时间(毫秒),默认为100ms + * @param expansionBlockSize 内存扩展块大小,默认为1024 + */ + constructor(recycleDelay = 100, expansionBlockSize = 1024) { + this._nextAvailableIndex = 0; + this._freeIndices = []; + this._generations = /* @__PURE__ */ new Map(); + this._pendingRecycle = []; + this._recycleDelay = 100; + this._stats = { + totalAllocated: 0, + totalRecycled: 0, + currentActive: 0, + memoryExpansions: 0 + }; + this._recycleDelay = recycleDelay; + this._expansionBlockSize = expansionBlockSize; + this._preAllocateGenerations(0, this._expansionBlockSize); + } + /** + * 获取一个可用的ID + * + * 返回一个32位ID,高16位为世代版本,低16位为索引。 + * + * @returns 新分配的实体ID + * @throws {Error} 当达到索引限制时抛出错误 + */ + checkOut() { + this._processDelayedRecycle(); + let index; + if (this._freeIndices.length > 0) { + index = this._freeIndices.pop(); + } else { + if (this._nextAvailableIndex > IdentifierPool.MAX_INDEX) { + throw new Error(`实体索引已达到框架设计限制 (${IdentifierPool.MAX_INDEX})。这意味着您已经分配了超过65535个不同的实体索引。这是16位索引设计的限制,考虑优化实体回收策略或升级到64位ID设计。`); + } + index = this._nextAvailableIndex++; + this._ensureGenerationCapacity(index); + } + const generation = this._generations.get(index) || 1; + this._stats.totalAllocated++; + this._stats.currentActive++; + return this._packId(index, generation); + } + /** + * 回收一个ID + * + * 验证ID的有效性后,将其加入延迟回收队列。 + * ID不会立即可重用,而是在延迟时间后才真正回收。 + * + * @param id 要回收的实体ID + * @returns 是否成功回收(ID是否有效且未被重复回收) + */ + checkIn(id) { + const index = this._unpackIndex(id); + const generation = this._unpackGeneration(id); + if (!this._isValidId(index, generation)) { + return false; + } + const alreadyPending = this._pendingRecycle.some((item) => item.index === index && item.generation === generation); + if (alreadyPending) { + return false; + } + this._pendingRecycle.push({ + index, + generation, + timestamp: Date.now() + }); + this._stats.currentActive--; + this._stats.totalRecycled++; + return true; + } + /** + * 验证ID是否有效 + * + * 检查ID的索引和世代版本是否匹配当前状态。 + * + * @param id 要验证的实体ID + * @returns ID是否有效 + */ + isValid(id) { + const index = this._unpackIndex(id); + const generation = this._unpackGeneration(id); + return this._isValidId(index, generation); + } + /** + * 获取统计信息 + * + * @returns 池的当前状态统计 + */ + getStats() { + let totalGeneration = 0; + let generationCount = 0; + for (const [index, generation] of this._generations) { + if (index < this._nextAvailableIndex) { + totalGeneration += generation; + generationCount++; + } + } + const averageGeneration = generationCount > 0 ? totalGeneration / generationCount : 1; + return { + totalAllocated: this._stats.totalAllocated, + totalRecycled: this._stats.totalRecycled, + currentActive: this._stats.currentActive, + currentlyFree: this._freeIndices.length, + pendingRecycle: this._pendingRecycle.length, + maxPossibleEntities: IdentifierPool.MAX_INDEX + 1, + maxUsedIndex: this._nextAvailableIndex - 1, + memoryUsage: this._calculateMemoryUsage(), + memoryExpansions: this._stats.memoryExpansions, + averageGeneration: Math.round(averageGeneration * 100) / 100, + generationStorageSize: this._generations.size + }; + } + /** + * 强制执行延迟回收处理 + * + * 在某些情况下可能需要立即处理延迟回收队列, + * 比如内存压力大或者需要精确的统计信息时。 + */ + forceProcessDelayedRecycle() { + this._processDelayedRecycle(true); + } + /** + * 清理过期的延迟回收项 + * + * 将超过延迟时间的回收项真正回收到空闲列表中。 + * + * @param forceAll 是否强制处理所有延迟回收项 + * @private + */ + _processDelayedRecycle(forceAll = false) { + if (this._pendingRecycle.length === 0) + return; + const now = Date.now(); + const readyToRecycle = []; + const stillPending = []; + for (const item of this._pendingRecycle) { + if (forceAll || now - item.timestamp >= this._recycleDelay) { + readyToRecycle.push(item); + } else { + stillPending.push(item); + } + } + for (const item of readyToRecycle) { + if (this._isValidId(item.index, item.generation)) { + let newGeneration = item.generation + 1; + if (newGeneration > IdentifierPool.MAX_GENERATION) { + newGeneration = 1; + } + this._generations.set(item.index, newGeneration); + this._freeIndices.push(item.index); + } + } + this._pendingRecycle = stillPending; + } + /** + * 预分配世代信息 + * + * @param startIndex 起始索引 + * @param count 分配数量 + * @private + */ + _preAllocateGenerations(startIndex, count) { + for (let i = 0; i < count; i++) { + const index = startIndex + i; + if (index <= IdentifierPool.MAX_INDEX) { + this._generations.set(index, 1); + } + } + this._stats.memoryExpansions++; + } + /** + * 确保指定索引的世代信息存在 + * + * @param index 索引 + * @private + */ + _ensureGenerationCapacity(index) { + if (!this._generations.has(index)) { + const expansionStart = Math.floor(index / this._expansionBlockSize) * this._expansionBlockSize; + this._preAllocateGenerations(expansionStart, this._expansionBlockSize); + } + } + /** + * 计算内存使用量 + * + * @returns 内存使用字节数 + * @private + */ + _calculateMemoryUsage() { + const generationMapSize = this._generations.size * 16; + const freeIndicesSize = this._freeIndices.length * 8; + const pendingRecycleSize = this._pendingRecycle.length * 32; + return generationMapSize + freeIndicesSize + pendingRecycleSize; + } + /** + * 打包索引和世代为32位ID + * + * @param index 索引(16位) + * @param generation 世代版本(16位) + * @returns 打包后的32位ID + * @private + */ + _packId(index, generation) { + return generation << 16 | index; + } + /** + * 从ID中解包索引 + * + * @param id 32位ID + * @returns 索引部分(16位) + * @private + */ + _unpackIndex(id) { + return id & 65535; + } + /** + * 从ID中解包世代版本 + * + * @param id 32位ID + * @returns 世代版本部分(16位) + * @private + */ + _unpackGeneration(id) { + return id >>> 16 & 65535; + } + /** + * 内部ID有效性检查 + * + * @param index 索引 + * @param generation 世代版本 + * @returns 是否有效 + * @private + */ + _isValidId(index, generation) { + if (index < 0 || index >= this._nextAvailableIndex) { + return false; + } + const currentGeneration = this._generations.get(index); + return currentGeneration !== void 0 && currentGeneration === generation; + } +} +IdentifierPool.MAX_INDEX = 65535; +IdentifierPool.MAX_GENERATION = 65535; +class SparseSet { + constructor() { + this._dense = []; + this._sparse = /* @__PURE__ */ new Map(); + } + /** + * 添加元素到集合 + * + * @param item 要添加的元素 + * @returns 是否成功添加(false表示元素已存在) + */ + add(item) { + if (this._sparse.has(item)) { + return false; + } + const index = this._dense.length; + this._dense.push(item); + this._sparse.set(item, index); + return true; + } + /** + * 从集合中移除元素 + * + * 使用swap-and-pop技术保持数组紧凑性: + * 1. 将要删除的元素与最后一个元素交换 + * 2. 删除最后一个元素 + * 3. 更新映射表 + * + * @param item 要移除的元素 + * @returns 是否成功移除(false表示元素不存在) + */ + remove(item) { + const index = this._sparse.get(item); + if (index === void 0) { + return false; + } + const lastIndex = this._dense.length - 1; + if (index !== lastIndex) { + const lastItem = this._dense[lastIndex]; + this._dense[index] = lastItem; + this._sparse.set(lastItem, index); + } + this._dense.pop(); + this._sparse.delete(item); + return true; + } + /** + * 检查元素是否存在于集合中 + * + * @param item 要检查的元素 + * @returns 元素是否存在 + */ + has(item) { + return this._sparse.has(item); + } + /** + * 获取元素在密集数组中的索引 + * + * @param item 要查询的元素 + * @returns 索引,如果元素不存在则返回undefined + */ + getIndex(item) { + return this._sparse.get(item); + } + /** + * 根据索引获取元素 + * + * @param index 索引 + * @returns 元素,如果索引无效则返回undefined + */ + getByIndex(index) { + return this._dense[index]; + } + /** + * 获取集合大小 + */ + get size() { + return this._dense.length; + } + /** + * 检查集合是否为空 + */ + get isEmpty() { + return this._dense.length === 0; + } + /** + * 遍历集合中的所有元素 + * + * 保证遍历顺序与添加顺序一致(除非中间有删除操作)。 + * 遍历性能优秀,因为数据在内存中连续存储。 + * + * @param callback 遍历回调函数 + */ + forEach(callback) { + for (let i = 0; i < this._dense.length; i++) { + callback(this._dense[i], i); + } + } + /** + * 映射集合中的所有元素 + * + * @param callback 映射回调函数 + * @returns 映射后的新数组 + */ + map(callback) { + const result = []; + for (let i = 0; i < this._dense.length; i++) { + result.push(callback(this._dense[i], i)); + } + return result; + } + /** + * 过滤集合中的元素 + * + * @param predicate 过滤条件 + * @returns 满足条件的元素数组 + */ + filter(predicate) { + const result = []; + for (let i = 0; i < this._dense.length; i++) { + if (predicate(this._dense[i], i)) { + result.push(this._dense[i]); + } + } + return result; + } + /** + * 查找第一个满足条件的元素 + * + * @param predicate 查找条件 + * @returns 找到的元素,如果没有则返回undefined + */ + find(predicate) { + for (let i = 0; i < this._dense.length; i++) { + if (predicate(this._dense[i], i)) { + return this._dense[i]; + } + } + return void 0; + } + /** + * 检查是否存在满足条件的元素 + * + * @param predicate 检查条件 + * @returns 是否存在满足条件的元素 + */ + some(predicate) { + for (let i = 0; i < this._dense.length; i++) { + if (predicate(this._dense[i], i)) { + return true; + } + } + return false; + } + /** + * 检查是否所有元素都满足条件 + * + * @param predicate 检查条件 + * @returns 是否所有元素都满足条件 + */ + every(predicate) { + for (let i = 0; i < this._dense.length; i++) { + if (!predicate(this._dense[i], i)) { + return false; + } + } + return true; + } + /** + * 获取密集数组的只读副本 + * + * 返回数组的浅拷贝,确保外部无法直接修改内部数据。 + */ + getDenseArray() { + return [...this._dense]; + } + /** + * 获取密集数组的直接引用(内部使用) + * + * 警告:直接修改返回的数组会破坏数据结构的完整性。 + * 仅在性能关键场景下使用,并确保不会修改数组内容。 + */ + getDenseArrayUnsafe() { + return this._dense; + } + /** + * 清空集合 + */ + clear() { + this._dense.length = 0; + this._sparse.clear(); + } + /** + * 转换为数组 + */ + toArray() { + return [...this._dense]; + } + /** + * 转换为Set + */ + toSet() { + return new Set(this._dense); + } + /** + * 获取内存使用统计信息 + */ + getMemoryStats() { + const denseArraySize = this._dense.length * 8; + const sparseMapSize = this._sparse.size * 16; + return { + denseArraySize, + sparseMapSize, + totalMemory: denseArraySize + sparseMapSize + }; + } + /** + * 验证数据结构的完整性 + * + * 调试用方法,检查内部数据结构是否一致。 + */ + validate() { + if (this._dense.length !== this._sparse.size) { + return false; + } + for (let i = 0; i < this._dense.length; i++) { + const item = this._dense[i]; + const mappedIndex = this._sparse.get(item); + if (mappedIndex !== i) { + return false; + } + } + for (const [item, index] of this._sparse) { + if (index >= this._dense.length || this._dense[index] !== item) { + return false; + } + } + return true; + } +} +class PoolableEntitySet extends Set { + constructor(...args) { + super(); + } + reset() { + this.clear(); + } +} +class ComponentSparseSet { + constructor() { + this._componentMasks = []; + this._componentToEntities = /* @__PURE__ */ new Map(); + this._entities = new SparseSet(); + } + /** + * 添加实体到组件索引 + * + * 分析实体的组件组成,生成位掩码,并更新所有相关索引。 + * + * @param entity 要添加的实体 + */ + addEntity(entity) { + if (this._entities.has(entity)) { + this.removeEntity(entity); + } + let componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO); + const entityComponents = /* @__PURE__ */ new Set(); + for (const component of entity.components) { + const componentType = component.constructor; + entityComponents.add(componentType); + if (!ComponentRegistry.isRegistered(componentType)) { + ComponentRegistry.register(componentType); + } + const bitMask = ComponentRegistry.getBitMask(componentType); + BitMask64Utils.orInPlace(componentMask, bitMask); + } + this._entities.add(entity); + const entityIndex = this._entities.getIndex(entity); + while (this._componentMasks.length <= entityIndex) { + this._componentMasks.push(BitMask64Utils.clone(BitMask64Utils.ZERO)); + } + this._componentMasks[entityIndex] = componentMask; + this.updateComponentMappings(entity, entityComponents, true); + } + /** + * 从组件索引中移除实体 + * + * 清理实体相关的所有索引数据,保持数据结构的紧凑性。 + * + * @param entity 要移除的实体 + */ + removeEntity(entity) { + const entityIndex = this._entities.getIndex(entity); + if (entityIndex === void 0) { + return; + } + const entityComponents = this.getEntityComponentTypes(entity); + this.updateComponentMappings(entity, entityComponents, false); + this._entities.remove(entity); + const lastIndex = this._componentMasks.length - 1; + if (entityIndex !== lastIndex) { + this._componentMasks[entityIndex] = this._componentMasks[lastIndex]; + } + this._componentMasks.pop(); + } + /** + * 查询包含指定组件的所有实体 + * + * @param componentType 组件类型 + * @returns 包含该组件的实体集合 + */ + queryByComponent(componentType) { + const entities = this._componentToEntities.get(componentType); + return entities ? new Set(entities) : /* @__PURE__ */ new Set(); + } + /** + * 多组件查询(AND操作) + * + * 查找同时包含所有指定组件的实体。 + * + * @param componentTypes 组件类型数组 + * @returns 满足条件的实体集合 + */ + queryMultipleAnd(componentTypes) { + if (componentTypes.length === 0) { + return /* @__PURE__ */ new Set(); + } + if (componentTypes.length === 1) { + return this.queryByComponent(componentTypes[0]); + } + let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO); + for (const componentType of componentTypes) { + if (!ComponentRegistry.isRegistered(componentType)) { + return /* @__PURE__ */ new Set(); + } + const bitMask = ComponentRegistry.getBitMask(componentType); + BitMask64Utils.orInPlace(targetMask, bitMask); + } + const result = ComponentSparseSet._entitySetPool.obtain(); + this._entities.forEach((entity, index) => { + const entityMask = this._componentMasks[index]; + if (BitMask64Utils.hasAll(entityMask, targetMask)) { + result.add(entity); + } + }); + return result; + } + /** + * 多组件查询(OR操作) + * + * 查找包含任意一个指定组件的实体。 + * + * @param componentTypes 组件类型数组 + * @returns 满足条件的实体集合 + */ + queryMultipleOr(componentTypes) { + if (componentTypes.length === 0) { + return /* @__PURE__ */ new Set(); + } + if (componentTypes.length === 1) { + return this.queryByComponent(componentTypes[0]); + } + let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO); + for (const componentType of componentTypes) { + if (ComponentRegistry.isRegistered(componentType)) { + const bitMask = ComponentRegistry.getBitMask(componentType); + BitMask64Utils.orInPlace(targetMask, bitMask); + } + } + if (BitMask64Utils.equals(targetMask, BitMask64Utils.ZERO)) { + return /* @__PURE__ */ new Set(); + } + const result = ComponentSparseSet._entitySetPool.obtain(); + this._entities.forEach((entity, index) => { + const entityMask = this._componentMasks[index]; + if (BitMask64Utils.hasAny(entityMask, targetMask)) { + result.add(entity); + } + }); + return result; + } + /** + * 检查实体是否包含指定组件 + * + * @param entity 实体 + * @param componentType 组件类型 + * @returns 是否包含该组件 + */ + hasComponent(entity, componentType) { + const entityIndex = this._entities.getIndex(entity); + if (entityIndex === void 0) { + return false; + } + if (!ComponentRegistry.isRegistered(componentType)) { + return false; + } + const entityMask = this._componentMasks[entityIndex]; + const componentMask = ComponentRegistry.getBitMask(componentType); + return BitMask64Utils.hasAny(entityMask, componentMask); + } + /** + * 获取实体的组件位掩码 + * + * @param entity 实体 + * @returns 组件位掩码,如果实体不存在则返回undefined + */ + getEntityMask(entity) { + const entityIndex = this._entities.getIndex(entity); + if (entityIndex === void 0) { + return void 0; + } + return this._componentMasks[entityIndex]; + } + /** + * 获取所有实体 + * + * @returns 所有实体的数组 + */ + getAllEntities() { + return this._entities.toArray(); + } + /** + * 获取实体数量 + */ + get size() { + return this._entities.size; + } + /** + * 检查是否为空 + */ + get isEmpty() { + return this._entities.isEmpty; + } + /** + * 遍历所有实体 + * + * @param callback 遍历回调函数 + */ + forEach(callback) { + this._entities.forEach((entity, index) => { + callback(entity, this._componentMasks[index], index); + }); + } + /** + * 清空所有数据 + */ + clear() { + this._entities.clear(); + this._componentMasks.length = 0; + for (const entitySet of this._componentToEntities.values()) { + ComponentSparseSet._entitySetPool.release(entitySet); + } + this._componentToEntities.clear(); + } + /** + * 获取内存使用统计 + */ + getMemoryStats() { + const entitiesStats = this._entities.getMemoryStats(); + const masksMemory = this._componentMasks.length * 16; + let mappingsMemory = this._componentToEntities.size * 16; + for (const entitySet of this._componentToEntities.values()) { + mappingsMemory += entitySet.size * 8; + } + return { + entitiesMemory: entitiesStats.totalMemory, + masksMemory, + mappingsMemory, + totalMemory: entitiesStats.totalMemory + masksMemory + mappingsMemory + }; + } + /** + * 验证数据结构完整性 + */ + validate() { + if (!this._entities.validate()) { + return false; + } + if (this._componentMasks.length !== this._entities.size) { + return false; + } + const allMappedEntities = /* @__PURE__ */ new Set(); + for (const entitySet of this._componentToEntities.values()) { + for (const entity of entitySet) { + allMappedEntities.add(entity); + } + } + for (const entity of allMappedEntities) { + if (!this._entities.has(entity)) { + return false; + } + } + return true; + } + /** + * 获取实体的组件类型集合 + */ + getEntityComponentTypes(entity) { + const componentTypes = /* @__PURE__ */ new Set(); + for (const component of entity.components) { + componentTypes.add(component.constructor); + } + return componentTypes; + } + /** + * 更新组件类型到实体的映射 + */ + updateComponentMappings(entity, componentTypes, add) { + for (const componentType of componentTypes) { + let entities = this._componentToEntities.get(componentType); + if (add) { + if (!entities) { + entities = ComponentSparseSet._entitySetPool.obtain(); + this._componentToEntities.set(componentType, entities); + } + entities.add(entity); + } else { + if (entities) { + entities.delete(entity); + if (entities.size === 0) { + this._componentToEntities.delete(componentType); + ComponentSparseSet._entitySetPool.release(entities); + } + } + } + } + } +} +ComponentSparseSet._entitySetPool = Pool.getPool(PoolableEntitySet, 50, 512); +class ComponentIndex { + constructor() { + this._queryCount = 0; + this._totalQueryTime = 0; + this._lastUpdated = Date.now(); + this._sparseSet = new ComponentSparseSet(); + } + addEntity(entity) { + this._sparseSet.addEntity(entity); + this._lastUpdated = Date.now(); + } + removeEntity(entity) { + this._sparseSet.removeEntity(entity); + this._lastUpdated = Date.now(); + } + query(componentType) { + const startTime = performance.now(); + const result = this._sparseSet.queryByComponent(componentType); + this._queryCount++; + this._totalQueryTime += performance.now() - startTime; + return result; + } + queryMultiple(componentTypes, operation) { + const startTime = performance.now(); + let result; + if (componentTypes.length === 0) { + result = /* @__PURE__ */ new Set(); + } else if (componentTypes.length === 1) { + result = this.query(componentTypes[0]); + } else if (operation === "AND") { + result = this._sparseSet.queryMultipleAnd(componentTypes); + } else { + result = this._sparseSet.queryMultipleOr(componentTypes); + } + this._queryCount++; + this._totalQueryTime += performance.now() - startTime; + return result; + } + clear() { + this._sparseSet.clear(); + this._lastUpdated = Date.now(); + } + getStats() { + const memoryStats = this._sparseSet.getMemoryStats(); + return { + size: this._sparseSet.size, + memoryUsage: memoryStats.totalMemory, + queryCount: this._queryCount, + avgQueryTime: this._queryCount > 0 ? this._totalQueryTime / this._queryCount : 0, + lastUpdated: this._lastUpdated + }; + } +} +class ComponentIndexManager { + constructor() { + this._index = new ComponentIndex(); + } + /** + * 添加实体到索引 + */ + addEntity(entity) { + this._index.addEntity(entity); + } + /** + * 从索引中移除实体 + */ + removeEntity(entity) { + this._index.removeEntity(entity); + } + /** + * 查询包含指定组件的实体 + */ + query(componentType) { + return this._index.query(componentType); + } + /** + * 批量查询多个组件 + */ + queryMultiple(componentTypes, operation) { + return this._index.queryMultiple(componentTypes, operation); + } + /** + * 获取索引统计信息 + */ + getStats() { + return this._index.getStats(); + } + /** + * 清空索引 + */ + clear() { + this._index.clear(); + } +} +class ArchetypeSystem { + constructor() { + this._archetypes = /* @__PURE__ */ new Map(); + this._entityToArchetype = /* @__PURE__ */ new Map(); + this._componentToArchetypes = /* @__PURE__ */ new Map(); + this._queryCache = /* @__PURE__ */ new Map(); + this._cacheTimeout = 5e3; + this._maxCacheSize = 100; + } + /** + * 添加实体到原型系统 + */ + addEntity(entity) { + const componentTypes = this.getEntityComponentTypes(entity); + const archetypeId = this.generateArchetypeId(componentTypes); + let archetype = this._archetypes.get(archetypeId); + if (!archetype) { + archetype = this.createArchetype(componentTypes); + } + archetype.entities.push(entity); + archetype.updatedAt = Date.now(); + this._entityToArchetype.set(entity, archetype); + this.updateComponentIndexes(archetype, componentTypes, true); + this.invalidateQueryCache(); + } + /** + * 从原型系统中移除实体 + */ + removeEntity(entity) { + const archetype = this._entityToArchetype.get(entity); + if (!archetype) + return; + const index = archetype.entities.indexOf(entity); + if (index !== -1) { + archetype.entities.splice(index, 1); + archetype.updatedAt = Date.now(); + } + this._entityToArchetype.delete(entity); + this.invalidateQueryCache(); + } + /** + * 更新实体的原型归属 + * + * 当实体的组件组合发生变化时调用此方法,将实体从旧原型移动到新原型。 + * 如果新的组件组合对应的原型不存在,将自动创建新原型。 + * + * @param entity 要更新的实体 + */ + updateEntity(entity) { + const currentArchetype = this._entityToArchetype.get(entity); + const newComponentTypes = this.getEntityComponentTypes(entity); + const newArchetypeId = this.generateArchetypeId(newComponentTypes); + if (currentArchetype && currentArchetype.id === newArchetypeId) { + return; + } + if (currentArchetype) { + const index = currentArchetype.entities.indexOf(entity); + if (index !== -1) { + currentArchetype.entities.splice(index, 1); + currentArchetype.updatedAt = Date.now(); + } + } + let newArchetype = this._archetypes.get(newArchetypeId); + if (!newArchetype) { + newArchetype = this.createArchetype(newComponentTypes); + } + newArchetype.entities.push(entity); + newArchetype.updatedAt = Date.now(); + this._entityToArchetype.set(entity, newArchetype); + if (currentArchetype) { + this.updateComponentIndexes(currentArchetype, currentArchetype.componentTypes, false); + } + this.updateComponentIndexes(newArchetype, newComponentTypes, true); + this.invalidateQueryCache(); + } + /** + * 查询包含指定组件组合的原型 + */ + queryArchetypes(componentTypes, operation = "AND") { + const startTime = performance.now(); + const cacheKey = `${operation}:${componentTypes.map((t) => getComponentTypeName(t)).sort().join(",")}`; + const cached = this._queryCache.get(cacheKey); + if (cached && Date.now() - cached.timestamp < this._cacheTimeout) { + return { + ...cached.result, + executionTime: performance.now() - startTime, + fromCache: true + }; + } + const matchingArchetypes = []; + let totalEntities = 0; + if (operation === "AND") { + for (const archetype of this._archetypes.values()) { + if (this.archetypeContainsAllComponents(archetype, componentTypes)) { + matchingArchetypes.push(archetype); + totalEntities += archetype.entities.length; + } + } + } else { + const foundArchetypes = /* @__PURE__ */ new Set(); + for (const componentType of componentTypes) { + const archetypes = this._componentToArchetypes.get(componentType); + if (archetypes) { + for (const archetype of archetypes) { + foundArchetypes.add(archetype); + } + } + } + for (const archetype of foundArchetypes) { + matchingArchetypes.push(archetype); + totalEntities += archetype.entities.length; + } + } + const result = { + archetypes: matchingArchetypes, + totalEntities, + executionTime: performance.now() - startTime, + fromCache: false + }; + this._queryCache.set(cacheKey, { + result, + timestamp: Date.now() + }); + return result; + } + /** + * 获取实体所属的原型 + */ + getEntityArchetype(entity) { + return this._entityToArchetype.get(entity); + } + /** + * 获取所有原型 + */ + getAllArchetypes() { + return Array.from(this._archetypes.values()); + } + /** + * 清空所有数据 + */ + clear() { + this._archetypes.clear(); + this._entityToArchetype.clear(); + this._componentToArchetypes.clear(); + this._queryCache.clear(); + } + /** + * 获取实体的组件类型列表 + */ + getEntityComponentTypes(entity) { + return entity.components.map((component) => component.constructor); + } + /** + * 生成原型ID + */ + generateArchetypeId(componentTypes) { + return componentTypes.map((type) => getComponentTypeName(type)).sort().join("|"); + } + /** + * 创建新原型 + */ + createArchetype(componentTypes) { + const id = this.generateArchetypeId(componentTypes); + const archetype = { + id, + componentTypes: [...componentTypes], + entities: [], + createdAt: Date.now(), + updatedAt: Date.now() + }; + this._archetypes.set(id, archetype); + return archetype; + } + /** + * 检查原型是否包含所有指定组件 + */ + archetypeContainsAllComponents(archetype, componentTypes) { + for (const componentType of componentTypes) { + if (!archetype.componentTypes.includes(componentType)) { + return false; + } + } + return true; + } + /** + * 更新组件索引 + */ + updateComponentIndexes(archetype, componentTypes, add) { + for (const componentType of componentTypes) { + let archetypes = this._componentToArchetypes.get(componentType); + if (!archetypes) { + archetypes = /* @__PURE__ */ new Set(); + this._componentToArchetypes.set(componentType, archetypes); + } + if (add) { + archetypes.add(archetype); + } else { + archetypes.delete(archetype); + if (archetypes.size === 0) { + this._componentToArchetypes.delete(componentType); + } + } + } + } + /** + * 使查询缓存失效 + */ + invalidateQueryCache() { + this._queryCache.clear(); + } +} +var QueryConditionType; +(function(QueryConditionType2) { + QueryConditionType2["ALL"] = "all"; + QueryConditionType2["ANY"] = "any"; + QueryConditionType2["NONE"] = "none"; +})(QueryConditionType || (QueryConditionType = {})); +class QuerySystem { + constructor() { + this._logger = createLogger("QuerySystem"); + this.entities = []; + this._version = 0; + this.queryCache = /* @__PURE__ */ new Map(); + this.cacheMaxSize = 1e3; + this.cacheTimeout = 5e3; + this.componentNameCache = /* @__PURE__ */ new WeakMap(); + this.cacheKeyCache = /* @__PURE__ */ new Map(); + this.componentMaskCache = /* @__PURE__ */ new Map(); + this.queryStats = { + totalQueries: 0, + cacheHits: 0, + indexHits: 0, + linearScans: 0, + archetypeHits: 0, + dirtyChecks: 0 + }; + this.entityIndex = { + byMask: /* @__PURE__ */ new Map(), + byComponentType: /* @__PURE__ */ new Map(), + byTag: /* @__PURE__ */ new Map(), + byName: /* @__PURE__ */ new Map() + }; + this.componentIndexManager = new ComponentIndexManager(); + this.archetypeSystem = new ArchetypeSystem(); + } + /** + * 设置实体列表并重建索引 + * + * 当实体集合发生大规模变化时调用此方法。 + * 系统将重新构建所有索引以确保查询性能。 + * + * @param entities 新的实体列表 + */ + setEntities(entities) { + this.entities = entities; + this.clearQueryCache(); + this.rebuildIndexes(); + } + /** + * 添加单个实体到查询系统 + * + * 将新实体添加到查询系统中,并自动更新相关索引。 + * 为了提高批量添加性能,可以延迟缓存清理。 + * + * @param entity 要添加的实体 + * @param deferCacheClear 是否延迟缓存清理(用于批量操作) + */ + addEntity(entity, deferCacheClear = false) { + if (!this.entities.includes(entity)) { + this.entities.push(entity); + this.addEntityToIndexes(entity); + this.componentIndexManager.addEntity(entity); + this.archetypeSystem.addEntity(entity); + if (!deferCacheClear) { + this.clearQueryCache(); + } + this._version++; + } + } + /** + * 批量添加实体 + * + * 高效地批量添加多个实体,减少缓存清理次数。 + * 使用Set来避免O(n)的重复检查。 + * + * @param entities 要添加的实体列表 + */ + addEntities(entities) { + if (entities.length === 0) + return; + const existingIds = new Set(this.entities.map((e) => e.id)); + let addedCount = 0; + for (const entity of entities) { + if (!existingIds.has(entity.id)) { + this.entities.push(entity); + this.addEntityToIndexes(entity); + this.componentIndexManager.addEntity(entity); + this.archetypeSystem.addEntity(entity); + existingIds.add(entity.id); + addedCount++; + } + } + if (addedCount > 0) { + this.clearQueryCache(); + } + } + /** + * 批量添加实体(无重复检查版本) + * + * 假设所有实体都是新的,跳过重复检查以获得最大性能。 + * 仅在确保没有重复实体时使用。 + * + * @param entities 要添加的实体列表 + */ + addEntitiesUnchecked(entities) { + if (entities.length === 0) + return; + for (const entity of entities) { + this.entities.push(entity); + } + for (const entity of entities) { + this.addEntityToIndexes(entity); + this.componentIndexManager.addEntity(entity); + this.archetypeSystem.addEntity(entity); + } + this.clearQueryCache(); + } + /** + * 从查询系统移除实体 + * + * 从查询系统中移除指定实体,并清理相关索引。 + * + * @param entity 要移除的实体 + */ + removeEntity(entity) { + const index = this.entities.indexOf(entity); + if (index !== -1) { + this.entities.splice(index, 1); + this.removeEntityFromIndexes(entity); + this.componentIndexManager.removeEntity(entity); + this.archetypeSystem.removeEntity(entity); + this.clearQueryCache(); + this._version++; + } + } + /** + * 更新实体在查询系统中的索引 + * + * 当实体的组件组合发生变化时调用此方法,高效地更新实体在查询系统中的索引。 + * + * @param entity 要更新的实体 + */ + updateEntity(entity) { + if (!this.entities.includes(entity)) { + this.addEntity(entity); + return; + } + this.removeEntityFromIndexes(entity); + this.archetypeSystem.updateEntity(entity); + this.componentIndexManager.removeEntity(entity); + this.componentIndexManager.addEntity(entity); + this.addEntityToIndexes(entity); + this.clearQueryCache(); + this._version++; + } + /** + * 将实体添加到各种索引中 + */ + addEntityToIndexes(entity) { + const mask = entity.componentMask; + const maskKey = mask.toString(); + const maskSet = this.entityIndex.byMask.get(maskKey) || this.createAndSetMaskIndex(maskKey); + maskSet.add(entity); + const components = entity.components; + for (let i = 0; i < components.length; i++) { + const componentType = components[i].constructor; + const typeSet = this.entityIndex.byComponentType.get(componentType) || this.createAndSetComponentIndex(componentType); + typeSet.add(entity); + } + const tag = entity.tag; + if (tag !== void 0) { + const tagSet = this.entityIndex.byTag.get(tag) || this.createAndSetTagIndex(tag); + tagSet.add(entity); + } + const name = entity.name; + if (name) { + const nameSet = this.entityIndex.byName.get(name) || this.createAndSetNameIndex(name); + nameSet.add(entity); + } + } + createAndSetMaskIndex(maskKey) { + const set = /* @__PURE__ */ new Set(); + this.entityIndex.byMask.set(maskKey, set); + return set; + } + createAndSetComponentIndex(componentType) { + const set = /* @__PURE__ */ new Set(); + this.entityIndex.byComponentType.set(componentType, set); + return set; + } + createAndSetTagIndex(tag) { + const set = /* @__PURE__ */ new Set(); + this.entityIndex.byTag.set(tag, set); + return set; + } + createAndSetNameIndex(name) { + const set = /* @__PURE__ */ new Set(); + this.entityIndex.byName.set(name, set); + return set; + } + /** + * 从各种索引中移除实体 + */ + removeEntityFromIndexes(entity) { + const mask = entity.componentMask; + const maskKey = mask.toString(); + const maskSet = this.entityIndex.byMask.get(maskKey); + if (maskSet) { + maskSet.delete(entity); + if (maskSet.size === 0) { + this.entityIndex.byMask.delete(maskKey); + } + } + for (const component of entity.components) { + const componentType = component.constructor; + const typeSet = this.entityIndex.byComponentType.get(componentType); + if (typeSet) { + typeSet.delete(entity); + if (typeSet.size === 0) { + this.entityIndex.byComponentType.delete(componentType); + } + } + } + if (entity.tag !== void 0) { + const tagSet = this.entityIndex.byTag.get(entity.tag); + if (tagSet) { + tagSet.delete(entity); + if (tagSet.size === 0) { + this.entityIndex.byTag.delete(entity.tag); + } + } + } + if (entity.name) { + const nameSet = this.entityIndex.byName.get(entity.name); + if (nameSet) { + nameSet.delete(entity); + if (nameSet.size === 0) { + this.entityIndex.byName.delete(entity.name); + } + } + } + } + /** + * 重建所有索引 + * + * 清空并重新构建所有查询索引。 + * 通常在大量实体变更后调用以确保索引一致性。 + */ + rebuildIndexes() { + this.entityIndex.byMask.clear(); + this.entityIndex.byComponentType.clear(); + this.entityIndex.byTag.clear(); + this.entityIndex.byName.clear(); + this.archetypeSystem.clear(); + this.componentIndexManager.clear(); + for (const entity of this.entities) { + this.addEntityToIndexes(entity); + this.componentIndexManager.addEntity(entity); + this.archetypeSystem.addEntity(entity); + } + } + /** + * 查询包含所有指定组件的实体 + * + * 返回同时包含所有指定组件类型的实体列表。 + * 系统会自动选择最高效的查询策略,包括索引查找和缓存机制。 + * + * @param componentTypes 要查询的组件类型列表 + * @returns 查询结果,包含匹配的实体和性能信息 + * + * @example + * ```typescript + * // 查询同时具有位置和速度组件的实体 + * const result = querySystem.queryAll(PositionComponent, VelocityComponent); + * logger.info(`找到 ${result.count} 个移动实体`); + * ``` + */ + queryAll(...componentTypes) { + const startTime = performance.now(); + this.queryStats.totalQueries++; + const cacheKey = this.generateCacheKey("all", componentTypes); + const cached = this.getFromCache(cacheKey); + if (cached) { + this.queryStats.cacheHits++; + return { + entities: cached, + count: cached.length, + executionTime: performance.now() - startTime, + fromCache: true + }; + } + let entities = []; + const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, "AND"); + if (archetypeResult.archetypes.length > 0) { + this.queryStats.archetypeHits++; + for (const archetype of archetypeResult.archetypes) { + entities.push(...archetype.entities); + } + } else { + try { + if (componentTypes.length === 1) { + this.queryStats.indexHits++; + const indexResult = this.componentIndexManager.query(componentTypes[0]); + entities = Array.from(indexResult); + } else { + const indexResult = this.componentIndexManager.queryMultiple(componentTypes, "AND"); + entities = Array.from(indexResult); + } + } catch (error) { + entities = []; + } + } + this.addToCache(cacheKey, entities); + return { + entities, + count: entities.length, + executionTime: performance.now() - startTime, + fromCache: false + }; + } + /** + * 多组件查询算法 + * + * 针对多组件查询场景的高效算法实现。 + * 通过选择最小的组件集合作为起点,减少需要检查的实体数量。 + * + * @param componentTypes 组件类型列表 + * @returns 匹配的实体列表 + */ + queryMultipleComponents(componentTypes) { + let smallestSet = null; + let smallestSize = Infinity; + for (const componentType of componentTypes) { + const set = this.entityIndex.byComponentType.get(componentType); + if (!set || set.size === 0) { + return []; + } + if (set.size < smallestSize) { + smallestSize = set.size; + smallestSet = set; + } + } + if (!smallestSet) { + return []; + } + const mask = this.createComponentMask(componentTypes); + const result = []; + for (const entity of smallestSet) { + if (BitMask64Utils.hasAll(entity.componentMask, mask)) { + result.push(entity); + } + } + return result; + } + /** + * 查询包含任意指定组件的实体 + * + * 返回包含任意一个指定组件类型的实体列表。 + * 使用集合合并算法确保高效的查询性能。 + * + * @param componentTypes 要查询的组件类型列表 + * @returns 查询结果,包含匹配的实体和性能信息 + * + * @example + * ```typescript + * // 查询具有武器或护甲组件的实体 + * const result = querySystem.queryAny(WeaponComponent, ArmorComponent); + * logger.info(`找到 ${result.count} 个装备实体`); + * ``` + */ + queryAny(...componentTypes) { + const startTime = performance.now(); + this.queryStats.totalQueries++; + const cacheKey = this.generateCacheKey("any", componentTypes); + const cached = this.getFromCache(cacheKey); + if (cached) { + this.queryStats.cacheHits++; + return { + entities: cached, + count: cached.length, + executionTime: performance.now() - startTime, + fromCache: true + }; + } + const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, "OR"); + let entities; + if (archetypeResult.archetypes.length > 0) { + this.queryStats.archetypeHits++; + entities = []; + for (const archetype of archetypeResult.archetypes) { + entities.push(...archetype.entities); + } + } else { + const indexResult = this.componentIndexManager.queryMultiple(componentTypes, "OR"); + entities = Array.from(indexResult); + } + this.addToCache(cacheKey, entities); + return { + entities, + count: entities.length, + executionTime: performance.now() - startTime, + fromCache: false + }; + } + /** + * 查询不包含任何指定组件的实体 + * + * 返回不包含任何指定组件类型的实体列表。 + * 适用于排除特定类型实体的查询场景。 + * + * @param componentTypes 要排除的组件类型列表 + * @returns 查询结果,包含匹配的实体和性能信息 + * + * @example + * ```typescript + * // 查询不具有AI和玩家控制组件的实体(如静态物体) + * const result = querySystem.queryNone(AIComponent, PlayerControlComponent); + * logger.info(`找到 ${result.count} 个静态实体`); + * ``` + */ + queryNone(...componentTypes) { + const startTime = performance.now(); + this.queryStats.totalQueries++; + const cacheKey = this.generateCacheKey("none", componentTypes); + const cached = this.getFromCache(cacheKey); + if (cached) { + this.queryStats.cacheHits++; + return { + entities: cached, + count: cached.length, + executionTime: performance.now() - startTime, + fromCache: true + }; + } + const mask = this.createComponentMask(componentTypes); + const entities = this.entities.filter((entity) => BitMask64Utils.hasNone(entity.componentMask, mask)); + this.addToCache(cacheKey, entities); + return { + entities, + count: entities.length, + executionTime: performance.now() - startTime, + fromCache: false + }; + } + /** + * 按标签查询实体 + * + * 返回具有指定标签的所有实体。 + * 标签查询使用专用索引,具有很高的查询性能。 + * + * @param tag 要查询的标签值 + * @returns 查询结果,包含匹配的实体和性能信息 + * + * @example + * ```typescript + * // 查询所有玩家实体 + * const players = querySystem.queryByTag(PLAYER_TAG); + * ``` + */ + queryByTag(tag) { + const startTime = performance.now(); + this.queryStats.totalQueries++; + const cacheKey = `tag:${tag}`; + const cached = this.getFromCache(cacheKey); + if (cached) { + this.queryStats.cacheHits++; + return { + entities: cached, + count: cached.length, + executionTime: performance.now() - startTime, + fromCache: true + }; + } + this.queryStats.indexHits++; + const entities = Array.from(this.entityIndex.byTag.get(tag) || []); + this.addToCache(cacheKey, entities); + return { + entities, + count: entities.length, + executionTime: performance.now() - startTime, + fromCache: false + }; + } + /** + * 按名称查询实体 + * + * 返回具有指定名称的所有实体。 + * 名称查询使用专用索引,适用于查找特定的命名实体。 + * + * @param name 要查询的实体名称 + * @returns 查询结果,包含匹配的实体和性能信息 + * + * @example + * ```typescript + * // 查找名为"Player"的实体 + * const player = querySystem.queryByName("Player"); + * ``` + */ + queryByName(name) { + const startTime = performance.now(); + this.queryStats.totalQueries++; + const cacheKey = `name:${name}`; + const cached = this.getFromCache(cacheKey); + if (cached) { + this.queryStats.cacheHits++; + return { + entities: cached, + count: cached.length, + executionTime: performance.now() - startTime, + fromCache: true + }; + } + this.queryStats.indexHits++; + const entities = Array.from(this.entityIndex.byName.get(name) || []); + this.addToCache(cacheKey, entities); + return { + entities, + count: entities.length, + executionTime: performance.now() - startTime, + fromCache: false + }; + } + /** + * 按单个组件类型查询实体 + * + * 返回包含指定组件类型的所有实体。 + * 这是最基础的查询方法,具有最高的查询性能。 + * + * @param componentType 要查询的组件类型 + * @returns 查询结果,包含匹配的实体和性能信息 + * + * @example + * ```typescript + * // 查询所有具有位置组件的实体 + * const entitiesWithPosition = querySystem.queryByComponent(PositionComponent); + * ``` + */ + queryByComponent(componentType) { + const startTime = performance.now(); + this.queryStats.totalQueries++; + const cacheKey = this.generateCacheKey("component", [componentType]); + const cached = this.getFromCache(cacheKey); + if (cached) { + this.queryStats.cacheHits++; + return { + entities: cached, + count: cached.length, + executionTime: performance.now() - startTime, + fromCache: true + }; + } + this.queryStats.indexHits++; + const entities = Array.from(this.entityIndex.byComponentType.get(componentType) || []); + this.addToCache(cacheKey, entities); + return { + entities, + count: entities.length, + executionTime: performance.now() - startTime, + fromCache: false + }; + } + /** + * 从缓存获取查询结果 + */ + getFromCache(cacheKey) { + const entry = this.queryCache.get(cacheKey); + if (!entry) + return null; + if (Date.now() - entry.timestamp > this.cacheTimeout || entry.version !== this._version) { + this.queryCache.delete(cacheKey); + return null; + } + entry.hitCount++; + return entry.entities; + } + /** + * 添加查询结果到缓存 + */ + addToCache(cacheKey, entities) { + if (this.queryCache.size >= this.cacheMaxSize) { + this.cleanupCache(); + } + this.queryCache.set(cacheKey, { + entities, + // 直接使用引用,通过版本号控制失效 + timestamp: Date.now(), + hitCount: 0, + version: this._version + }); + } + /** + * 清理缓存 + */ + cleanupCache() { + const now = Date.now(); + for (const [key, entry] of this.queryCache.entries()) { + if (now - entry.timestamp > this.cacheTimeout) { + this.queryCache.delete(key); + } + } + if (this.queryCache.size >= this.cacheMaxSize) { + let minHitCount = Infinity; + let oldestKey = ""; + let oldestTimestamp = Infinity; + for (const [key, entry] of this.queryCache.entries()) { + if (entry.hitCount < minHitCount || entry.hitCount === minHitCount && entry.timestamp < oldestTimestamp) { + minHitCount = entry.hitCount; + oldestKey = key; + oldestTimestamp = entry.timestamp; + } + } + if (oldestKey) { + this.queryCache.delete(oldestKey); + } + } + } + /** + * 清除所有查询缓存 + */ + clearQueryCache() { + this.queryCache.clear(); + this.cacheKeyCache.clear(); + this.componentMaskCache.clear(); + } + /** + * 高效的缓存键生成 + */ + generateCacheKey(prefix, componentTypes) { + if (componentTypes.length === 1) { + let name = this.componentNameCache.get(componentTypes[0]); + if (!name) { + name = getComponentTypeName(componentTypes[0]); + this.componentNameCache.set(componentTypes[0], name); + } + return `${prefix}:${name}`; + } + const sortKey = componentTypes.map((t) => { + let name = this.componentNameCache.get(t); + if (!name) { + name = getComponentTypeName(t); + this.componentNameCache.set(t, name); + } + return name; + }).sort().join(","); + const fullKey = `${prefix}:${sortKey}`; + let cachedKey = this.cacheKeyCache.get(fullKey); + if (!cachedKey) { + cachedKey = fullKey; + this.cacheKeyCache.set(fullKey, cachedKey); + } + return cachedKey; + } + /** + * 清理查询缓存 + * + * 用于外部调用清理缓存,通常在批量操作后使用。 + */ + clearCache() { + this.clearQueryCache(); + } + /** + * 创建组件掩码 + * + * 根据组件类型列表生成对应的位掩码。 + * 使用缓存避免重复计算。 + * + * @param componentTypes 组件类型列表 + * @returns 生成的位掩码 + */ + createComponentMask(componentTypes) { + const cacheKey = componentTypes.map((t) => { + let name = this.componentNameCache.get(t); + if (!name) { + name = getComponentTypeName(t); + this.componentNameCache.set(t, name); + } + return name; + }).sort().join(","); + const cached = this.componentMaskCache.get(cacheKey); + if (cached) { + return cached; + } + let mask = BitMask64Utils.clone(BitMask64Utils.ZERO); + let hasValidComponents = false; + for (const type of componentTypes) { + try { + const bitMask = ComponentRegistry.getBitMask(type); + BitMask64Utils.orInPlace(mask, bitMask); + hasValidComponents = true; + } catch (error) { + this._logger.warn(`组件类型 ${getComponentTypeName(type)} 未注册,跳过`); + } + } + if (!hasValidComponents) { + mask = { lo: 4294967295, hi: 4294967295 }; + } + this.componentMaskCache.set(cacheKey, mask); + return mask; + } + /** + * 获取当前版本号(用于缓存失效) + */ + get version() { + return this._version; + } + /** + * 获取所有实体 + */ + getAllEntities() { + return this.entities; + } + /** + * 获取系统统计信息 + * + * 返回查询系统的详细统计信息,包括实体数量、索引状态、 + * 查询性能统计等,用于性能监控和调试。 + * + * @returns 系统统计信息对象 + */ + getStats() { + return { + entityCount: this.entities.length, + indexStats: { + maskIndexSize: this.entityIndex.byMask.size, + componentIndexSize: this.entityIndex.byComponentType.size, + tagIndexSize: this.entityIndex.byTag.size, + nameIndexSize: this.entityIndex.byName.size + }, + queryStats: { + ...this.queryStats, + cacheHitRate: this.queryStats.totalQueries > 0 ? (this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + "%" : "0%" + }, + optimizationStats: { + componentIndex: this.componentIndexManager.getStats(), + archetypeSystem: this.archetypeSystem.getAllArchetypes().map((a) => ({ + id: a.id, + componentTypes: a.componentTypes.map((t) => getComponentTypeName(t)), + entityCount: a.entities.length + })) + }, + cacheStats: { + size: this.queryCache.size, + hitRate: this.queryStats.totalQueries > 0 ? (this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + "%" : "0%" + } + }; + } + /** + * 获取实体所属的原型信息 + * + * @param entity 要查询的实体 + */ + getEntityArchetype(entity) { + return this.archetypeSystem.getEntityArchetype(entity); + } +} +class QueryBuilder { + constructor(querySystem) { + this._logger = createLogger("QueryBuilder"); + this.conditions = []; + this.querySystem = querySystem; + } + /** + * 添加"必须包含所有组件"条件 + * + * @param componentTypes 必须包含的组件类型 + * @returns 查询构建器实例,支持链式调用 + */ + withAll(...componentTypes) { + this.conditions.push({ + type: QueryConditionType.ALL, + componentTypes, + mask: this.createComponentMask(componentTypes) + }); + return this; + } + /** + * 添加"必须包含任意组件"条件 + * + * @param componentTypes 必须包含其中任意一个的组件类型 + * @returns 查询构建器实例,支持链式调用 + */ + withAny(...componentTypes) { + this.conditions.push({ + type: QueryConditionType.ANY, + componentTypes, + mask: this.createComponentMask(componentTypes) + }); + return this; + } + /** + * 添加"不能包含任何组件"条件 + * + * @param componentTypes 不能包含的组件类型 + * @returns 查询构建器实例,支持链式调用 + */ + without(...componentTypes) { + this.conditions.push({ + type: QueryConditionType.NONE, + componentTypes, + mask: this.createComponentMask(componentTypes) + }); + return this; + } + /** + * 执行查询并返回结果 + * + * 根据已添加的查询条件执行实体查询。 + * + * @returns 查询结果,包含匹配的实体和性能信息 + */ + execute() { + const startTime = performance.now(); + if (this.conditions.length === 1) { + const condition = this.conditions[0]; + switch (condition.type) { + case QueryConditionType.ALL: + return this.querySystem.queryAll(...condition.componentTypes); + case QueryConditionType.ANY: + return this.querySystem.queryAny(...condition.componentTypes); + case QueryConditionType.NONE: + return this.querySystem.queryNone(...condition.componentTypes); + } + } + return { + entities: [], + count: 0, + executionTime: performance.now() - startTime, + fromCache: false + }; + } + /** + * 创建组件掩码 + */ + createComponentMask(componentTypes) { + let mask = BitMask64Utils.clone(BitMask64Utils.ZERO); + for (const type of componentTypes) { + try { + const bitMask = ComponentRegistry.getBitMask(type); + BitMask64Utils.orInPlace(mask, bitMask); + } catch (error) { + this._logger.warn(`组件类型 ${getComponentTypeName(type)} 未注册,跳过`); + } + } + return mask; + } + /** + * 重置查询构建器 + * + * 清除所有已添加的查询条件,重新开始构建查询。 + * + * @returns 查询构建器实例,支持链式调用 + */ + reset() { + this.conditions = []; + return this; + } +} +class TypeSafeEventSystem { + constructor() { + this.listeners = /* @__PURE__ */ new Map(); + this.stats = /* @__PURE__ */ new Map(); + this.batchQueue = /* @__PURE__ */ new Map(); + this.batchTimers = /* @__PURE__ */ new Map(); + this.batchConfigs = /* @__PURE__ */ new Map(); + this.nextListenerId = 0; + this.isEnabled = true; + this.maxListeners = 100; + } + /** + * 添加事件监听器 + * @param eventType 事件类型 + * @param handler 事件处理器 + * @param config 监听器配置 + * @returns 监听器ID(用于移除) + */ + on(eventType, handler, config = {}) { + return this.addListener(eventType, handler, config); + } + /** + * 添加一次性事件监听器 + * @param eventType 事件类型 + * @param handler 事件处理器 + * @param config 监听器配置 + * @returns 监听器ID + */ + once(eventType, handler, config = {}) { + return this.addListener(eventType, handler, { ...config, once: true }); + } + /** + * 添加异步事件监听器 + * @param eventType 事件类型 + * @param handler 异步事件处理器 + * @param config 监听器配置 + * @returns 监听器ID + */ + onAsync(eventType, handler, config = {}) { + return this.addListener(eventType, handler, { ...config, async: true }); + } + /** + * 移除事件监听器 + * @param eventType 事件类型 + * @param listenerId 监听器ID + * @returns 是否成功移除 + */ + off(eventType, listenerId) { + const listeners = this.listeners.get(eventType); + if (!listeners) + return false; + const index = listeners.findIndex((l) => l.id === listenerId); + if (index === -1) + return false; + listeners.splice(index, 1); + if (listeners.length === 0) { + this.listeners.delete(eventType); + this.stats.delete(eventType); + } + return true; + } + /** + * 移除指定事件类型的所有监听器 + * @param eventType 事件类型 + */ + offAll(eventType) { + this.listeners.delete(eventType); + this.stats.delete(eventType); + this.clearBatch(eventType); + } + /** + * 触发事件 + * @param eventType 事件类型 + * @param event 事件数据 + * @returns Promise(如果有异步监听器) + */ + async emit(eventType, event) { + if (!this.isEnabled) + return; + const batchConfig = this.batchConfigs.get(eventType); + if (batchConfig?.enabled) { + this.addToBatch(eventType, event); + return; + } + await this.executeEvent(eventType, event); + } + /** + * 同步触发事件(忽略异步监听器) + * @param eventType 事件类型 + * @param event 事件数据 + */ + emitSync(eventType, event) { + if (!this.isEnabled) + return; + const listeners = this.listeners.get(eventType); + if (!listeners || listeners.length === 0) + return; + const startTime = performance.now(); + const toRemove = []; + const sortedListeners = this.sortListenersByPriority(listeners); + for (const listener of sortedListeners) { + if (listener.config.async) + continue; + try { + if (listener.config.context) { + listener.handler.call(listener.config.context, event); + } else { + listener.handler(event); + } + if (listener.config.once) { + toRemove.push(listener.id); + } + } catch (error) { + TypeSafeEventSystem._logger.error(`事件处理器执行错误 ${eventType}:`, error); + } + } + this.removeListeners(eventType, toRemove); + this.updateStats(eventType, performance.now() - startTime); + } + /** + * 设置事件批处理配置 + * @param eventType 事件类型 + * @param config 批处理配置 + */ + setBatchConfig(eventType, config) { + this.batchConfigs.set(eventType, config); + } + /** + * 立即处理指定事件类型的批处理队列 + * @param eventType 事件类型 + */ + flushBatch(eventType) { + const batch = this.batchQueue.get(eventType); + if (!batch || batch.length === 0) + return; + const timer = this.batchTimers.get(eventType); + if (timer) { + clearTimeout(timer); + this.batchTimers.delete(eventType); + } + this.processBatch(eventType, batch); + this.batchQueue.delete(eventType); + } + /** + * 获取事件统计信息 + * @param eventType 事件类型(可选) + * @returns 统计信息 + */ + getStats(eventType) { + if (eventType) { + return this.stats.get(eventType) || this.createEmptyStats(eventType); + } + return new Map(this.stats); + } + /** + * 重置统计信息 + * @param eventType 事件类型(可选,不指定则重置所有) + */ + resetStats(eventType) { + if (eventType) { + this.stats.delete(eventType); + } else { + this.stats.clear(); + } + } + /** + * 启用/禁用事件系统 + * @param enabled 是否启用 + */ + setEnabled(enabled) { + this.isEnabled = enabled; + } + /** + * 检查是否有指定事件类型的监听器 + * @param eventType 事件类型 + * @returns 是否有监听器 + */ + hasListeners(eventType) { + const listeners = this.listeners.get(eventType); + return listeners ? listeners.length > 0 : false; + } + /** + * 获取指定事件类型的监听器数量 + * @param eventType 事件类型 + * @returns 监听器数量 + */ + getListenerCount(eventType) { + const listeners = this.listeners.get(eventType); + return listeners ? listeners.length : 0; + } + /** + * 清空所有事件监听器和数据 + */ + clear() { + this.listeners.clear(); + this.stats.clear(); + this.clearAllBatches(); + } + /** + * 设置每个事件类型的最大监听器数量 + * @param max 最大数量 + */ + setMaxListeners(max) { + this.maxListeners = max; + } + /** + * 添加监听器的内部实现 + * @param eventType 事件类型 + * @param handler 事件处理器 + * @param config 配置 + * @returns 监听器ID + */ + addListener(eventType, handler, config) { + let listeners = this.listeners.get(eventType); + if (!listeners) { + listeners = []; + this.listeners.set(eventType, listeners); + } + if (listeners.length >= this.maxListeners) { + TypeSafeEventSystem._logger.warn(`事件类型 ${eventType} 的监听器数量超过最大限制 (${this.maxListeners})`); + return ""; + } + const listenerId = `listener_${this.nextListenerId++}`; + const listener = { + handler, + config: { + priority: 0, + ...config + }, + id: listenerId + }; + listeners.push(listener); + if (!this.stats.has(eventType)) { + this.stats.set(eventType, this.createEmptyStats(eventType)); + } + return listenerId; + } + /** + * 执行事件的内部实现 + * @param eventType 事件类型 + * @param event 事件数据 + */ + async executeEvent(eventType, event) { + const listeners = this.listeners.get(eventType); + if (!listeners || listeners.length === 0) + return; + const startTime = performance.now(); + const toRemove = []; + const sortedListeners = this.sortListenersByPriority(listeners); + const syncListeners = sortedListeners.filter((l) => !l.config.async); + const asyncListeners = sortedListeners.filter((l) => l.config.async); + for (const listener of syncListeners) { + try { + if (listener.config.context) { + listener.handler.call(listener.config.context, event); + } else { + listener.handler(event); + } + if (listener.config.once) { + toRemove.push(listener.id); + } + } catch (error) { + TypeSafeEventSystem._logger.error(`同步事件处理器执行错误 ${eventType}:`, error); + } + } + const asyncPromises = asyncListeners.map(async (listener) => { + try { + if (listener.config.context) { + await listener.handler.call(listener.config.context, event); + } else { + await listener.handler(event); + } + if (listener.config.once) { + toRemove.push(listener.id); + } + } catch (error) { + TypeSafeEventSystem._logger.error(`异步事件处理器执行错误 ${eventType}:`, error); + } + }); + await Promise.all(asyncPromises); + this.removeListeners(eventType, toRemove); + this.updateStats(eventType, performance.now() - startTime); + } + /** + * 按优先级排序监听器 + * @param listeners 监听器数组 + * @returns 排序后的监听器数组 + */ + sortListenersByPriority(listeners) { + return listeners.slice().sort((a, b) => (b.config.priority || 0) - (a.config.priority || 0)); + } + /** + * 移除指定的监听器 + * @param eventType 事件类型 + * @param listenerIds 要移除的监听器ID数组 + */ + removeListeners(eventType, listenerIds) { + if (listenerIds.length === 0) + return; + const listeners = this.listeners.get(eventType); + if (!listeners) + return; + for (const id of listenerIds) { + const index = listeners.findIndex((l) => l.id === id); + if (index !== -1) { + listeners.splice(index, 1); + } + } + if (listeners.length === 0) { + this.listeners.delete(eventType); + this.stats.delete(eventType); + } + } + /** + * 添加事件到批处理队列 + * @param eventType 事件类型 + * @param event 事件数据 + */ + addToBatch(eventType, event) { + let batch = this.batchQueue.get(eventType); + if (!batch) { + batch = []; + this.batchQueue.set(eventType, batch); + } + batch.push(event); + const config = this.batchConfigs.get(eventType); + if (batch.length >= config.batchSize) { + this.flushBatch(eventType); + return; + } + if (!this.batchTimers.has(eventType)) { + const timer = setTimeout(() => { + this.flushBatch(eventType); + }, config.delay); + this.batchTimers.set(eventType, timer); + } + } + /** + * 处理批处理事件 + * @param eventType 事件类型 + * @param batch 批处理事件数组 + */ + async processBatch(eventType, batch) { + const batchEvent = { + type: eventType, + events: batch, + count: batch.length, + timestamp: Date.now() + }; + await this.executeEvent(`${eventType}:batch`, batchEvent); + } + /** + * 清除指定事件类型的批处理 + * @param eventType 事件类型 + */ + clearBatch(eventType) { + this.batchQueue.delete(eventType); + const timer = this.batchTimers.get(eventType); + if (timer) { + clearTimeout(timer); + this.batchTimers.delete(eventType); + } + } + /** + * 清除所有批处理 + */ + clearAllBatches() { + this.batchQueue.clear(); + for (const timer of this.batchTimers.values()) { + clearTimeout(timer); + } + this.batchTimers.clear(); + this.batchConfigs.clear(); + } + /** + * 更新事件统计信息 + * @param eventType 事件类型 + * @param executionTime 执行时间 + */ + updateStats(eventType, executionTime) { + let stats = this.stats.get(eventType); + if (!stats) { + stats = this.createEmptyStats(eventType); + this.stats.set(eventType, stats); + } + stats.triggerCount++; + stats.totalExecutionTime += executionTime; + stats.averageExecutionTime = stats.totalExecutionTime / stats.triggerCount; + stats.lastTriggerTime = Date.now(); + stats.listenerCount = this.getListenerCount(eventType); + } + /** + * 创建空的统计信息 + * @param eventType 事件类型 + * @returns 空的统计信息 + */ + createEmptyStats(eventType) { + return { + eventType, + listenerCount: 0, + triggerCount: 0, + totalExecutionTime: 0, + averageExecutionTime: 0, + lastTriggerTime: 0 + }; + } +} +TypeSafeEventSystem._logger = createLogger("EventSystem"); +var ECSEventType; +(function(ECSEventType2) { + ECSEventType2["ENTITY_CREATED"] = "entity:created"; + ECSEventType2["ENTITY_DESTROYED"] = "entity:destroyed"; + ECSEventType2["ENTITY_ENABLED"] = "entity:enabled"; + ECSEventType2["ENTITY_DISABLED"] = "entity:disabled"; + ECSEventType2["ENTITY_TAG_ADDED"] = "entity:tag:added"; + ECSEventType2["ENTITY_TAG_REMOVED"] = "entity:tag:removed"; + ECSEventType2["ENTITY_NAME_CHANGED"] = "entity:name:changed"; + ECSEventType2["COMPONENT_ADDED"] = "component:added"; + ECSEventType2["COMPONENT_REMOVED"] = "component:removed"; + ECSEventType2["COMPONENT_MODIFIED"] = "component:modified"; + ECSEventType2["COMPONENT_ENABLED"] = "component:enabled"; + ECSEventType2["COMPONENT_DISABLED"] = "component:disabled"; + ECSEventType2["SYSTEM_ADDED"] = "system:added"; + ECSEventType2["SYSTEM_REMOVED"] = "system:removed"; + ECSEventType2["SYSTEM_ENABLED"] = "system:enabled"; + ECSEventType2["SYSTEM_DISABLED"] = "system:disabled"; + ECSEventType2["SYSTEM_PROCESSING_START"] = "system:processing:start"; + ECSEventType2["SYSTEM_PROCESSING_END"] = "system:processing:end"; + ECSEventType2["SYSTEM_ERROR"] = "system:error"; + ECSEventType2["SCENE_CREATED"] = "scene:created"; + ECSEventType2["SCENE_DESTROYED"] = "scene:destroyed"; + ECSEventType2["SCENE_ACTIVATED"] = "scene:activated"; + ECSEventType2["SCENE_DEACTIVATED"] = "scene:deactivated"; + ECSEventType2["SCENE_PAUSED"] = "scene:paused"; + ECSEventType2["SCENE_RESUMED"] = "scene:resumed"; + ECSEventType2["QUERY_EXECUTED"] = "query:executed"; + ECSEventType2["QUERY_CACHE_HIT"] = "query:cache:hit"; + ECSEventType2["QUERY_CACHE_MISS"] = "query:cache:miss"; + ECSEventType2["QUERY_OPTIMIZED"] = "query:optimized"; + ECSEventType2["PERFORMANCE_WARNING"] = "performance:warning"; + ECSEventType2["PERFORMANCE_CRITICAL"] = "performance:critical"; + ECSEventType2["MEMORY_USAGE_HIGH"] = "memory:usage:high"; + ECSEventType2["FRAME_RATE_DROP"] = "frame:rate:drop"; + ECSEventType2["INDEX_CREATED"] = "index:created"; + ECSEventType2["INDEX_UPDATED"] = "index:updated"; + ECSEventType2["INDEX_OPTIMIZED"] = "index:optimized"; + ECSEventType2["ARCHETYPE_CREATED"] = "archetype:created"; + ECSEventType2["ARCHETYPE_ENTITY_ADDED"] = "archetype:entity:added"; + ECSEventType2["ARCHETYPE_ENTITY_REMOVED"] = "archetype:entity:removed"; + ECSEventType2["DIRTY_MARK_ADDED"] = "dirty:mark:added"; + ECSEventType2["DIRTY_BATCH_PROCESSED"] = "dirty:batch:processed"; + ECSEventType2["ERROR_OCCURRED"] = "error:occurred"; + ECSEventType2["WARNING_ISSUED"] = "warning:issued"; + ECSEventType2["FRAMEWORK_INITIALIZED"] = "framework:initialized"; + ECSEventType2["FRAMEWORK_SHUTDOWN"] = "framework:shutdown"; + ECSEventType2["DEBUG_INFO"] = "debug:info"; + ECSEventType2["DEBUG_STATS_UPDATED"] = "debug:stats:updated"; +})(ECSEventType || (ECSEventType = {})); +var EventPriority; +(function(EventPriority2) { + EventPriority2[EventPriority2["LOWEST"] = 0] = "LOWEST"; + EventPriority2[EventPriority2["LOW"] = 25] = "LOW"; + EventPriority2[EventPriority2["NORMAL"] = 50] = "NORMAL"; + EventPriority2[EventPriority2["HIGH"] = 75] = "HIGH"; + EventPriority2[EventPriority2["HIGHEST"] = 100] = "HIGHEST"; + EventPriority2[EventPriority2["CRITICAL"] = 200] = "CRITICAL"; +})(EventPriority || (EventPriority = {})); +const EVENT_TYPES = { + // 实体事件 + ENTITY: { + CREATED: ECSEventType.ENTITY_CREATED, + DESTROYED: ECSEventType.ENTITY_DESTROYED, + ENABLED: ECSEventType.ENTITY_ENABLED, + DISABLED: ECSEventType.ENTITY_DISABLED, + TAG_ADDED: ECSEventType.ENTITY_TAG_ADDED, + TAG_REMOVED: ECSEventType.ENTITY_TAG_REMOVED, + NAME_CHANGED: ECSEventType.ENTITY_NAME_CHANGED + }, + // 组件事件 + COMPONENT: { + ADDED: ECSEventType.COMPONENT_ADDED, + REMOVED: ECSEventType.COMPONENT_REMOVED, + MODIFIED: ECSEventType.COMPONENT_MODIFIED, + ENABLED: ECSEventType.COMPONENT_ENABLED, + DISABLED: ECSEventType.COMPONENT_DISABLED + }, + // 系统事件 + SYSTEM: { + ADDED: ECSEventType.SYSTEM_ADDED, + REMOVED: ECSEventType.SYSTEM_REMOVED, + ENABLED: ECSEventType.SYSTEM_ENABLED, + DISABLED: ECSEventType.SYSTEM_DISABLED, + PROCESSING_START: ECSEventType.SYSTEM_PROCESSING_START, + PROCESSING_END: ECSEventType.SYSTEM_PROCESSING_END, + ERROR: ECSEventType.SYSTEM_ERROR + }, + // 性能事件 + PERFORMANCE: { + WARNING: ECSEventType.PERFORMANCE_WARNING, + CRITICAL: ECSEventType.PERFORMANCE_CRITICAL, + MEMORY_HIGH: ECSEventType.MEMORY_USAGE_HIGH, + FRAME_DROP: ECSEventType.FRAME_RATE_DROP + } +}; +class EventTypeValidator { + /** + * 验证事件类型是否有效 + * @param eventType 事件类型 + * @returns 是否有效 + */ + static isValid(eventType) { + return this.validTypes.has(eventType); + } + /** + * 获取所有有效的事件类型 + * @returns 事件类型数组 + */ + static getAllValidTypes() { + return Array.from(this.validTypes); + } + /** + * 添加自定义事件类型 + * @param eventType 事件类型 + */ + static addCustomType(eventType) { + this.validTypes.add(eventType); + } + /** + * 移除自定义事件类型 + * @param eventType 事件类型 + */ + static removeCustomType(eventType) { + this.validTypes.delete(eventType); + } +} +EventTypeValidator.validTypes = /* @__PURE__ */ new Set([ + ...Object.values(ECSEventType), + ...Object.values(EVENT_TYPES.ENTITY), + ...Object.values(EVENT_TYPES.COMPONENT), + ...Object.values(EVENT_TYPES.SYSTEM), + ...Object.values(EVENT_TYPES.PERFORMANCE) +]); +class EventBus { + constructor(debugMode = false) { + this.eventIdCounter = 0; + this.isDebugMode = false; + this.eventSystem = new TypeSafeEventSystem(); + this.isDebugMode = debugMode; + } + /** + * 发射事件 + * @param eventType 事件类型 + * @param data 事件数据 + * @param enhance 是否增强事件数据(添加timestamp、eventId等),默认false提升性能 + */ + emit(eventType, data, enhance = false) { + this.validateEventType(eventType); + const finalData = enhance ? this.enhanceEventData(eventType, data) : data; + if (this.isDebugMode) { + EventBus._logger.info(`发射事件: ${eventType}`, finalData); + } + this.eventSystem.emitSync(eventType, finalData); + } + /** + * 异步发射事件 + * @param eventType 事件类型 + * @param data 事件数据 + * @param enhance 是否增强事件数据(添加timestamp、eventId等),默认false提升性能 + */ + async emitAsync(eventType, data, enhance = false) { + this.validateEventType(eventType); + const finalData = enhance ? this.enhanceEventData(eventType, data) : data; + if (this.isDebugMode) { + EventBus._logger.info(`发射异步事件: ${eventType}`, finalData); + } + await this.eventSystem.emit(eventType, finalData); + } + /** + * 监听事件 + * @param eventType 事件类型 + * @param handler 事件处理器 + * @param config 监听器配置 + * @returns 监听器ID + */ + on(eventType, handler, config = {}) { + this.validateEventType(eventType); + const eventConfig = { + once: config.once || false, + priority: config.priority || EventPriority.NORMAL, + async: config.async || false, + context: config.context + }; + if (this.isDebugMode) { + EventBus._logger.info(`添加监听器: ${eventType}`, eventConfig); + } + return this.eventSystem.on(eventType, handler, eventConfig); + } + /** + * 监听事件(一次性) + * @param eventType 事件类型 + * @param handler 事件处理器 + * @param config 监听器配置 + * @returns 监听器ID + */ + once(eventType, handler, config = {}) { + return this.on(eventType, handler, { ...config, once: true }); + } + /** + * 异步监听事件 + * @param eventType 事件类型 + * @param handler 异步事件处理器 + * @param config 监听器配置 + * @returns 监听器ID + */ + onAsync(eventType, handler, config = {}) { + return this.on(eventType, handler, { ...config, async: true }); + } + /** + * 移除事件监听器 + * @param eventType 事件类型 + * @param listenerId 监听器ID + */ + off(eventType, listenerId) { + if (this.isDebugMode) { + EventBus._logger.info(`移除监听器: ${listenerId} 事件: ${eventType}`); + } + return this.eventSystem.off(eventType, listenerId); + } + /** + * 移除指定事件类型的所有监听器 + * @param eventType 事件类型 + */ + offAll(eventType) { + if (this.isDebugMode) { + EventBus._logger.info(`移除所有监听器: ${eventType}`); + } + this.eventSystem.offAll(eventType); + } + /** + * 检查是否有指定事件的监听器 + * @param eventType 事件类型 + */ + hasListeners(eventType) { + return this.eventSystem.hasListeners(eventType); + } + /** + * 获取事件统计信息 + * @param eventType 事件类型(可选) + */ + getStats(eventType) { + const stats = this.eventSystem.getStats(eventType); + if (stats instanceof Map) { + const result = /* @__PURE__ */ new Map(); + stats.forEach((stat, key) => { + result.set(key, this.convertEventStats(stat)); + }); + return result; + } else { + return this.convertEventStats(stats); + } + } + /** + * 清空所有监听器 + */ + clear() { + if (this.isDebugMode) { + EventBus._logger.info("清空所有监听器"); + } + this.eventSystem.clear(); + } + /** + * 启用或禁用事件系统 + * @param enabled 是否启用 + */ + setEnabled(enabled) { + this.eventSystem.setEnabled(enabled); + } + /** + * 设置调试模式 + * @param debug 是否启用调试 + */ + setDebugMode(debug) { + this.isDebugMode = debug; + } + /** + * 设置最大监听器数量 + * @param max 最大数量 + */ + setMaxListeners(max) { + this.eventSystem.setMaxListeners(max); + } + /** + * 获取监听器数量 + * @param eventType 事件类型 + */ + getListenerCount(eventType) { + return this.eventSystem.getListenerCount(eventType); + } + /** + * 设置事件批处理配置 + * @param eventType 事件类型 + * @param batchSize 批处理大小 + * @param delay 延迟时间(毫秒) + */ + setBatchConfig(eventType, batchSize, delay) { + this.eventSystem.setBatchConfig(eventType, { + batchSize, + delay, + enabled: true + }); + } + /** + * 刷新指定事件的批处理队列 + * @param eventType 事件类型 + */ + flushBatch(eventType) { + this.eventSystem.flushBatch(eventType); + } + /** + * 重置事件统计 + * @param eventType 事件类型(可选) + */ + resetStats(eventType) { + this.eventSystem.resetStats(eventType); + } + // 便捷方法:发射预定义的ECS事件 + /** + * 发射实体创建事件 + * @param entityData 实体事件数据 + */ + emitEntityCreated(entityData) { + this.emit(ECSEventType.ENTITY_CREATED, entityData); + } + /** + * 发射实体销毁事件 + * @param entityData 实体事件数据 + */ + emitEntityDestroyed(entityData) { + this.emit(ECSEventType.ENTITY_DESTROYED, entityData); + } + /** + * 发射组件添加事件 + * @param componentData 组件事件数据 + */ + emitComponentAdded(componentData) { + this.emit(ECSEventType.COMPONENT_ADDED, componentData); + } + /** + * 发射组件移除事件 + * @param componentData 组件事件数据 + */ + emitComponentRemoved(componentData) { + this.emit(ECSEventType.COMPONENT_REMOVED, componentData); + } + /** + * 发射系统添加事件 + * @param systemData 系统事件数据 + */ + emitSystemAdded(systemData) { + this.emit(ECSEventType.SYSTEM_ADDED, systemData); + } + /** + * 发射系统移除事件 + * @param systemData 系统事件数据 + */ + emitSystemRemoved(systemData) { + this.emit(ECSEventType.SYSTEM_REMOVED, systemData); + } + /** + * 发射场景变化事件 + * @param sceneData 场景事件数据 + */ + emitSceneChanged(sceneData) { + this.emit(ECSEventType.SCENE_ACTIVATED, sceneData); + } + /** + * 发射性能警告事件 + * @param performanceData 性能事件数据 + */ + emitPerformanceWarning(performanceData) { + this.emit(ECSEventType.PERFORMANCE_WARNING, performanceData); + } + // 便捷方法:监听预定义的ECS事件 + /** + * 监听实体创建事件 + * @param handler 事件处理器 + * @param config 监听器配置 + */ + onEntityCreated(handler, config) { + return this.on(ECSEventType.ENTITY_CREATED, handler, config); + } + /** + * 监听组件添加事件 + * @param handler 事件处理器 + * @param config 监听器配置 + */ + onComponentAdded(handler, config) { + return this.on(ECSEventType.COMPONENT_ADDED, handler, config); + } + /** + * 监听系统错误事件 + * @param handler 事件处理器 + * @param config 监听器配置 + */ + onSystemError(handler, config) { + return this.on(ECSEventType.SYSTEM_ERROR, handler, config); + } + /** + * 监听性能警告事件 + * @param handler 事件处理器 + * @param config 监听器配置 + */ + onPerformanceWarning(handler, config) { + return this.on(ECSEventType.PERFORMANCE_WARNING, handler, config); + } + // 私有方法 + /** + * 验证事件类型(仅在debug模式下执行,提升性能) + * @param eventType 事件类型 + */ + validateEventType(eventType) { + if (this.isDebugMode) { + if (!EventTypeValidator.isValid(eventType)) { + EventBus._logger.warn(`未知事件类型: ${eventType}`); + EventTypeValidator.addCustomType(eventType); + } + } + } + /** + * 增强事件数据 + * @param eventType 事件类型 + * @param data 原始数据 + */ + enhanceEventData(eventType, data) { + if (data === null || data === void 0) { + return { + timestamp: Date.now(), + eventId: `${eventType}_${++this.eventIdCounter}`, + source: "EventBus" + }; + } + const enhanced = data; + if (!enhanced.timestamp) { + enhanced.timestamp = Date.now(); + } + if (!enhanced.eventId) { + enhanced.eventId = `${eventType}_${++this.eventIdCounter}`; + } + if (!enhanced.source) { + enhanced.source = "EventBus"; + } + return enhanced; + } + /** + * 转换EventStats为IEventStats + * @param stats EventStats实例 + */ + convertEventStats(stats) { + return { + eventType: stats.eventType, + listenerCount: stats.listenerCount, + triggerCount: stats.triggerCount, + totalExecutionTime: stats.totalExecutionTime, + averageExecutionTime: stats.averageExecutionTime, + lastTriggerTime: stats.lastTriggerTime + }; + } +} +EventBus._logger = createLogger("EventBus"); +class Scene { + /** + * 获取系统列表(兼容性属性) + */ + get systems() { + return this.entityProcessors.processors; + } + /** + * 创建场景实例 + */ + constructor(config) { + this.name = ""; + this._didSceneBegin = false; + this.entities = new EntityList(this); + this.entityProcessors = new EntityProcessorList(); + this.identifierPool = new IdentifierPool(); + this.componentStorageManager = new ComponentStorageManager(); + this.querySystem = new QuerySystem(); + this.eventSystem = new TypeSafeEventSystem(); + if (config?.name) { + this.name = config.name; + } + if (config?.enableEntityDirectUpdate !== void 0) { + this.entities.setEnableEntityDirectUpdate(config.enableEntityDirectUpdate); + } + if (!Entity.eventBus) { + Entity.eventBus = new EventBus(false); + } + if (Entity.eventBus) { + Entity.eventBus.onComponentAdded((data) => { + this.eventSystem.emitSync("component:added", data); + }); + } + } + /** + * 初始化场景 + * + * 在场景创建时调用,子类可以重写此方法来设置初始实体和组件。 + */ + initialize() { + } + /** + * 场景开始运行时的回调 + * + * 在场景开始运行时调用,可以在此方法中执行场景启动逻辑。 + */ + onStart() { + } + /** + * 场景卸载时的回调 + * + * 在场景被销毁时调用,可以在此方法中执行清理工作。 + */ + unload() { + } + /** + * 开始场景,启动实体处理器等 + * + * 这个方法会启动场景。它将启动实体处理器等,并调用onStart方法。 + */ + begin() { + if (this.entityProcessors != null) + this.entityProcessors.begin(); + this._didSceneBegin = true; + this.onStart(); + } + /** + * 结束场景,清除实体、实体处理器等 + * + * 这个方法会结束场景。它将移除所有实体,结束实体处理器等,并调用unload方法。 + */ + end() { + this._didSceneBegin = false; + this.entities.removeAllEntities(); + this.querySystem.setEntities([]); + this.componentStorageManager.clear(); + if (this.entityProcessors) + this.entityProcessors.end(); + this.unload(); + } + /** + * 更新场景 + */ + update() { + this.entities.updateLists(); + if (this.entityProcessors != null) + this.entityProcessors.update(); + this.entities.update(); + if (this.entityProcessors != null) + this.entityProcessors.lateUpdate(); + } + /** + * 将实体添加到此场景,并返回它 + * @param name 实体名称 + */ + createEntity(name) { + let entity = new Entity(name, this.identifierPool.checkOut()); + this.eventSystem.emitSync("entity:created", { entityName: name, entity, scene: this }); + return this.addEntity(entity); + } + /** + * 清除所有EntitySystem的实体缓存 + * 当实体或组件发生变化时调用 + */ + clearSystemEntityCaches() { + for (const system of this.entityProcessors.processors) { + system.clearEntityCache(); + } + } + /** + * 在场景的实体列表中添加一个实体 + * @param entity 要添加的实体 + * @param deferCacheClear 是否延迟缓存清理(用于批量操作) + */ + addEntity(entity, deferCacheClear = false) { + this.entities.add(entity); + entity.scene = this; + this.querySystem.addEntity(entity, deferCacheClear); + if (!deferCacheClear) { + this.clearSystemEntityCaches(); + } + this.eventSystem.emitSync("entity:added", { entity, scene: this }); + return entity; + } + /** + * 批量创建实体(高性能版本) + * @param count 要创建的实体数量 + * @param namePrefix 实体名称前缀 + * @returns 创建的实体列表 + */ + createEntities(count, namePrefix = "Entity") { + const entities = []; + for (let i = 0; i < count; i++) { + const entity = new Entity(`${namePrefix}_${i}`, this.identifierPool.checkOut()); + entity.scene = this; + entities.push(entity); + } + for (const entity of entities) { + this.entities.add(entity); + } + this.querySystem.addEntitiesUnchecked(entities); + this.eventSystem.emitSync("entities:batch_added", { entities, scene: this, count }); + return entities; + } + /** + * 从场景中删除所有实体 + */ + destroyAllEntities() { + this.entities.removeAllEntities(); + this.querySystem.setEntities([]); + } + /** + * 搜索并返回第一个具有名称的实体 + * @param name 实体名称 + */ + findEntity(name) { + return this.entities.findEntity(name); + } + /** + * 根据ID查找实体 + * @param id 实体ID + */ + findEntityById(id) { + return this.entities.findEntityById(id); + } + /** + * 根据标签查找实体 + * @param tag 实体标签 + */ + findEntitiesByTag(tag) { + const result = []; + for (const entity of this.entities.buffer) { + if (entity.tag === tag) { + result.push(entity); + } + } + return result; + } + /** + * 根据名称查找实体(别名方法) + * @param name 实体名称 + */ + getEntityByName(name) { + return this.findEntity(name); + } + /** + * 根据标签查找实体(别名方法) + * @param tag 实体标签 + */ + getEntitiesByTag(tag) { + return this.findEntitiesByTag(tag); + } + /** + * 在场景中添加一个EntitySystem处理器 + * @param processor 处理器 + */ + addEntityProcessor(processor) { + if (this.entityProcessors.processors.includes(processor)) { + return processor; + } + processor.scene = this; + this.entityProcessors.add(processor); + processor.initialize(); + processor.setUpdateOrder(this.entityProcessors.count - 1); + return processor; + } + /** + * 添加系统到场景(addEntityProcessor的别名) + * @param system 系统 + */ + addSystem(system) { + return this.addEntityProcessor(system); + } + /** + * 从场景中删除EntitySystem处理器 + * @param processor 要删除的处理器 + */ + removeEntityProcessor(processor) { + this.entityProcessors.remove(processor); + processor.reset(); + } + /** + * 从场景中删除系统(removeEntityProcessor的别名) + * @param system 系统 + */ + removeSystem(system) { + this.removeEntityProcessor(system); + } + /** + * 获取指定类型的EntitySystem处理器 + * @param type 处理器类型 + */ + getEntityProcessor(type) { + return this.entityProcessors.getProcessor(type); + } + /** + * 获取场景统计信息 + */ + getStats() { + return { + entityCount: this.entities.count, + processorCount: this.entityProcessors.count, + componentStorageStats: this.componentStorageManager.getAllStats() + }; + } + /** + * 获取场景的调试信息 + */ + getDebugInfo() { + return { + name: this.name || this.constructor.name, + entityCount: this.entities.count, + processorCount: this.entityProcessors.count, + isRunning: this._didSceneBegin, + entities: this.entities.buffer.map((entity) => ({ + name: entity.name, + id: entity.id, + componentCount: entity.components.length, + componentTypes: entity.components.map((c) => getComponentInstanceTypeName(c)) + })), + processors: this.entityProcessors.processors.map((processor) => ({ + name: getSystemInstanceTypeName(processor), + updateOrder: processor.updateOrder, + entityCount: processor._entities?.length || 0 + })), + componentStats: this.componentStorageManager.getAllStats() + }; + } +} +class SceneBuilder { + constructor() { + this.scene = new Scene(); + } + /** + * 设置场景名称 + * @param name 场景名称 + * @returns 场景构建器 + */ + named(name) { + this.scene.name = name; + return this; + } + /** + * 添加实体 + * @param entity 实体 + * @returns 场景构建器 + */ + withEntity(entity) { + this.scene.addEntity(entity); + return this; + } + /** + * 使用实体构建器添加实体 + * @param builderFn 实体构建器函数 + * @returns 场景构建器 + */ + withEntityBuilder(builderFn) { + const builder = new EntityBuilder(this.scene, this.scene.componentStorageManager); + const configuredBuilder = builderFn(builder); + const entity = configuredBuilder.build(); + this.scene.addEntity(entity); + return this; + } + /** + * 批量添加实体 + * @param entities 实体数组 + * @returns 场景构建器 + */ + withEntities(...entities) { + for (const entity of entities) { + this.scene.addEntity(entity); + } + return this; + } + /** + * 添加系统 + * @param system 系统实例 + * @returns 场景构建器 + */ + withSystem(system) { + this.scene.addSystem(system); + return this; + } + /** + * 批量添加系统 + * @param systems 系统数组 + * @returns 场景构建器 + */ + withSystems(...systems) { + for (const system of systems) { + this.scene.addSystem(system); + } + return this; + } + /** + * 构建并返回场景 + * @returns 构建的场景 + */ + build() { + return this.scene; + } +} +class ComponentBuilder { + constructor(componentClass, ...args) { + this.component = new componentClass(...args); + } + /** + * 设置组件属性 + * @param property 属性名 + * @param value 属性值 + * @returns 组件构建器 + */ + set(property, value) { + this.component[property] = value; + return this; + } + /** + * 使用配置函数设置组件 + * @param configurator 配置函数 + * @returns 组件构建器 + */ + configure(configurator) { + configurator(this.component); + return this; + } + /** + * 条件性设置属性 + * @param condition 条件 + * @param property 属性名 + * @param value 属性值 + * @returns 组件构建器 + */ + setIf(condition, property, value) { + if (condition) { + this.component[property] = value; + } + return this; + } + /** + * 构建并返回组件 + * @returns 构建的组件 + */ + build() { + return this.component; + } +} +class EntityBatchOperator { + constructor(entities) { + this.entities = entities; + } + /** + * 批量添加组件 + * @param component 组件实例 + * @returns 批量操作器 + */ + addComponent(component) { + for (const entity of this.entities) { + entity.addComponent(component); + } + return this; + } + /** + * 批量移除组件 + * @param componentType 组件类型 + * @returns 批量操作器 + */ + removeComponent(componentType) { + for (const entity of this.entities) { + entity.removeComponentByType(componentType); + } + return this; + } + /** + * 批量设置活跃状态 + * @param active 是否活跃 + * @returns 批量操作器 + */ + setActive(active) { + for (const entity of this.entities) { + entity.active = active; + } + return this; + } + /** + * 批量设置标签 + * @param tag 标签 + * @returns 批量操作器 + */ + setTag(tag) { + for (const entity of this.entities) { + entity.tag = tag; + } + return this; + } + /** + * 批量执行操作 + * @param operation 操作函数 + * @returns 批量操作器 + */ + forEach(operation) { + this.entities.forEach(operation); + return this; + } + /** + * 过滤实体 + * @param predicate 过滤条件 + * @returns 新的批量操作器 + */ + filter(predicate) { + return new EntityBatchOperator(this.entities.filter(predicate)); + } + /** + * 获取实体数组 + * @returns 实体数组 + */ + toArray() { + return this.entities.slice(); + } + /** + * 获取实体数量 + * @returns 实体数量 + */ + count() { + return this.entities.length; + } +} +class ECSFluentAPI { + constructor(scene, querySystem, eventSystem) { + this.scene = scene; + this.querySystem = querySystem; + this.eventSystem = eventSystem; + } + /** + * 创建实体构建器 + * @returns 实体构建器 + */ + createEntity() { + return new EntityBuilder(this.scene, this.scene.componentStorageManager); + } + /** + * 创建场景构建器 + * @returns 场景构建器 + */ + createScene() { + return new SceneBuilder(); + } + /** + * 创建组件构建器 + * @param componentClass 组件类 + * @param args 构造参数 + * @returns 组件构建器 + */ + createComponent(componentClass, ...args) { + return new ComponentBuilder(componentClass, ...args); + } + /** + * 创建查询构建器 + * @returns 查询构建器 + */ + query() { + return new QueryBuilder(this.querySystem); + } + /** + * 查找实体 + * @param componentTypes 组件类型 + * @returns 实体数组 + */ + find(...componentTypes) { + return this.querySystem.queryAll(...componentTypes).entities; + } + /** + * 查找第一个匹配的实体 + * @param componentTypes 组件类型 + * @returns 实体或null + */ + findFirst(...componentTypes) { + const result = this.querySystem.queryAll(...componentTypes); + return result.entities.length > 0 ? result.entities[0] : null; + } + /** + * 按名称查找实体 + * @param name 实体名称 + * @returns 实体或null + */ + findByName(name) { + return this.scene.findEntity(name); + } + /** + * 按标签查找实体 + * @param tag 标签 + * @returns 实体数组 + */ + findByTag(tag) { + return this.scene.findEntitiesByTag(tag); + } + /** + * 触发事件 + * @param eventType 事件类型 + * @param event 事件数据 + */ + emit(eventType, event) { + this.eventSystem.emitSync(eventType, event); + } + /** + * 异步触发事件 + * @param eventType 事件类型 + * @param event 事件数据 + */ + async emitAsync(eventType, event) { + await this.eventSystem.emit(eventType, event); + } + /** + * 监听事件 + * @param eventType 事件类型 + * @param handler 事件处理器 + * @returns 监听器ID + */ + on(eventType, handler) { + return this.eventSystem.on(eventType, handler); + } + /** + * 一次性监听事件 + * @param eventType 事件类型 + * @param handler 事件处理器 + * @returns 监听器ID + */ + once(eventType, handler) { + return this.eventSystem.once(eventType, handler); + } + /** + * 移除事件监听器 + * @param eventType 事件类型 + * @param listenerId 监听器ID + */ + off(eventType, listenerId) { + this.eventSystem.off(eventType, listenerId); + } + /** + * 批量操作实体 + * @param entities 实体数组 + * @returns 批量操作器 + */ + batch(entities) { + return new EntityBatchOperator(entities); + } + /** + * 获取场景统计信息 + * @returns 统计信息 + */ + getStats() { + return { + entityCount: this.scene.entities.count, + systemCount: this.scene.systems.length, + componentStats: this.scene.componentStorageManager.getAllStats(), + queryStats: this.querySystem.getStats(), + eventStats: this.eventSystem.getStats() + }; + } +} +function createECSAPI(scene, querySystem, eventSystem) { + return new ECSFluentAPI(scene, querySystem, eventSystem); +} +const logger$1 = createLogger("World"); +class World { + constructor(config = {}) { + this._scenes = /* @__PURE__ */ new Map(); + this._activeScenes = /* @__PURE__ */ new Set(); + this._globalSystems = []; + this._isActive = false; + this._config = { + name: "World", + debug: false, + maxScenes: 10, + autoCleanup: true, + ...config + }; + this.name = this._config.name; + this._createdAt = Date.now(); + logger$1.info(`创建World: ${this.name}`); + } + // ===== Scene管理 ===== + /** + * 创建并添加Scene到World + */ + createScene(sceneId, sceneInstance) { + if (this._scenes.has(sceneId)) { + throw new Error(`Scene ID '${sceneId}' 已存在于World '${this.name}' 中`); + } + if (this._scenes.size >= this._config.maxScenes) { + throw new Error(`World '${this.name}' 已达到最大Scene数量限制: ${this._config.maxScenes}`); + } + const scene = sceneInstance || new Scene(); + if ("id" in scene) { + scene.id = sceneId; + } + if ("name" in scene && !scene.name) { + scene.name = sceneId; + } + this._scenes.set(sceneId, scene); + scene.initialize(); + logger$1.info(`在World '${this.name}' 中创建Scene: ${sceneId}`); + return scene; + } + /** + * 移除Scene + */ + removeScene(sceneId) { + const scene = this._scenes.get(sceneId); + if (!scene) { + return false; + } + if (this._activeScenes.has(sceneId)) { + this.setSceneActive(sceneId, false); + } + scene.end(); + this._scenes.delete(sceneId); + logger$1.info(`从World '${this.name}' 中移除Scene: ${sceneId}`); + return true; + } + /** + * 获取Scene + */ + getScene(sceneId) { + return this._scenes.get(sceneId) || null; + } + /** + * 获取所有Scene ID + */ + getSceneIds() { + return Array.from(this._scenes.keys()); + } + /** + * 获取所有Scene + */ + getAllScenes() { + return Array.from(this._scenes.values()); + } + /** + * 设置Scene激活状态 + */ + setSceneActive(sceneId, active) { + const scene = this._scenes.get(sceneId); + if (!scene) { + logger$1.warn(`Scene '${sceneId}' 不存在于World '${this.name}' 中`); + return; + } + if (active) { + this._activeScenes.add(sceneId); + if (scene.begin) { + scene.begin(); + } + logger$1.debug(`在World '${this.name}' 中激活Scene: ${sceneId}`); + } else { + this._activeScenes.delete(sceneId); + logger$1.debug(`在World '${this.name}' 中停用Scene: ${sceneId}`); + } + } + /** + * 检查Scene是否激活 + */ + isSceneActive(sceneId) { + return this._activeScenes.has(sceneId); + } + /** + * 获取活跃Scene数量 + */ + getActiveSceneCount() { + return this._activeScenes.size; + } + // ===== 全局System管理 ===== + /** + * 添加全局System + * 全局System会在所有激活Scene之前更新 + */ + addGlobalSystem(system) { + if (this._globalSystems.includes(system)) { + return system; + } + this._globalSystems.push(system); + if (system.initialize) { + system.initialize(); + } + logger$1.debug(`在World '${this.name}' 中添加全局System: ${system.name}`); + return system; + } + /** + * 移除全局System + */ + removeGlobalSystem(system) { + const index = this._globalSystems.indexOf(system); + if (index === -1) { + return false; + } + this._globalSystems.splice(index, 1); + if (system.reset) { + system.reset(); + } + logger$1.debug(`从World '${this.name}' 中移除全局System: ${system.name}`); + return true; + } + /** + * 获取全局System + */ + getGlobalSystem(type) { + for (const system of this._globalSystems) { + if (system instanceof type) { + return system; + } + } + return null; + } + // ===== World生命周期 ===== + /** + * 启动World + */ + start() { + if (this._isActive) { + return; + } + this._isActive = true; + for (const system of this._globalSystems) { + if (system.initialize) { + system.initialize(); + } + } + logger$1.info(`启动World: ${this.name}`); + } + /** + * 停止World + */ + stop() { + if (!this._isActive) { + return; + } + for (const sceneId of this._activeScenes) { + this.setSceneActive(sceneId, false); + } + for (const system of this._globalSystems) { + if (system.reset) { + system.reset(); + } + } + this._isActive = false; + logger$1.info(`停止World: ${this.name}`); + } + /** + * 更新World中的全局System + * 注意:此方法由Core.update()调用,不应直接调用 + */ + updateGlobalSystems() { + if (!this._isActive) { + return; + } + for (const system of this._globalSystems) { + if (system.update) { + system.update(); + } + } + } + /** + * 更新World中的所有激活Scene + * 注意:此方法由Core.update()调用,不应直接调用 + */ + updateScenes() { + if (!this._isActive) { + return; + } + for (const sceneId of this._activeScenes) { + const scene = this._scenes.get(sceneId); + if (scene && scene.update) { + scene.update(); + } + } + if (this._config.autoCleanup && this.shouldAutoCleanup()) { + this.cleanup(); + } + } + /** + * 销毁World + */ + destroy() { + logger$1.info(`销毁World: ${this.name}`); + this.stop(); + const sceneIds = Array.from(this._scenes.keys()); + for (const sceneId of sceneIds) { + this.removeScene(sceneId); + } + for (const system of this._globalSystems) { + if (system.destroy) { + system.destroy(); + } else if (system.reset) { + system.reset(); + } + } + this._globalSystems.length = 0; + this._scenes.clear(); + this._activeScenes.clear(); + } + // ===== 状态信息 ===== + /** + * 获取World状态 + */ + getStatus() { + return { + name: this.name, + isActive: this._isActive, + sceneCount: this._scenes.size, + activeSceneCount: this._activeScenes.size, + globalSystemCount: this._globalSystems.length, + createdAt: this._createdAt, + config: { ...this._config }, + scenes: Array.from(this._scenes.keys()).map((sceneId) => ({ + id: sceneId, + isActive: this._activeScenes.has(sceneId), + name: this._scenes.get(sceneId)?.name || sceneId + })) + }; + } + /** + * 获取World统计信息 + */ + getStats() { + const stats = { + totalEntities: 0, + totalSystems: this._globalSystems.length, + memoryUsage: 0, + performance: { + averageUpdateTime: 0, + maxUpdateTime: 0 + } + }; + for (const scene of this._scenes.values()) { + if (scene.entities) { + stats.totalEntities += scene.entities.count; + } + if (scene.systems) { + stats.totalSystems += scene.systems.length; + } + } + return stats; + } + // ===== 私有方法 ===== + /** + * 检查是否应该执行自动清理 + */ + shouldAutoCleanup() { + const currentTime = Date.now(); + const cleanupThreshold = 5 * 60 * 1e3; + for (const [sceneId, scene] of this._scenes) { + if (!this._activeScenes.has(sceneId) && scene.entities && scene.entities.count === 0 && currentTime - this._createdAt > cleanupThreshold) { + return true; + } + } + return false; + } + /** + * 执行清理操作 + */ + cleanup() { + const sceneIds = Array.from(this._scenes.keys()); + const currentTime = Date.now(); + const cleanupThreshold = 5 * 60 * 1e3; + for (const sceneId of sceneIds) { + const scene = this._scenes.get(sceneId); + if (scene && !this._activeScenes.has(sceneId) && scene.entities && scene.entities.count === 0 && currentTime - this._createdAt > cleanupThreshold) { + this.removeScene(sceneId); + logger$1.debug(`自动清理空Scene: ${sceneId} from World ${this.name}`); + } + } + } + // ===== 访问器 ===== + /** + * 检查World是否激活 + */ + get isActive() { + return this._isActive; + } + /** + * 获取Scene数量 + */ + get sceneCount() { + return this._scenes.size; + } + /** + * 获取创建时间 + */ + get createdAt() { + return this._createdAt; + } +} +const logger = createLogger("WorldManager"); +class WorldManager { + constructor(config = {}) { + this._worlds = /* @__PURE__ */ new Map(); + this._activeWorlds = /* @__PURE__ */ new Set(); + this._cleanupTimer = null; + this._isRunning = false; + this._config = { + maxWorlds: 50, + autoCleanup: true, + cleanupInterval: 3e4, + // 30秒 + debug: false, + ...config + }; + logger.info("WorldManager已初始化", { + maxWorlds: this._config.maxWorlds, + autoCleanup: this._config.autoCleanup, + cleanupInterval: this._config.cleanupInterval + }); + this.startCleanupTimer(); + } + /** + * 获取WorldManager单例实例 + */ + static getInstance(config) { + if (!this._instance) { + this._instance = new WorldManager(config); + } + return this._instance; + } + /** + * 重置WorldManager实例(主要用于测试) + */ + static reset() { + if (this._instance) { + this._instance.destroy(); + this._instance = null; + } + } + // ===== World管理 ===== + /** + * 创建新World + */ + createWorld(worldId, config) { + if (!worldId || typeof worldId !== "string" || worldId.trim() === "") { + throw new Error("World ID不能为空"); + } + if (this._worlds.has(worldId)) { + throw new Error(`World ID '${worldId}' 已存在`); + } + if (this._worlds.size >= this._config.maxWorlds) { + throw new Error(`已达到最大World数量限制: ${this._config.maxWorlds}`); + } + const worldConfig = { + name: worldId, + debug: this._config.debug, + ...config + }; + const world = new World(worldConfig); + this._worlds.set(worldId, world); + logger.info(`创建World: ${worldId}`, { config: worldConfig }); + return world; + } + /** + * 移除World + */ + removeWorld(worldId) { + const world = this._worlds.get(worldId); + if (!world) { + return false; + } + if (this._activeWorlds.has(worldId)) { + this.setWorldActive(worldId, false); + } + world.destroy(); + this._worlds.delete(worldId); + logger.info(`移除World: ${worldId}`); + return true; + } + /** + * 获取World + */ + getWorld(worldId) { + return this._worlds.get(worldId) || null; + } + /** + * 获取所有World ID + */ + getWorldIds() { + return Array.from(this._worlds.keys()); + } + /** + * 获取所有World + */ + getAllWorlds() { + return Array.from(this._worlds.values()); + } + /** + * 设置World激活状态 + */ + setWorldActive(worldId, active) { + const world = this._worlds.get(worldId); + if (!world) { + logger.warn(`World '${worldId}' 不存在`); + return; + } + if (active) { + this._activeWorlds.add(worldId); + world.start(); + logger.debug(`激活World: ${worldId}`); + } else { + this._activeWorlds.delete(worldId); + world.stop(); + logger.debug(`停用World: ${worldId}`); + } + } + /** + * 检查World是否激活 + */ + isWorldActive(worldId) { + return this._activeWorlds.has(worldId); + } + // ===== 批量操作 ===== + /** + * 获取所有激活的World + * 注意:此方法供Core.update()使用 + */ + getActiveWorlds() { + const activeWorlds = []; + for (const worldId of this._activeWorlds) { + const world = this._worlds.get(worldId); + if (world) { + activeWorlds.push(world); + } + } + return activeWorlds; + } + /** + * 启动所有World + */ + startAll() { + this._isRunning = true; + for (const worldId of this._worlds.keys()) { + this.setWorldActive(worldId, true); + } + logger.info("启动所有World"); + } + /** + * 停止所有World + */ + stopAll() { + this._isRunning = false; + for (const worldId of this._activeWorlds) { + this.setWorldActive(worldId, false); + } + logger.info("停止所有World"); + } + /** + * 查找满足条件的World + */ + findWorlds(predicate) { + const results = []; + for (const world of this._worlds.values()) { + if (predicate(world)) { + results.push(world); + } + } + return results; + } + /** + * 根据名称查找World + */ + findWorldByName(name) { + for (const world of this._worlds.values()) { + if (world.name === name) { + return world; + } + } + return null; + } + // ===== 统计和监控 ===== + /** + * 获取WorldManager统计信息 + */ + getStats() { + const stats = { + totalWorlds: this._worlds.size, + activeWorlds: this._activeWorlds.size, + totalScenes: 0, + totalEntities: 0, + totalSystems: 0, + memoryUsage: 0, + isRunning: this._isRunning, + config: { ...this._config }, + worlds: [] + }; + for (const [worldId, world] of this._worlds) { + const worldStats = world.getStats(); + stats.totalScenes += worldStats.totalSystems; + stats.totalEntities += worldStats.totalEntities; + stats.totalSystems += worldStats.totalSystems; + stats.worlds.push({ + id: worldId, + name: world.name, + isActive: this._activeWorlds.has(worldId), + sceneCount: world.sceneCount, + ...worldStats + }); + } + return stats; + } + /** + * 获取详细状态信息 + */ + getDetailedStatus() { + return { + ...this.getStats(), + worlds: Array.from(this._worlds.entries()).map(([worldId, world]) => ({ + id: worldId, + isActive: this._activeWorlds.has(worldId), + status: world.getStatus() + })) + }; + } + // ===== 生命周期管理 ===== + /** + * 清理空World + */ + cleanup() { + const worldsToRemove = []; + for (const [worldId, world] of this._worlds) { + if (this.shouldCleanupWorld(world)) { + worldsToRemove.push(worldId); + } + } + for (const worldId of worldsToRemove) { + this.removeWorld(worldId); + } + if (worldsToRemove.length > 0) { + logger.debug(`清理了 ${worldsToRemove.length} 个World`); + } + return worldsToRemove.length; + } + /** + * 销毁WorldManager + */ + destroy() { + logger.info("正在销毁WorldManager..."); + this.stopCleanupTimer(); + this.stopAll(); + const worldIds = Array.from(this._worlds.keys()); + for (const worldId of worldIds) { + this.removeWorld(worldId); + } + this._worlds.clear(); + this._activeWorlds.clear(); + this._isRunning = false; + logger.info("WorldManager已销毁"); + } + // ===== 私有方法 ===== + /** + * 启动清理定时器 + */ + startCleanupTimer() { + if (!this._config.autoCleanup || this._cleanupTimer) { + return; + } + this._cleanupTimer = setInterval(() => { + this.cleanup(); + }, this._config.cleanupInterval); + logger.debug(`启动World清理定时器,间隔: ${this._config.cleanupInterval}ms`); + } + /** + * 停止清理定时器 + */ + stopCleanupTimer() { + if (this._cleanupTimer) { + clearInterval(this._cleanupTimer); + this._cleanupTimer = null; + logger.debug("停止World清理定时器"); + } + } + /** + * 判断World是否应该被清理 + */ + shouldCleanupWorld(world) { + if (world.isActive) { + return false; + } + if (world.sceneCount === 0) { + const age = Date.now() - world.createdAt; + return age > 10 * 60 * 1e3; + } + const allScenes = world.getAllScenes(); + const hasEntities = allScenes.some((scene) => scene.entities && scene.entities.count > 0); + if (!hasEntities) { + const age = Date.now() - world.createdAt; + return age > 10 * 60 * 1e3; + } + return false; + } + // ===== 访问器 ===== + /** + * 获取World总数 + */ + get worldCount() { + return this._worlds.size; + } + /** + * 获取激活World数量 + */ + get activeWorldCount() { + return this._activeWorlds.size; + } + /** + * 检查是否正在运行 + */ + get isRunning() { + return this._isRunning; + } + /** + * 获取配置 + */ + get config() { + return { ...this._config }; + } +} +WorldManager._instance = null; +class Bits { + /** + * 构造函数,创建位集合 + * @param initialValue 初始值,可以是BitMask64Data对象、数字或字符串 + */ + constructor(initialValue) { + if (initialValue && typeof initialValue === "object") { + this._value = BitMask64Utils.clone(initialValue); + } else if (typeof initialValue === "number") { + this._value = BitMask64Utils.fromNumber(initialValue); + } else if (typeof initialValue === "string") { + const num = parseInt(initialValue, 10); + this._value = BitMask64Utils.fromNumber(num); + } else { + this._value = BitMask64Utils.clone(BitMask64Utils.ZERO); + } + } + /** + * 设置指定位为1 + * @param index 位索引,范围 [0, 63] + * @throws 当位索引为负数或超过64位限制时抛出错误 + */ + set(index) { + if (index < 0) { + throw new Error("Bit index cannot be negative"); + } + if (index >= 64) { + throw new Error("Bit index exceeds 64-bit limit. ECS framework supports max 64 component types."); + } + BitMask64Utils.setBit(this._value, index); + } + /** + * 清除指定位为0 + * @param index 位索引,范围 [0, 63] + * @throws 当位索引为负数时抛出错误 + */ + clear(index) { + if (index < 0) { + throw new Error("Bit index cannot be negative"); + } + if (index >= 64) { + return; + } + BitMask64Utils.clearBit(this._value, index); + } + /** + * 获取指定位的值 + * @param index 位索引 + * @returns 如果位被设置为1则返回true,否则返回false + */ + get(index) { + if (index < 0 || index >= 64) { + return false; + } + const mask = BitMask64Utils.create(index); + return BitMask64Utils.hasAny(this._value, mask); + } + /** + * 检查是否包含另一个位集合的所有位 + * @param other 另一个位集合 + * @returns 如果包含other的所有设置位则返回true + */ + containsAll(other) { + return BitMask64Utils.hasAll(this._value, other._value); + } + /** + * 检查是否与另一个位集合有交集 + * @param other 另一个位集合 + * @returns 如果有共同的设置位则返回true + */ + intersects(other) { + return BitMask64Utils.hasAny(this._value, other._value); + } + /** + * 检查是否与另一个位集合没有交集 + * @param other 另一个位集合 + * @returns 如果没有共同的设置位则返回true + */ + excludes(other) { + return BitMask64Utils.hasNone(this._value, other._value); + } + /** + * 清除所有位为0 + */ + clearAll() { + BitMask64Utils.clear(this._value); + } + /** + * 检查位集合是否为空 + * @returns 如果所有位都为0则返回true + */ + isEmpty() { + return BitMask64Utils.isZero(this._value); + } + /** + * 计算设置为1的位数 + * @returns 设置位的总数 + */ + cardinality() { + return BitMask64Utils.popCount(this._value); + } + /** + * 与另一个位集合执行按位与操作 + * @param other 另一个位集合 + * @returns 新的位集合,包含按位与的结果 + */ + and(other) { + const result = new Bits(); + BitMask64Utils.copy(this._value, result._value); + BitMask64Utils.andInPlace(result._value, other._value); + return result; + } + /** + * 与另一个位集合执行按位或操作 + * @param other 另一个位集合 + * @returns 新的位集合,包含按位或的结果 + */ + or(other) { + const result = new Bits(); + BitMask64Utils.copy(this._value, result._value); + BitMask64Utils.orInPlace(result._value, other._value); + return result; + } + /** + * 与另一个位集合执行按位异或操作 + * @param other 另一个位集合 + * @returns 新的位集合,包含按位异或的结果 + */ + xor(other) { + const result = new Bits(); + BitMask64Utils.copy(this._value, result._value); + BitMask64Utils.xorInPlace(result._value, other._value); + return result; + } + /** + * 执行按位取反操作 + * @param maxBits 最大位数,默认为64 + * @returns 新的位集合,包含按位取反的结果 + */ + not(maxBits = 64) { + if (maxBits > 64) { + maxBits = 64; + } + const result = new Bits(); + BitMask64Utils.copy(this._value, result._value); + if (maxBits <= 32) { + const mask = (1 << maxBits) - 1; + result._value.lo = ~result._value.lo & mask; + result._value.hi = 0; + } else { + result._value.lo = ~result._value.lo; + if (maxBits < 64) { + const remainingBits = maxBits - 32; + const mask = (1 << remainingBits) - 1; + result._value.hi = ~result._value.hi & mask; + } else { + result._value.hi = ~result._value.hi; + } + } + return result; + } + /** + * 从另一个位集合复制值 + * @param other 源位集合 + */ + copyFrom(other) { + BitMask64Utils.copy(other._value, this._value); + } + /** + * 创建当前位集合的深拷贝 + * @returns 新的位集合,内容与当前位集合相同 + */ + clone() { + return new Bits(this._value); + } + /** + * 获取内部的64位掩码数据 + * @returns 内部存储的BitMask64Data对象 + */ + getValue() { + return this._value; + } + /** + * 设置位集合的值 + * @param value 新值,可以是BitMask64Data对象、数字或字符串 + */ + setValue(value) { + if (typeof value === "object") { + BitMask64Utils.copy(value, this._value); + } else if (typeof value === "number") { + this._value = BitMask64Utils.fromNumber(value); + } else { + const num = parseInt(value, 10); + this._value = BitMask64Utils.fromNumber(num); + } + } + /** + * 将位集合转换为可读字符串 + * @returns 格式为"Bits[index1, index2, ...]"的字符串 + */ + toString() { + const bits = []; + for (let i = 0; i < 64; i++) { + if (this.get(i)) { + bits.push(i.toString()); + } + } + return `Bits[${bits.join(", ")}]`; + } + /** + * 将位集合转换为二进制字符串 + * @param maxBits 最大位数,默认为64 + * @returns 二进制字符串表示,每8位用空格分隔 + */ + toBinaryString(maxBits = 64) { + if (maxBits > 64) + maxBits = 64; + let result = ""; + for (let i = maxBits - 1; i >= 0; i--) { + result += this.get(i) ? "1" : "0"; + if (i % 8 === 0 && i > 0) { + result += " "; + } + } + return result; + } + /** + * 将位集合转换为十六进制字符串 + * @returns 十六进制字符串表示,带0x前缀 + */ + toHexString() { + return BitMask64Utils.toString(this._value, 16); + } + /** + * 从二进制字符串创建位集合 + * @param binaryString 二进制字符串,可以包含空格 + * @returns 新的位集合对象 + */ + static fromBinaryString(binaryString) { + const cleanString = binaryString.replace(/\s/g, ""); + let data; + if (cleanString.length <= 32) { + const num = parseInt(cleanString, 2); + data = { lo: num >>> 0, hi: 0 }; + } else { + const loBits = cleanString.substring(cleanString.length - 32); + const hiBits = cleanString.substring(0, cleanString.length - 32); + const lo = parseInt(loBits, 2); + const hi = parseInt(hiBits, 2); + data = { lo: lo >>> 0, hi: hi >>> 0 }; + } + return new Bits(data); + } + /** + * 从十六进制字符串创建位集合 + * @param hexString 十六进制字符串,可以带或不带0x前缀 + * @returns 新的位集合对象 + */ + static fromHexString(hexString) { + const cleanString = hexString.replace(/^0x/i, ""); + let data; + if (cleanString.length <= 8) { + const num = parseInt(cleanString, 16); + data = { lo: num >>> 0, hi: 0 }; + } else { + const loBits = cleanString.substring(cleanString.length - 8); + const hiBits = cleanString.substring(0, cleanString.length - 8); + const lo = parseInt(loBits, 16); + const hi = parseInt(hiBits, 16); + data = { lo: lo >>> 0, hi: hi >>> 0 }; + } + return new Bits(data); + } + /** + * 检查是否与另一个位集合相等 + * @param other 另一个位集合 + * @returns 如果两个位集合完全相同则返回true + */ + equals(other) { + return BitMask64Utils.equals(this._value, other._value); + } + /** + * 获取最高位设置位的索引 + * @returns 最高位设置位的索引,如果位集合为空则返回-1 + */ + getHighestBitIndex() { + if (BitMask64Utils.isZero(this._value)) { + return -1; + } + if (this._value.hi !== 0) { + for (let i = 31; i >= 0; i--) { + if ((this._value.hi & 1 << i) !== 0) { + return i + 32; + } + } + } + for (let i = 31; i >= 0; i--) { + if ((this._value.lo & 1 << i) !== 0) { + return i; + } + } + return -1; + } + /** + * 获取最低位设置位的索引 + * @returns 最低位设置位的索引,如果位集合为空则返回-1 + */ + getLowestBitIndex() { + if (BitMask64Utils.isZero(this._value)) { + return -1; + } + for (let i = 0; i < 32; i++) { + if ((this._value.lo & 1 << i) !== 0) { + return i; + } + } + for (let i = 0; i < 32; i++) { + if ((this._value.hi & 1 << i) !== 0) { + return i + 32; + } + } + return -1; + } +} +class ComponentTypeManager { + /** + * 获取单例实例 + */ + static get instance() { + if (!ComponentTypeManager._instance) { + ComponentTypeManager._instance = new ComponentTypeManager(); + } + return ComponentTypeManager._instance; + } + constructor() { + this._componentTypes = /* @__PURE__ */ new Map(); + this._typeNames = /* @__PURE__ */ new Map(); + this._nextTypeId = 0; + } + /** + * 获取组件类型的ID + * @param componentType 组件类型构造函数 + * @returns 组件类型ID + */ + getTypeId(componentType) { + let typeId = this._componentTypes.get(componentType); + if (typeId === void 0) { + typeId = this._nextTypeId++; + this._componentTypes.set(componentType, typeId); + this._typeNames.set(typeId, getComponentTypeName(componentType)); + } + return typeId; + } + /** + * 获取组件类型名称 + * @param typeId 组件类型ID + * @returns 组件类型名称 + */ + getTypeName(typeId) { + return this._typeNames.get(typeId) || "Unknown"; + } + /** + * 创建包含指定组件类型的Bits对象 + * @param componentTypes 组件类型构造函数数组 + * @returns Bits对象 + */ + createBits(...componentTypes) { + const bits = new Bits(); + for (const componentType of componentTypes) { + const typeId = this.getTypeId(componentType); + bits.set(typeId); + } + return bits; + } + /** + * 获取实体的组件位掩码 + * @param components 组件数组 + * @returns Bits对象 + */ + getEntityBits(components) { + const bits = new Bits(); + for (const component of components) { + const typeId = this.getTypeId(component.constructor); + bits.set(typeId); + } + return bits; + } + /** + * 重置管理器(主要用于测试) + */ + reset() { + this._componentTypes.clear(); + this._typeNames.clear(); + this._nextTypeId = 0; + } + /** + * 获取已注册的组件类型数量 + */ + get registeredTypeCount() { + return this._componentTypes.size; + } +} +class EntityDataCollector { + /** + * 收集实体数据 + * @param scene 场景实例 + */ + collectEntityData(scene) { + if (!scene) { + return this.getEmptyEntityDebugData(); + } + const entityList = scene.entities; + if (!entityList) { + return this.getEmptyEntityDebugData(); + } + let stats; + try { + stats = entityList.getStats ? entityList.getStats() : this.calculateFallbackEntityStats(entityList); + } catch (error) { + return { + totalEntities: 0, + activeEntities: 0, + pendingAdd: 0, + pendingRemove: 0, + entitiesPerArchetype: [], + topEntitiesByComponents: [], + entityHierarchy: [], + entityDetailsMap: {} + }; + } + const archetypeData = this.collectArchetypeData(scene); + return { + totalEntities: stats.totalEntities, + activeEntities: stats.activeEntities, + pendingAdd: stats.pendingAdd || 0, + pendingRemove: stats.pendingRemove || 0, + entitiesPerArchetype: archetypeData.distribution, + topEntitiesByComponents: archetypeData.topEntities, + entityHierarchy: [], + entityDetailsMap: {} + }; + } + /** + * 获取原始实体列表 + * @param scene 场景实例 + */ + getRawEntityList(scene) { + if (!scene) + return []; + const entityList = scene.entities; + if (!entityList?.buffer) + return []; + return entityList.buffer.map((entity) => ({ + id: entity.id, + name: entity.name || `Entity_${entity.id}`, + active: entity.active !== false, + enabled: entity.enabled !== false, + activeInHierarchy: entity.activeInHierarchy !== false, + componentCount: entity.components.length, + componentTypes: entity.components.map((component) => getComponentInstanceTypeName(component)), + parentId: entity.parent?.id || null, + childIds: entity.children?.map((child) => child.id) || [], + depth: entity.getDepth ? entity.getDepth() : 0, + tag: entity.tag || 0, + updateOrder: entity.updateOrder || 0 + })); + } + /** + * 获取实体详细信息 + * @param entityId 实体ID + * @param scene 场景实例 + */ + getEntityDetails(entityId, scene) { + try { + if (!scene) + return null; + const entityList = scene.entities; + if (!entityList?.buffer) + return null; + const entity = entityList.buffer.find((e) => e.id === entityId); + if (!entity) + return null; + const baseDebugInfo = entity.getDebugInfo ? entity.getDebugInfo() : this.buildFallbackEntityInfo(entity, scene); + const componentDetails = this.extractComponentDetails(entity.components); + const sceneInfo = this.getSceneInfo(scene); + return { + ...baseDebugInfo, + scene: sceneInfo.name, + sceneName: sceneInfo.name, + sceneType: sceneInfo.type, + parentName: entity.parent?.name || null, + components: componentDetails || [], + componentCount: entity.components?.length || 0, + componentTypes: entity.components?.map((comp) => getComponentInstanceTypeName(comp)) || [] + }; + } catch (error) { + return { + error: `获取实体详情失败: ${error instanceof Error ? error.message : String(error)}`, + scene: "获取失败", + components: [], + componentCount: 0, + componentTypes: [] + }; + } + } + getSceneInfo(scene) { + let sceneName = "当前场景"; + let sceneType = "Scene"; + try { + if (scene.name && typeof scene.name === "string" && scene.name.trim()) { + sceneName = scene.name.trim(); + } else if (scene.constructor && scene.constructor.name) { + sceneName = scene.constructor.name; + sceneType = scene.constructor.name; + } else if (scene._name && typeof scene._name === "string" && scene._name.trim()) { + sceneName = scene._name.trim(); + } else { + const sceneClassName = Object.getPrototypeOf(scene)?.constructor?.name; + if (sceneClassName && sceneClassName !== "Object") { + sceneName = sceneClassName; + sceneType = sceneClassName; + } + } + } catch (error) { + sceneName = "场景名获取失败"; + } + return { name: sceneName, type: sceneType }; + } + /** + * 收集实体数据(包含内存信息) + * @param scene 场景实例 + */ + collectEntityDataWithMemory(scene) { + if (!scene) { + return this.getEmptyEntityDebugData(); + } + const entityList = scene.entities; + if (!entityList) { + return this.getEmptyEntityDebugData(); + } + let stats; + try { + stats = entityList.getStats ? entityList.getStats() : this.calculateFallbackEntityStats(entityList); + } catch (error) { + return { + totalEntities: 0, + activeEntities: 0, + pendingAdd: 0, + pendingRemove: 0, + entitiesPerArchetype: [], + topEntitiesByComponents: [], + entityHierarchy: [], + entityDetailsMap: {} + }; + } + const archetypeData = this.collectArchetypeDataWithMemory(scene); + return { + totalEntities: stats.totalEntities, + activeEntities: stats.activeEntities, + pendingAdd: stats.pendingAdd || 0, + pendingRemove: stats.pendingRemove || 0, + entitiesPerArchetype: archetypeData.distribution, + topEntitiesByComponents: archetypeData.topEntities, + entityHierarchy: this.buildEntityHierarchyTree(entityList), + entityDetailsMap: this.buildEntityDetailsMap(entityList, scene) + }; + } + collectArchetypeData(scene) { + if (scene && scene.archetypeSystem && typeof scene.archetypeSystem.getAllArchetypes === "function") { + return this.extractArchetypeStatistics(scene.archetypeSystem); + } + const entityContainer = { entities: scene.entities?.buffer || [] }; + return { + distribution: this.getArchetypeDistributionFast(entityContainer), + topEntities: this.getTopEntitiesByComponentsFast(entityContainer) + }; + } + getArchetypeDistributionFast(entityContainer) { + const distribution = /* @__PURE__ */ new Map(); + if (entityContainer && entityContainer.entities) { + entityContainer.entities.forEach((entity) => { + const componentTypes = entity.components?.map((comp) => getComponentInstanceTypeName(comp)) || []; + const signature = componentTypes.length > 0 ? componentTypes.sort().join(", ") : "无组件"; + const existing = distribution.get(signature); + if (existing) { + existing.count++; + } else { + distribution.set(signature, { count: 1, componentTypes }); + } + }); + } + return Array.from(distribution.entries()).map(([signature, data]) => ({ + signature, + count: data.count, + memory: 0 + })).sort((a, b) => b.count - a.count).slice(0, 20); + } + getTopEntitiesByComponentsFast(entityContainer) { + if (!entityContainer || !entityContainer.entities) { + return []; + } + return entityContainer.entities.map((entity) => ({ + id: entity.id.toString(), + name: entity.name || `Entity_${entity.id}`, + componentCount: entity.components?.length || 0, + memory: 0 + })).sort((a, b) => b.componentCount - a.componentCount).slice(0, 10); + } + collectArchetypeDataWithMemory(scene) { + if (scene && scene.archetypeSystem && typeof scene.archetypeSystem.getAllArchetypes === "function") { + return this.extractArchetypeStatisticsWithMemory(scene.archetypeSystem); + } + const entityContainer = { entities: scene.entities?.buffer || [] }; + return { + distribution: this.getArchetypeDistributionWithMemory(entityContainer), + topEntities: this.getTopEntitiesByComponentsWithMemory(entityContainer) + }; + } + extractArchetypeStatistics(archetypeSystem) { + const archetypes = archetypeSystem.getAllArchetypes(); + const distribution = []; + const topEntities = []; + archetypes.forEach((archetype) => { + const signature = archetype.componentTypes?.map((type) => type.name).join(",") || "Unknown"; + const entityCount = archetype.entities?.length || 0; + distribution.push({ + signature, + count: entityCount, + memory: 0 + }); + if (archetype.entities) { + archetype.entities.slice(0, 5).forEach((entity) => { + topEntities.push({ + id: entity.id.toString(), + name: entity.name || `Entity_${entity.id}`, + componentCount: entity.components?.length || 0, + memory: 0 + }); + }); + } + }); + distribution.sort((a, b) => b.count - a.count); + topEntities.sort((a, b) => b.componentCount - a.componentCount); + return { distribution, topEntities }; + } + extractArchetypeStatisticsWithMemory(archetypeSystem) { + const archetypes = archetypeSystem.getAllArchetypes(); + const distribution = []; + const topEntities = []; + archetypes.forEach((archetype) => { + const signature = archetype.componentTypes?.map((type) => type.name).join(",") || "Unknown"; + const entityCount = archetype.entities?.length || 0; + let actualMemory = 0; + if (archetype.entities && archetype.entities.length > 0) { + const sampleSize = Math.min(5, archetype.entities.length); + let sampleMemory = 0; + for (let i = 0; i < sampleSize; i++) { + sampleMemory += this.estimateEntityMemoryUsage(archetype.entities[i]); + } + actualMemory = sampleMemory / sampleSize * entityCount; + } + distribution.push({ + signature, + count: entityCount, + memory: actualMemory + }); + if (archetype.entities) { + archetype.entities.slice(0, 5).forEach((entity) => { + topEntities.push({ + id: entity.id.toString(), + name: entity.name || `Entity_${entity.id}`, + componentCount: entity.components?.length || 0, + memory: this.estimateEntityMemoryUsage(entity) + }); + }); + } + }); + distribution.sort((a, b) => b.count - a.count); + topEntities.sort((a, b) => b.componentCount - a.componentCount); + return { distribution, topEntities }; + } + getArchetypeDistribution(entityContainer) { + const distribution = /* @__PURE__ */ new Map(); + if (entityContainer && entityContainer.entities) { + entityContainer.entities.forEach((entity) => { + const signature = entity.componentMask?.toString() || "0"; + const existing = distribution.get(signature); + distribution.set(signature, (existing || 0) + 1); + }); + } + return Array.from(distribution.entries()).map(([signature, count]) => ({ signature, count, memory: 0 })).sort((a, b) => b.count - a.count); + } + getArchetypeDistributionWithMemory(entityContainer) { + const distribution = /* @__PURE__ */ new Map(); + if (entityContainer && entityContainer.entities) { + entityContainer.entities.forEach((entity) => { + const componentTypes = entity.components?.map((comp) => getComponentInstanceTypeName(comp)) || []; + const signature = componentTypes.length > 0 ? componentTypes.sort().join(", ") : "无组件"; + const existing = distribution.get(signature); + let memory = this.estimateEntityMemoryUsage(entity); + if (isNaN(memory) || memory < 0) { + memory = 0; + } + if (existing) { + existing.count++; + existing.memory += memory; + } else { + distribution.set(signature, { count: 1, memory, componentTypes }); + } + }); + } + return Array.from(distribution.entries()).map(([signature, data]) => ({ + signature, + count: data.count, + memory: isNaN(data.memory) ? 0 : data.memory + })).sort((a, b) => b.count - a.count); + } + getTopEntitiesByComponents(entityContainer) { + if (!entityContainer || !entityContainer.entities) { + return []; + } + return entityContainer.entities.map((entity) => ({ + id: entity.id.toString(), + name: entity.name || `Entity_${entity.id}`, + componentCount: entity.components?.length || 0, + memory: 0 + })).sort((a, b) => b.componentCount - a.componentCount); + } + getTopEntitiesByComponentsWithMemory(entityContainer) { + if (!entityContainer || !entityContainer.entities) { + return []; + } + return entityContainer.entities.map((entity) => ({ + id: entity.id.toString(), + name: entity.name || `Entity_${entity.id}`, + componentCount: entity.components?.length || 0, + memory: this.estimateEntityMemoryUsage(entity) + })).sort((a, b) => b.componentCount - a.componentCount); + } + getEmptyEntityDebugData() { + return { + totalEntities: 0, + activeEntities: 0, + pendingAdd: 0, + pendingRemove: 0, + entitiesPerArchetype: [], + topEntitiesByComponents: [], + entityHierarchy: [], + entityDetailsMap: {} + }; + } + calculateFallbackEntityStats(entityList) { + const allEntities = entityList.buffer || []; + const activeEntities = allEntities.filter((entity) => entity.enabled && !entity._isDestroyed); + return { + totalEntities: allEntities.length, + activeEntities: activeEntities.length, + pendingAdd: 0, + pendingRemove: 0, + averageComponentsPerEntity: activeEntities.length > 0 ? allEntities.reduce((sum, e) => sum + (e.components?.length || 0), 0) / activeEntities.length : 0 + }; + } + estimateEntityMemoryUsage(entity) { + try { + let totalSize = 0; + const entitySize = this.calculateObjectSize(entity, ["components", "children", "parent"]); + if (!isNaN(entitySize) && entitySize > 0) { + totalSize += entitySize; + } + if (entity.components && Array.isArray(entity.components)) { + entity.components.forEach((component) => { + const componentSize = this.calculateObjectSize(component, ["entity"]); + if (!isNaN(componentSize) && componentSize > 0) { + totalSize += componentSize; + } + }); + } + return isNaN(totalSize) || totalSize < 0 ? 0 : totalSize; + } catch (error) { + return 0; + } + } + calculateObjectSize(obj, excludeKeys = []) { + if (!obj || typeof obj !== "object") + return 0; + const visited = /* @__PURE__ */ new WeakSet(); + const maxDepth = 2; + const calculate = (item, depth = 0) => { + if (!item || typeof item !== "object" || depth >= maxDepth) { + return 0; + } + if (visited.has(item)) + return 0; + visited.add(item); + let itemSize = 32; + try { + const keys = Object.keys(item); + const maxKeys = Math.min(keys.length, 20); + for (let i = 0; i < maxKeys; i++) { + const key = keys[i]; + if (excludeKeys.includes(key) || key === "constructor" || key === "__proto__" || key.startsWith("_cc_") || key.startsWith("__")) { + continue; + } + const value = item[key]; + itemSize += key.length * 2; + if (typeof value === "string") { + itemSize += Math.min(value.length * 2, 200); + } else if (typeof value === "number") { + itemSize += 8; + } else if (typeof value === "boolean") { + itemSize += 4; + } else if (Array.isArray(value)) { + itemSize += 40 + Math.min(value.length * 8, 160); + } else if (typeof value === "object" && value !== null) { + itemSize += calculate(value, depth + 1); + } + } + } catch (error) { + return 64; + } + return itemSize; + }; + try { + const size = calculate(obj); + return Math.max(size, 32); + } catch (error) { + return 64; + } + } + buildEntityHierarchyTree(entityList) { + if (!entityList?.buffer) + return []; + const rootEntities = []; + entityList.buffer.forEach((entity) => { + if (!entity.parent) { + const hierarchyNode = this.buildEntityHierarchyNode(entity); + rootEntities.push(hierarchyNode); + } + }); + rootEntities.sort((nodeA, nodeB) => { + if (nodeA.name < nodeB.name) + return -1; + if (nodeA.name > nodeB.name) + return 1; + return nodeA.id - nodeB.id; + }); + return rootEntities; + } + /** + * 构建实体层次结构节点 + */ + buildEntityHierarchyNode(entity) { + let node = { + id: entity.id, + name: entity.name || `Entity_${entity.id}`, + active: entity.active !== false, + enabled: entity.enabled !== false, + activeInHierarchy: entity.activeInHierarchy !== false, + componentCount: entity.components.length, + componentTypes: entity.components.map((component) => getComponentInstanceTypeName(component)), + parentId: entity.parent?.id || null, + children: [], + depth: entity.getDepth ? entity.getDepth() : 0, + tag: entity.tag || 0, + updateOrder: entity.updateOrder || 0 + }; + if (entity.children && entity.children.length > 0) { + node.children = entity.children.map((child) => this.buildEntityHierarchyNode(child)); + } + if (typeof entity.getDebugInfo === "function") { + const debugInfo = entity.getDebugInfo(); + node = { + ...node, + ...debugInfo + }; + } + if (entity.components && entity.components.length > 0) { + node.componentDetails = this.extractComponentDetails(entity.components); + } + return node; + } + /** + * 构建实体详情映射 + */ + buildEntityDetailsMap(entityList, scene) { + if (!entityList?.buffer) + return {}; + const entityDetailsMap = {}; + const entities = entityList.buffer; + const batchSize = 100; + for (let i = 0; i < entities.length; i += batchSize) { + const batch = entities.slice(i, i + batchSize); + batch.forEach((entity) => { + const baseDebugInfo = entity.getDebugInfo ? entity.getDebugInfo() : this.buildFallbackEntityInfo(entity, scene); + const componentCacheStats = entity.getComponentCacheStats ? entity.getComponentCacheStats() : null; + const componentDetails = this.extractComponentDetails(entity.components); + entityDetailsMap[entity.id] = { + ...baseDebugInfo, + parentName: entity.parent?.name || null, + components: componentDetails, + componentTypes: baseDebugInfo.componentTypes || componentDetails.map((comp) => comp.typeName), + cachePerformance: componentCacheStats ? { + hitRate: componentCacheStats.cacheStats.hitRate, + size: componentCacheStats.cacheStats.size, + maxSize: componentCacheStats.cacheStats.maxSize + } : null + }; + }); + } + return entityDetailsMap; + } + /** + * 构建实体基础信息 + */ + buildFallbackEntityInfo(entity, scene) { + const sceneInfo = this.getSceneInfo(scene); + return { + name: entity.name || `Entity_${entity.id}`, + id: entity.id, + enabled: entity.enabled !== false, + active: entity.active !== false, + activeInHierarchy: entity.activeInHierarchy !== false, + destroyed: entity.isDestroyed || false, + scene: sceneInfo.name, + sceneName: sceneInfo.name, + sceneType: sceneInfo.type, + componentCount: entity.components.length, + componentTypes: entity.components.map((component) => getComponentInstanceTypeName(component)), + componentMask: entity.componentMask?.toString() || "0", + parentId: entity.parent?.id || null, + childCount: entity.children?.length || 0, + childIds: entity.children.map((child) => child.id) || [], + depth: entity.getDepth ? entity.getDepth() : 0, + tag: entity.tag || 0, + updateOrder: entity.updateOrder || 0 + }; + } + /** + * 提取组件详细信息 + */ + extractComponentDetails(components) { + return components.map((component) => { + let typeName = getComponentInstanceTypeName(component); + if (!typeName || typeName === "Object" || typeName === "Function") { + try { + const typeManager = ComponentTypeManager.instance; + const componentType = component.constructor; + const typeId = typeManager.getTypeId(componentType); + typeName = typeManager.getTypeName(typeId); + } catch (error) { + typeName = "UnknownComponent"; + } + } + const properties = {}; + try { + const propertyKeys = Object.keys(component); + propertyKeys.forEach((propertyKey) => { + if (!propertyKey.startsWith("_") && propertyKey !== "entity" && propertyKey !== "constructor") { + const propertyValue = component[propertyKey]; + if (propertyValue !== void 0 && propertyValue !== null) { + properties[propertyKey] = this.formatPropertyValue(propertyValue); + } + } + }); + if (Object.keys(properties).length === 0) { + properties._info = "该组件没有公开属性"; + properties._componentId = getComponentInstanceTypeName(component); + } + } catch (error) { + properties._error = "属性提取失败"; + properties._componentId = getComponentInstanceTypeName(component); + } + return { + typeName, + properties + }; + }); + } + /** + * 获取组件的完整属性信息(仅在需要时调用) + * @param entityId 实体ID + * @param componentIndex 组件索引 + * @param scene 场景实例 + */ + getComponentProperties(entityId, componentIndex, scene) { + try { + if (!scene) + return {}; + const entityList = scene.entities; + if (!entityList?.buffer) + return {}; + const entity = entityList.buffer.find((e) => e.id === entityId); + if (!entity || componentIndex >= entity.components.length) + return {}; + const component = entity.components[componentIndex]; + const properties = {}; + const propertyKeys = Object.keys(component); + propertyKeys.forEach((propertyKey) => { + if (!propertyKey.startsWith("_") && propertyKey !== "entity") { + const propertyValue = component[propertyKey]; + if (propertyValue !== void 0 && propertyValue !== null) { + properties[propertyKey] = this.formatPropertyValue(propertyValue); + } + } + }); + return properties; + } catch (error) { + return { _error: "属性提取失败" }; + } + } + /** + * 格式化属性值 + */ + formatPropertyValue(value, depth = 0) { + if (value === null || value === void 0) { + return value; + } + if (typeof value !== "object") { + if (typeof value === "string" && value.length > 200) { + return `[长字符串: ${value.length}字符] ${value.substring(0, 100)}...`; + } + return value; + } + if (depth === 0) { + return this.formatObjectFirstLevel(value); + } else { + return this.createLazyLoadPlaceholder(value); + } + } + /** + * 格式化对象第一层 + */ + formatObjectFirstLevel(obj) { + try { + if (Array.isArray(obj)) { + if (obj.length === 0) + return []; + if (obj.length > 10) { + const sample = obj.slice(0, 3).map((item) => this.formatPropertyValue(item, 1)); + return { + _isLazyArray: true, + _arrayLength: obj.length, + _sample: sample, + _summary: `数组[${obj.length}个元素]` + }; + } + return obj.map((item) => this.formatPropertyValue(item, 1)); + } + const keys = Object.keys(obj); + if (keys.length === 0) + return {}; + const result = {}; + let processedCount = 0; + const maxProperties = 15; + for (const key of keys) { + if (processedCount >= maxProperties) { + result._hasMoreProperties = true; + result._totalProperties = keys.length; + result._hiddenCount = keys.length - processedCount; + break; + } + if (key.startsWith("_") || key.startsWith("$") || typeof obj[key] === "function") { + continue; + } + try { + const value = obj[key]; + if (value !== null && value !== void 0) { + result[key] = this.formatPropertyValue(value, 1); + processedCount++; + } + } catch (error) { + result[key] = `[访问失败: ${error instanceof Error ? error.message : String(error)}]`; + processedCount++; + } + } + return result; + } catch (error) { + return `[对象解析失败: ${error instanceof Error ? error.message : String(error)}]`; + } + } + /** + * 创建懒加载占位符 + */ + createLazyLoadPlaceholder(obj) { + try { + const typeName = obj.constructor?.name || "Object"; + const summary = this.getObjectSummary(obj, typeName); + return { + _isLazyObject: true, + _typeName: typeName, + _summary: summary, + _objectId: this.generateObjectId(obj) + }; + } catch (error) { + return { + _isLazyObject: true, + _typeName: "Unknown", + _summary: `无法分析的对象: ${error instanceof Error ? error.message : String(error)}`, + _objectId: Math.random().toString(36).substr(2, 9) + }; + } + } + /** + * 获取对象摘要信息 + */ + getObjectSummary(obj, typeName) { + try { + if (typeName.toLowerCase().includes("vec") || typeName.toLowerCase().includes("vector")) { + if (obj.x !== void 0 && obj.y !== void 0) { + const z = obj.z !== void 0 ? obj.z : ""; + return `${typeName}(${obj.x}, ${obj.y}${z ? ", " + z : ""})`; + } + } + if (typeName.toLowerCase().includes("color")) { + if (obj.r !== void 0 && obj.g !== void 0 && obj.b !== void 0) { + const a = obj.a !== void 0 ? obj.a : 1; + return `${typeName}(${obj.r}, ${obj.g}, ${obj.b}, ${a})`; + } + } + if (typeName.toLowerCase().includes("node")) { + const name = obj.name || obj._name || "未命名"; + return `${typeName}: ${name}`; + } + if (typeName.toLowerCase().includes("component")) { + const nodeName = obj.node?.name || obj.node?._name || ""; + return `${typeName}${nodeName ? ` on ${nodeName}` : ""}`; + } + const keys = Object.keys(obj); + if (keys.length === 0) { + return `${typeName} (空对象)`; + } + return `${typeName} (${keys.length}个属性)`; + } catch (error) { + return `${typeName} (无法分析)`; + } + } + /** + * 生成对象ID + */ + generateObjectId(obj) { + try { + if (obj.id !== void 0) + return `obj_${obj.id}`; + if (obj._id !== void 0) + return `obj_${obj._id}`; + if (obj.uuid !== void 0) + return `obj_${obj.uuid}`; + if (obj._uuid !== void 0) + return `obj_${obj._uuid}`; + return `obj_${Math.random().toString(36).substr(2, 9)}`; + } catch { + return `obj_${Math.random().toString(36).substr(2, 9)}`; + } + } + /** + * 展开懒加载对象(供调试面板调用) + * @param entityId 实体ID + * @param componentIndex 组件索引 + * @param propertyPath 属性路径 + * @param scene 场景实例 + */ + expandLazyObject(entityId, componentIndex, propertyPath, scene) { + try { + if (!scene) + return null; + const entityList = scene.entities; + if (!entityList?.buffer) + return null; + const entity = entityList.buffer.find((e) => e.id === entityId); + if (!entity) + return null; + if (componentIndex >= entity.components.length) + return null; + const component = entity.components[componentIndex]; + const targetObject = this.getObjectByPath(component, propertyPath); + if (!targetObject) + return null; + return this.formatObjectFirstLevel(targetObject); + } catch (error) { + return { + error: `展开失败: ${error instanceof Error ? error.message : String(error)}` + }; + } + } + /** + * 根据路径获取对象 + */ + getObjectByPath(root, path) { + if (!path) + return root; + const parts = path.split("."); + let current = root; + for (const part of parts) { + if (current === null || current === void 0) + return null; + if (part.includes("[") && part.includes("]")) { + const arrayName = part.substring(0, part.indexOf("[")); + const index = parseInt(part.substring(part.indexOf("[") + 1, part.indexOf("]"))); + if (arrayName) { + current = current[arrayName]; + } + if (Array.isArray(current) && index >= 0 && index < current.length) { + current = current[index]; + } else { + return null; + } + } else { + current = current[part]; + } + } + return current; + } +} +class SystemDataCollector { + /** + * 收集系统数据 + * @param performanceMonitor 性能监视器实例 + * @param scene 场景实例 + */ + collectSystemData(performanceMonitor, scene) { + if (!scene) { + return { + totalSystems: 0, + systemsInfo: [] + }; + } + const entityProcessors = scene.entityProcessors; + if (!entityProcessors) { + return { + totalSystems: 0, + systemsInfo: [] + }; + } + const systems = entityProcessors.processors || []; + let systemStats = /* @__PURE__ */ new Map(); + let systemData = /* @__PURE__ */ new Map(); + if (performanceMonitor) { + try { + systemStats = performanceMonitor.getAllSystemStats(); + systemData = performanceMonitor.getAllSystemData(); + } catch (error) { + } + } + return { + totalSystems: systems.length, + systemsInfo: systems.map((system) => { + const systemName = system.systemName || getSystemInstanceTypeName(system); + const stats = systemStats.get(systemName); + const data = systemData.get(systemName); + return { + name: systemName, + type: getSystemInstanceTypeName(system), + entityCount: system.entities?.length || 0, + executionTime: stats?.averageTime || data?.executionTime || 0, + minExecutionTime: stats?.minTime === Number.MAX_VALUE ? 0 : stats?.minTime || 0, + maxExecutionTime: stats?.maxTime || 0, + executionTimeHistory: stats?.recentTimes || [], + updateOrder: system.updateOrder || 0, + enabled: system.enabled !== false, + lastUpdateTime: data?.lastUpdateTime || 0 + }; + }) + }; + } +} +class PerformanceDataCollector { + constructor() { + this.frameTimeHistory = []; + this.maxHistoryLength = 60; + this.lastGCCount = 0; + this.gcCollections = 0; + this.lastMemoryCheck = 0; + } + /** + * 收集性能数据 + */ + collectPerformanceData(performanceMonitor) { + const frameTimeSeconds = Time.deltaTime; + const engineFrameTimeMs = frameTimeSeconds * 1e3; + const currentFps = frameTimeSeconds > 0 ? Math.round(1 / frameTimeSeconds) : 0; + const ecsPerformanceData = this.getECSPerformanceData(performanceMonitor); + const ecsExecutionTimeMs = ecsPerformanceData.totalExecutionTime; + const ecsPercentage = engineFrameTimeMs > 0 ? ecsExecutionTimeMs / engineFrameTimeMs * 100 : 0; + let memoryUsage = 0; + if (performance.memory) { + memoryUsage = performance.memory.usedJSHeapSize / 1024 / 1024; + } + this.frameTimeHistory.push(ecsExecutionTimeMs); + if (this.frameTimeHistory.length > this.maxHistoryLength) { + this.frameTimeHistory.shift(); + } + const history = this.frameTimeHistory.filter((t) => t >= 0); + const averageECSTime = history.length > 0 ? history.reduce((a, b) => a + b, 0) / history.length : ecsExecutionTimeMs; + const minECSTime = history.length > 0 ? Math.min(...history) : ecsExecutionTimeMs; + const maxECSTime = history.length > 0 ? Math.max(...history) : ecsExecutionTimeMs; + return { + frameTime: ecsExecutionTimeMs, + engineFrameTime: engineFrameTimeMs, + ecsPercentage, + memoryUsage, + fps: currentFps, + averageFrameTime: averageECSTime, + minFrameTime: minECSTime, + maxFrameTime: maxECSTime, + frameTimeHistory: [...this.frameTimeHistory], + systemPerformance: this.getSystemPerformance(performanceMonitor), + systemBreakdown: ecsPerformanceData.systemBreakdown, + memoryDetails: this.getMemoryDetails() + }; + } + /** + * 获取ECS框架整体性能数据 + */ + getECSPerformanceData(performanceMonitor) { + if (!performanceMonitor) { + return { totalExecutionTime: 0, systemBreakdown: [] }; + } + if (!performanceMonitor.enabled) { + try { + performanceMonitor.enabled = true; + } catch (error) { + } + return { totalExecutionTime: 0, systemBreakdown: [] }; + } + try { + let totalTime = 0; + const systemBreakdown = []; + const stats = performanceMonitor.getAllSystemStats(); + if (stats.size === 0) { + return { totalExecutionTime: 0, systemBreakdown: [] }; + } + for (const [systemName, stat] of stats.entries()) { + const systemTime = stat.recentTimes && stat.recentTimes.length > 0 ? stat.recentTimes[stat.recentTimes.length - 1] : stat.averageTime || 0; + totalTime += systemTime; + systemBreakdown.push({ + systemName, + executionTime: systemTime, + percentage: 0 + // 后面计算 + }); + } + systemBreakdown.forEach((system) => { + system.percentage = totalTime > 0 ? system.executionTime / totalTime * 100 : 0; + }); + systemBreakdown.sort((a, b) => b.executionTime - a.executionTime); + return { + totalExecutionTime: totalTime, + systemBreakdown + }; + } catch (error) { + return { totalExecutionTime: 0, systemBreakdown: [] }; + } + } + /** + * 获取系统性能数据 + */ + getSystemPerformance(performanceMonitor) { + if (!performanceMonitor) { + return []; + } + try { + const stats = performanceMonitor.getAllSystemStats(); + const systemData = performanceMonitor.getAllSystemData(); + return Array.from(stats.entries()).map(([systemName, stat]) => { + const data = systemData.get(systemName); + return { + systemName, + averageTime: stat.averageTime || 0, + maxTime: stat.maxTime || 0, + minTime: stat.minTime === Number.MAX_VALUE ? 0 : stat.minTime || 0, + samples: stat.executionCount || 0, + percentage: 0, + entityCount: data?.entityCount || 0, + lastExecutionTime: data?.executionTime || 0 + }; + }); + } catch (error) { + return []; + } + } + /** + * 获取内存详情 + */ + getMemoryDetails() { + const memoryInfo = { + entities: 0, + components: 0, + systems: 0, + pooled: 0, + totalMemory: 0, + usedMemory: 0, + freeMemory: 0, + gcCollections: this.updateGCCount() + }; + try { + if (performance.memory) { + const perfMemory = performance.memory; + memoryInfo.totalMemory = perfMemory.jsHeapSizeLimit || 512 * 1024 * 1024; + memoryInfo.usedMemory = perfMemory.usedJSHeapSize || 0; + memoryInfo.freeMemory = memoryInfo.totalMemory - memoryInfo.usedMemory; + if (this.lastMemoryCheck > 0) { + const memoryDrop = this.lastMemoryCheck - memoryInfo.usedMemory; + if (memoryDrop > 1024 * 1024) { + this.gcCollections++; + } + } + this.lastMemoryCheck = memoryInfo.usedMemory; + } else { + memoryInfo.totalMemory = 512 * 1024 * 1024; + memoryInfo.freeMemory = 512 * 1024 * 1024; + } + } catch (error) { + return { + totalMemory: 0, + usedMemory: 0, + freeMemory: 0, + entityMemory: 0, + componentMemory: 0, + systemMemory: 0, + pooledMemory: 0, + gcCollections: this.gcCollections + }; + } + return memoryInfo; + } + /** + * 更新GC计数 + */ + updateGCCount() { + try { + if (typeof PerformanceObserver !== "undefined") { + return this.gcCollections; + } + if (performance.measureUserAgentSpecificMemory) { + return this.gcCollections; + } + return this.gcCollections; + } catch (error) { + return this.gcCollections; + } + } +} +class ComponentPool { + constructor(createFn, resetFn, maxSize = 1e3) { + this.pool = []; + this.createFn = createFn; + this.resetFn = resetFn; + this.maxSize = maxSize; + } + /** + * 获取一个组件实例 + */ + acquire() { + if (this.pool.length > 0) { + return this.pool.pop(); + } + return this.createFn(); + } + /** + * 释放一个组件实例回池中 + */ + release(component) { + if (this.pool.length < this.maxSize) { + if (this.resetFn) { + this.resetFn(component); + } + this.pool.push(component); + } + } + /** + * 预填充对象池 + */ + prewarm(count) { + for (let i = 0; i < count && this.pool.length < this.maxSize; i++) { + this.pool.push(this.createFn()); + } + } + /** + * 清空对象池 + */ + clear() { + this.pool.length = 0; + } + /** + * 获取池中可用对象数量 + */ + getAvailableCount() { + return this.pool.length; + } + /** + * 获取池的最大容量 + */ + getMaxSize() { + return this.maxSize; + } +} +class ComponentPoolManager { + constructor() { + this.pools = /* @__PURE__ */ new Map(); + } + static getInstance() { + if (!ComponentPoolManager.instance) { + ComponentPoolManager.instance = new ComponentPoolManager(); + } + return ComponentPoolManager.instance; + } + /** + * 注册组件池 + */ + registerPool(componentName, createFn, resetFn, maxSize) { + this.pools.set(componentName, new ComponentPool(createFn, resetFn, maxSize)); + } + /** + * 获取组件实例 + */ + acquireComponent(componentName) { + const pool = this.pools.get(componentName); + return pool ? pool.acquire() : null; + } + /** + * 释放组件实例 + */ + releaseComponent(componentName, component) { + const pool = this.pools.get(componentName); + if (pool) { + pool.release(component); + } + } + /** + * 预热所有池 + */ + prewarmAll(count = 100) { + for (const pool of this.pools.values()) { + pool.prewarm(count); + } + } + /** + * 清空所有池 + */ + clearAll() { + for (const pool of this.pools.values()) { + pool.clear(); + } + } + /** + * 重置管理器,移除所有注册的池 + */ + reset() { + this.pools.clear(); + } + /** + * 获取池统计信息 + */ + getPoolStats() { + const stats = /* @__PURE__ */ new Map(); + for (const [name, pool] of this.pools) { + stats.set(name, { + available: pool.getAvailableCount(), + maxSize: pool.getMaxSize() + }); + } + return stats; + } + /** + * 获取池利用率信息(用于调试) + */ + getPoolUtilization() { + const utilization = /* @__PURE__ */ new Map(); + for (const [name, pool] of this.pools) { + const available = pool.getAvailableCount(); + const maxSize = pool.getMaxSize(); + const used = maxSize - available; + const utilRate = maxSize > 0 ? used / maxSize * 100 : 0; + utilization.set(name, { + used, + total: maxSize, + utilization: utilRate + }); + } + return utilization; + } + /** + * 获取指定组件的池利用率 + */ + getComponentUtilization(componentName) { + const pool = this.pools.get(componentName); + if (!pool) + return 0; + const available = pool.getAvailableCount(); + const maxSize = pool.getMaxSize(); + const used = maxSize - available; + return maxSize > 0 ? used / maxSize * 100 : 0; + } +} +class ComponentDataCollector { + /** + * 收集组件数据(轻量版,不计算实际内存大小) + * @param scene 场景实例 + */ + collectComponentData(scene) { + if (!scene) { + return { + componentTypes: 0, + componentInstances: 0, + componentStats: [] + }; + } + const entityList = scene.entities; + if (!entityList?.buffer) { + return { + componentTypes: 0, + componentInstances: 0, + componentStats: [] + }; + } + const componentStats = /* @__PURE__ */ new Map(); + let totalInstances = 0; + entityList.buffer.forEach((entity) => { + if (entity.components) { + entity.components.forEach((component) => { + const typeName = getComponentInstanceTypeName(component); + const stats = componentStats.get(typeName) || { count: 0, entities: 0 }; + stats.count++; + totalInstances++; + componentStats.set(typeName, stats); + }); + } + }); + let poolUtilizations = /* @__PURE__ */ new Map(); + let poolSizes = /* @__PURE__ */ new Map(); + try { + const poolManager = ComponentPoolManager.getInstance(); + const poolStats = poolManager.getPoolStats(); + const utilizations = poolManager.getPoolUtilization(); + for (const [typeName, stats] of poolStats.entries()) { + poolSizes.set(typeName, stats.maxSize); + } + for (const [typeName, util] of utilizations.entries()) { + poolUtilizations.set(typeName, util.utilization); + } + } catch (error) { + } + return { + componentTypes: componentStats.size, + componentInstances: totalInstances, + componentStats: Array.from(componentStats.entries()).map(([typeName, stats]) => { + const poolSize = poolSizes.get(typeName) || 0; + const poolUtilization = poolUtilizations.get(typeName) || 0; + const memoryPerInstance = this.getEstimatedComponentSize(typeName, scene); + return { + typeName, + instanceCount: stats.count, + memoryPerInstance, + totalMemory: stats.count * memoryPerInstance, + poolSize, + poolUtilization, + averagePerEntity: stats.count / entityList.buffer.length + }; + }) + }; + } + /** + * 获取组件类型的估算内存大小(基于预设值,不进行实际计算) + */ + getEstimatedComponentSize(typeName, scene) { + if (ComponentDataCollector.componentSizeCache.has(typeName)) { + return ComponentDataCollector.componentSizeCache.get(typeName); + } + if (!scene) + return 64; + const entityList = scene.entities; + if (!entityList?.buffer) + return 64; + let calculatedSize = 64; + try { + for (const entity of entityList.buffer) { + if (entity.components) { + const component = entity.components.find((c) => getComponentInstanceTypeName(c) === typeName); + if (component) { + calculatedSize = this.calculateQuickObjectSize(component); + break; + } + } + } + } catch (error) { + calculatedSize = 64; + } + ComponentDataCollector.componentSizeCache.set(typeName, calculatedSize); + return calculatedSize; + } + calculateQuickObjectSize(obj) { + if (!obj || typeof obj !== "object") + return 8; + let size = 32; + const visited = /* @__PURE__ */ new WeakSet(); + const calculate = (item, depth = 0) => { + if (!item || typeof item !== "object" || visited.has(item) || depth > 3) { + return 0; + } + visited.add(item); + let itemSize = 0; + try { + const keys = Object.keys(item); + for (let i = 0; i < Math.min(keys.length, 20); i++) { + const key = keys[i]; + if (key === "entity" || key === "_entity" || key === "constructor") + continue; + const value = item[key]; + itemSize += key.length * 2; + if (typeof value === "string") { + itemSize += Math.min(value.length * 2, 200); + } else if (typeof value === "number") { + itemSize += 8; + } else if (typeof value === "boolean") { + itemSize += 4; + } else if (typeof value === "object" && value !== null) { + itemSize += calculate(value, depth + 1); + } + } + } catch (error) { + return 32; + } + return itemSize; + }; + size += calculate(obj); + return Math.max(size, 32); + } + /** + * 为内存快照功能提供的详细内存计算 + * 只在用户主动请求内存快照时调用 + * @param typeName 组件类型名称 + * @param scene 场景实例 + */ + calculateDetailedComponentMemory(typeName, scene) { + if (!scene) + return this.getEstimatedComponentSize(typeName, scene); + const entityList = scene.entities; + if (!entityList?.buffer) + return this.getEstimatedComponentSize(typeName, scene); + try { + for (const entity of entityList.buffer) { + if (entity.components) { + const component = entity.components.find((c) => getComponentInstanceTypeName(c) === typeName); + if (component) { + return this.estimateObjectSize(component); + } + } + } + } catch (error) { + } + return this.getEstimatedComponentSize(typeName, scene); + } + /** + * 估算对象内存大小(仅用于内存快照) + * 优化版本:减少递归深度,提高性能 + */ + estimateObjectSize(obj, visited = /* @__PURE__ */ new WeakSet(), depth = 0) { + if (obj === null || obj === void 0 || depth > 10) + return 0; + if (visited.has(obj)) + return 0; + let size = 0; + const type = typeof obj; + switch (type) { + case "boolean": + size = 4; + break; + case "number": + size = 8; + break; + case "string": + size = 24 + Math.min(obj.length * 2, 1e3); + break; + case "object": + visited.add(obj); + if (Array.isArray(obj)) { + size = 40 + obj.length * 8; + const maxElements = Math.min(obj.length, 50); + for (let i = 0; i < maxElements; i++) { + size += this.estimateObjectSize(obj[i], visited, depth + 1); + } + } else { + size = 32; + try { + const ownKeys = Object.getOwnPropertyNames(obj); + const maxProps = Math.min(ownKeys.length, 30); + for (let i = 0; i < maxProps; i++) { + const key = ownKeys[i]; + if (key === "constructor" || key === "__proto__" || key === "entity" || key === "_entity" || key.startsWith("_cc_") || key.startsWith("__")) { + continue; + } + try { + size += 16 + key.length * 2; + const value = obj[key]; + if (value !== void 0 && value !== null) { + size += this.estimateObjectSize(value, visited, depth + 1); + } + } catch (error) { + continue; + } + } + } catch (error) { + size = 128; + } + } + break; + default: + size = 8; + } + return Math.ceil(size / 8) * 8; + } + static clearCache() { + ComponentDataCollector.componentSizeCache.clear(); + } +} +ComponentDataCollector.componentSizeCache = /* @__PURE__ */ new Map(); +class SceneDataCollector { + constructor() { + this.sceneStartTime = Date.now(); + } + /** + * 收集场景数据 + * @param scene 场景实例 + */ + collectSceneData(scene) { + if (!scene) { + return { + currentSceneName: "No Scene", + isInitialized: false, + sceneRunTime: 0, + sceneEntityCount: 0, + sceneSystemCount: 0, + sceneMemory: 0, + sceneUptime: 0 + }; + } + const currentTime = Date.now(); + const runTime = (currentTime - this.sceneStartTime) / 1e3; + const entityList = scene.entities; + const entityProcessors = scene.entityProcessors; + return { + currentSceneName: scene.name || "Unnamed Scene", + isInitialized: scene._didSceneBegin || false, + sceneRunTime: runTime, + sceneEntityCount: entityList?.buffer?.length || 0, + sceneSystemCount: entityProcessors?.processors?.length || 0, + sceneMemory: 0, + // TODO: 计算实际场景内存 + sceneUptime: runTime + }; + } + /** + * 设置场景开始时间 + */ + setSceneStartTime(time) { + this.sceneStartTime = time; + } +} +class WebSocketManager { + constructor(url, autoReconnect = true) { + this.isConnected = false; + this.reconnectAttempts = 0; + this.maxReconnectAttempts = 5; + this.reconnectInterval = 2e3; + this.url = url; + this.autoReconnect = autoReconnect; + } + /** + * 设置消息处理回调 + */ + setMessageHandler(handler) { + this.messageHandler = handler; + } + /** + * 连接WebSocket + */ + connect() { + return new Promise((resolve, reject) => { + try { + this.ws = new WebSocket(this.url); + this.ws.onopen = (event) => { + this.handleOpen(event); + resolve(); + }; + this.ws.onclose = (event) => { + this.handleClose(event); + }; + this.ws.onerror = (error) => { + this.handleError(error); + reject(error); + }; + this.ws.onmessage = (event) => { + this.handleMessage(event); + }; + } catch (error) { + this.handleConnectionFailure(error); + reject(error); + } + }); + } + /** + * 断开连接 + */ + disconnect() { + if (this.ws) { + this.autoReconnect = false; + this.ws.close(); + this.ws = void 0; + } + this.isConnected = false; + } + /** + * 发送数据 + */ + send(data) { + if (!this.isConnected || !this.ws) { + return; + } + try { + const message = typeof data === "string" ? data : JSON.stringify(data); + this.ws.send(message); + } catch (error) { + } + } + /** + * 获取连接状态 + */ + getConnectionStatus() { + return this.isConnected; + } + /** + * 设置最大重连次数 + */ + setMaxReconnectAttempts(attempts) { + this.maxReconnectAttempts = attempts; + } + /** + * 设置重连间隔 + */ + setReconnectInterval(interval) { + this.reconnectInterval = interval; + } + /** + * 计划重连 + */ + scheduleReconnect() { + if (this.reconnectTimer) { + clearTimeout(this.reconnectTimer); + } + const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts), 3e4); + this.reconnectAttempts++; + this.reconnectTimer = setTimeout(() => { + this.connect().catch((error) => { + if (this.reconnectAttempts < this.maxReconnectAttempts) { + this.scheduleReconnect(); + } + }); + }, delay); + } + /** + * 处理接收到的消息 + */ + handleMessage(event) { + try { + const message = JSON.parse(event.data); + if (this.messageHandler) { + this.messageHandler(message); + } + } catch (error) { + } + } + handleOpen(event) { + this.isConnected = true; + this.reconnectAttempts = 0; + if (this.onOpen) { + this.onOpen(event); + } + } + handleClose(event) { + this.isConnected = false; + if (this.onClose) { + this.onClose(event); + } + if (this.autoReconnect && this.reconnectAttempts < this.maxReconnectAttempts) { + this.scheduleReconnect(); + } + } + handleError(error) { + if (this.onError) { + this.onError(error); + } + } + handleConnectionFailure(error) { + if (this.onError) { + this.onError(error); + } + } +} +class DebugManager { + /** + * 构造调试管理器 + * @param core Core实例 + * @param config 调试配置 + */ + constructor(core, config) { + this.frameCounter = 0; + this.lastSendTime = 0; + this.isRunning = false; + this.config = config; + this.sceneProvider = () => core.scene || core.constructor.scene; + this.performanceMonitorProvider = () => core._performanceMonitor; + this.entityCollector = new EntityDataCollector(); + this.systemCollector = new SystemDataCollector(); + this.performanceCollector = new PerformanceDataCollector(); + this.componentCollector = new ComponentDataCollector(); + this.sceneCollector = new SceneDataCollector(); + this.webSocketManager = new WebSocketManager(config.websocketUrl, config.autoReconnect !== false); + this.webSocketManager.setMessageHandler(this.handleMessage.bind(this)); + const debugFrameRate = config.debugFrameRate || 30; + this.sendInterval = 1e3 / debugFrameRate; + this.start(); + } + /** + * 启动调试管理器 + */ + start() { + if (this.isRunning) + return; + this.isRunning = true; + this.connectWebSocket(); + } + /** + * 停止调试管理器 + */ + stop() { + if (!this.isRunning) + return; + this.isRunning = false; + this.webSocketManager.disconnect(); + } + /** + * 更新配置 + */ + updateConfig(config) { + this.config = config; + const debugFrameRate = config.debugFrameRate || 30; + this.sendInterval = 1e3 / debugFrameRate; + if (this.webSocketManager && config.websocketUrl) { + this.webSocketManager.disconnect(); + this.webSocketManager = new WebSocketManager(config.websocketUrl, config.autoReconnect !== false); + this.webSocketManager.setMessageHandler(this.handleMessage.bind(this)); + this.connectWebSocket(); + } + } + /** + * 帧更新回调 + */ + onFrameUpdate(deltaTime) { + if (!this.isRunning || !this.config.enabled) + return; + this.frameCounter++; + const currentTime = Date.now(); + if (currentTime - this.lastSendTime >= this.sendInterval) { + this.sendDebugData(); + this.lastSendTime = currentTime; + } + } + /** + * 场景变更回调 + */ + onSceneChanged() { + if (this.isRunning && this.config.enabled) { + this.sendDebugData(); + } + } + /** + * 处理来自调试面板的消息 + */ + handleMessage(message) { + try { + switch (message.type) { + case "capture_memory_snapshot": + this.handleMemorySnapshotRequest(); + break; + case "config_update": + if (message.config) { + this.updateConfig({ ...this.config, ...message.config }); + } + break; + case "expand_lazy_object": + this.handleExpandLazyObjectRequest(message); + break; + case "get_component_properties": + this.handleGetComponentPropertiesRequest(message); + break; + case "get_raw_entity_list": + this.handleGetRawEntityListRequest(message); + break; + case "get_entity_details": + this.handleGetEntityDetailsRequest(message); + break; + case "ping": + this.webSocketManager.send({ + type: "pong", + timestamp: Date.now() + }); + break; + default: + break; + } + } catch (error) { + if (message.requestId) { + this.webSocketManager.send({ + type: "error_response", + requestId: message.requestId, + error: error instanceof Error ? error.message : String(error) + }); + } + } + } + /** + * 处理展开懒加载对象请求 + */ + handleExpandLazyObjectRequest(message) { + try { + const { entityId, componentIndex, propertyPath, requestId } = message; + if (entityId === void 0 || componentIndex === void 0 || !propertyPath) { + this.webSocketManager.send({ + type: "expand_lazy_object_response", + requestId, + error: "缺少必要参数" + }); + return; + } + const expandedData = this.entityCollector.expandLazyObject(entityId, componentIndex, propertyPath); + this.webSocketManager.send({ + type: "expand_lazy_object_response", + requestId, + data: expandedData + }); + } catch (error) { + this.webSocketManager.send({ + type: "expand_lazy_object_response", + requestId: message.requestId, + error: error instanceof Error ? error.message : String(error) + }); + } + } + /** + * 处理获取组件属性请求 + */ + handleGetComponentPropertiesRequest(message) { + try { + const { entityId, componentIndex, requestId } = message; + if (entityId === void 0 || componentIndex === void 0) { + this.webSocketManager.send({ + type: "get_component_properties_response", + requestId, + error: "缺少必要参数" + }); + return; + } + const properties = this.entityCollector.getComponentProperties(entityId, componentIndex); + this.webSocketManager.send({ + type: "get_component_properties_response", + requestId, + data: properties + }); + } catch (error) { + this.webSocketManager.send({ + type: "get_component_properties_response", + requestId: message.requestId, + error: error instanceof Error ? error.message : String(error) + }); + } + } + /** + * 处理获取原始实体列表请求 + */ + handleGetRawEntityListRequest(message) { + try { + const { requestId } = message; + const rawEntityList = this.entityCollector.getRawEntityList(); + this.webSocketManager.send({ + type: "get_raw_entity_list_response", + requestId, + data: rawEntityList + }); + } catch (error) { + this.webSocketManager.send({ + type: "get_raw_entity_list_response", + requestId: message.requestId, + error: error instanceof Error ? error.message : String(error) + }); + } + } + /** + * 处理获取实体详情请求 + */ + handleGetEntityDetailsRequest(message) { + try { + const { entityId, requestId } = message; + if (entityId === void 0) { + this.webSocketManager.send({ + type: "get_entity_details_response", + requestId, + error: "缺少实体ID参数" + }); + return; + } + const entityDetails = this.entityCollector.getEntityDetails(entityId); + this.webSocketManager.send({ + type: "get_entity_details_response", + requestId, + data: entityDetails + }); + } catch (error) { + this.webSocketManager.send({ + type: "get_entity_details_response", + requestId: message.requestId, + error: error instanceof Error ? error.message : String(error) + }); + } + } + /** + * 处理内存快照请求 + */ + handleMemorySnapshotRequest() { + try { + const memorySnapshot = this.captureMemorySnapshot(); + this.webSocketManager.send({ + type: "memory_snapshot_response", + data: memorySnapshot + }); + } catch (error) { + this.webSocketManager.send({ + type: "memory_snapshot_error", + error: error instanceof Error ? error.message : "内存快照捕获失败" + }); + } + } + /** + * 捕获内存快照 + */ + captureMemorySnapshot() { + const timestamp = Date.now(); + const baseMemoryInfo = this.collectBaseMemoryInfo(); + const scene = this.sceneProvider(); + const entityData = this.entityCollector.collectEntityDataWithMemory(scene); + const componentMemoryStats = scene?.entities ? this.collectComponentMemoryStats(scene.entities) : { totalMemory: 0, componentTypes: 0, totalInstances: 0, breakdown: [] }; + const systemMemoryStats = this.collectSystemMemoryStats(); + const poolMemoryStats = this.collectPoolMemoryStats(); + const performanceStats = this.collectPerformanceStats(); + const totalEntityMemory = entityData.entitiesPerArchetype.reduce((sum, arch) => sum + arch.memory, 0); + return { + timestamp, + version: "2.0", + summary: { + totalEntities: entityData.totalEntities, + totalMemoryUsage: baseMemoryInfo.usedMemory, + totalMemoryLimit: baseMemoryInfo.totalMemory, + memoryUtilization: baseMemoryInfo.usedMemory / baseMemoryInfo.totalMemory * 100, + gcCollections: baseMemoryInfo.gcCollections, + entityMemory: totalEntityMemory, + componentMemory: componentMemoryStats.totalMemory, + systemMemory: systemMemoryStats.totalMemory, + poolMemory: poolMemoryStats.totalMemory + }, + baseMemory: baseMemoryInfo, + entities: { + totalMemory: totalEntityMemory, + entityCount: entityData.totalEntities, + archetypes: entityData.entitiesPerArchetype, + largestEntities: entityData.topEntitiesByComponents + }, + components: componentMemoryStats, + systems: systemMemoryStats, + pools: poolMemoryStats, + performance: performanceStats + }; + } + /** + * 收集基础内存信息 + */ + collectBaseMemoryInfo() { + const memoryInfo = { + totalMemory: 0, + usedMemory: 0, + freeMemory: 0, + gcCollections: 0, + heapInfo: null, + detailedMemory: void 0 + }; + try { + const performanceWithMemory = performance; + if (performanceWithMemory.memory) { + const perfMemory = performanceWithMemory.memory; + memoryInfo.totalMemory = perfMemory.jsHeapSizeLimit || 512 * 1024 * 1024; + memoryInfo.usedMemory = perfMemory.usedJSHeapSize || 0; + memoryInfo.freeMemory = memoryInfo.totalMemory - memoryInfo.usedMemory; + memoryInfo.heapInfo = { + totalJSHeapSize: perfMemory.totalJSHeapSize || 0, + usedJSHeapSize: perfMemory.usedJSHeapSize || 0, + jsHeapSizeLimit: perfMemory.jsHeapSizeLimit || 0 + }; + } else { + memoryInfo.totalMemory = 512 * 1024 * 1024; + memoryInfo.freeMemory = 512 * 1024 * 1024; + } + if (performanceWithMemory.measureUserAgentSpecificMemory) { + performanceWithMemory.measureUserAgentSpecificMemory().then((result) => { + memoryInfo.detailedMemory = result; + }).catch(() => { + }); + } + } catch (error) { + } + return memoryInfo; + } + /** + * 收集组件内存统计(仅用于内存快照) + */ + collectComponentMemoryStats(entityList) { + const componentStats = /* @__PURE__ */ new Map(); + let totalComponentMemory = 0; + const componentTypeCounts = /* @__PURE__ */ new Map(); + for (const entity of entityList.buffer) { + if (!entity || entity.destroyed || !entity.components) + continue; + for (const component of entity.components) { + const typeName = getComponentInstanceTypeName(component); + componentTypeCounts.set(typeName, (componentTypeCounts.get(typeName) || 0) + 1); + } + } + for (const [typeName, count] of componentTypeCounts.entries()) { + const detailedMemoryPerInstance = this.componentCollector.calculateDetailedComponentMemory(typeName); + const totalMemoryForType = detailedMemoryPerInstance * count; + totalComponentMemory += totalMemoryForType; + const instances = []; + let instanceCount = 0; + for (const entity of entityList.buffer) { + if (!entity || entity.destroyed || !entity.components) + continue; + for (const component of entity.components) { + if (getComponentInstanceTypeName(component) === typeName) { + instances.push({ + entityId: entity.id, + entityName: entity.name || `Entity_${entity.id}`, + memory: detailedMemoryPerInstance + // 使用统一的详细计算结果 + }); + instanceCount++; + if (instanceCount >= 100) + break; + } + } + if (instanceCount >= 100) + break; + } + componentStats.set(typeName, { + count, + totalMemory: totalMemoryForType, + instances: instances.slice(0, 10) + // 只保留前10个实例用于显示 + }); + } + const componentBreakdown = Array.from(componentStats.entries()).map(([typeName, stats]) => ({ + typeName, + instanceCount: stats.count, + totalMemory: stats.totalMemory, + averageMemory: stats.totalMemory / stats.count, + percentage: totalComponentMemory > 0 ? stats.totalMemory / totalComponentMemory * 100 : 0, + largestInstances: stats.instances.sort((a, b) => b.memory - a.memory).slice(0, 3) + })).sort((a, b) => b.totalMemory - a.totalMemory); + return { + totalMemory: totalComponentMemory, + componentTypes: componentStats.size, + totalInstances: Array.from(componentStats.values()).reduce((sum, stats) => sum + stats.count, 0), + breakdown: componentBreakdown + }; + } + collectSystemMemoryStats() { + const scene = this.sceneProvider(); + let totalSystemMemory = 0; + const systemBreakdown = []; + try { + const entityProcessors = scene?.entityProcessors; + if (entityProcessors && entityProcessors.processors) { + const systemTypeMemoryCache = /* @__PURE__ */ new Map(); + for (const system of entityProcessors.processors) { + const systemTypeName = getSystemInstanceTypeName(system); + let systemMemory; + if (systemTypeMemoryCache.has(systemTypeName)) { + systemMemory = systemTypeMemoryCache.get(systemTypeName); + } else { + systemMemory = this.calculateQuickSystemSize(system); + systemTypeMemoryCache.set(systemTypeName, systemMemory); + } + totalSystemMemory += systemMemory; + systemBreakdown.push({ + name: systemTypeName, + memory: systemMemory, + enabled: system.enabled !== false, + updateOrder: system.updateOrder || 0 + }); + } + } + } catch (error) { + } + return { + totalMemory: totalSystemMemory, + systemCount: systemBreakdown.length, + breakdown: systemBreakdown.sort((a, b) => b.memory - a.memory) + }; + } + calculateQuickSystemSize(system) { + if (!system || typeof system !== "object") + return 64; + let size = 128; + try { + const keys = Object.keys(system); + for (let i = 0; i < Math.min(keys.length, 15); i++) { + const key = keys[i]; + if (key === "entities" || key === "scene" || key === "constructor") + continue; + const value = system[key]; + size += key.length * 2; + if (typeof value === "string") { + size += Math.min(value.length * 2, 100); + } else if (typeof value === "number") { + size += 8; + } else if (typeof value === "boolean") { + size += 4; + } else if (Array.isArray(value)) { + size += 40 + Math.min(value.length * 8, 200); + } else if (typeof value === "object" && value !== null) { + size += 64; + } + } + } catch (error) { + return 128; + } + return Math.max(size, 64); + } + /** + * 收集对象池内存统计 + */ + collectPoolMemoryStats() { + let totalPoolMemory = 0; + const poolBreakdown = []; + try { + const poolManager = ComponentPoolManager.getInstance(); + const poolStats = poolManager.getPoolStats(); + for (const [typeName, stats] of poolStats.entries()) { + const poolData = stats; + const poolMemory = poolData.maxSize * 32; + totalPoolMemory += poolMemory; + poolBreakdown.push({ + typeName, + maxSize: poolData.maxSize, + currentSize: poolData.currentSize || 0, + estimatedMemory: poolMemory, + utilization: poolData.currentSize ? poolData.currentSize / poolData.maxSize * 100 : 0 + }); + } + } catch (error) { + } + try { + const poolStats = Pool.getAllPoolStats(); + for (const [typeName, stats] of Object.entries(poolStats)) { + const poolData = stats; + totalPoolMemory += poolData.estimatedMemoryUsage; + poolBreakdown.push({ + typeName: `Pool_${typeName}`, + maxSize: poolData.maxSize, + currentSize: poolData.size, + estimatedMemory: poolData.estimatedMemoryUsage, + utilization: poolData.size / poolData.maxSize * 100, + hitRate: poolData.hitRate * 100 + }); + } + } catch (error) { + } + return { + totalMemory: totalPoolMemory, + poolCount: poolBreakdown.length, + breakdown: poolBreakdown.sort((a, b) => b.estimatedMemory - a.estimatedMemory) + }; + } + /** + * 收集性能统计信息 + */ + collectPerformanceStats() { + try { + const performanceMonitor = this.performanceMonitorProvider(); + if (!performanceMonitor) { + return { enabled: false }; + } + const stats = performanceMonitor.getAllSystemStats(); + const warnings = performanceMonitor.getPerformanceWarnings(); + return { + enabled: performanceMonitor.enabled ?? false, + systemCount: stats.size, + warnings: warnings.slice(0, 10), + // 最多10个警告 + topSystems: Array.from(stats.entries()).map((entry) => { + const [name, stat] = entry; + return { + name, + averageTime: stat.averageTime, + maxTime: stat.maxTime, + samples: stat.executionCount + }; + }).sort((a, b) => b.averageTime - a.averageTime).slice(0, 5) + }; + } catch (error) { + return { enabled: false, error: error instanceof Error ? error.message : String(error) }; + } + } + /** + * 获取调试数据 + */ + getDebugData() { + const currentTime = Date.now(); + const scene = this.sceneProvider(); + const debugData = { + timestamp: currentTime, + frameworkVersion: "1.0.0", + // 可以从package.json读取 + isRunning: this.isRunning, + frameworkLoaded: true, + currentScene: scene?.name || "Unknown" + }; + if (this.config.channels.entities) { + debugData.entities = this.entityCollector.collectEntityData(scene); + } + if (this.config.channels.systems) { + const performanceMonitor = this.performanceMonitorProvider(); + debugData.systems = this.systemCollector.collectSystemData(performanceMonitor, scene); + } + if (this.config.channels.performance) { + const performanceMonitor = this.performanceMonitorProvider(); + debugData.performance = this.performanceCollector.collectPerformanceData(performanceMonitor); + } + if (this.config.channels.components) { + debugData.components = this.componentCollector.collectComponentData(scene); + } + if (this.config.channels.scenes) { + debugData.scenes = this.sceneCollector.collectSceneData(scene); + } + return debugData; + } + /** + * 连接WebSocket + */ + async connectWebSocket() { + try { + await this.webSocketManager.connect(); + } catch (error) { + } + } + /** + * 发送调试数据 + */ + sendDebugData() { + if (!this.webSocketManager.getConnectionStatus()) { + return; + } + try { + const debugData = this.getDebugData(); + const message = { + type: "debug_data", + data: debugData + }; + this.webSocketManager.send(message); + } catch (error) { + } + } +} +class Core { + /** + * 创建核心实例 + * + * @param config - Core配置对象 + */ + constructor(config = {}) { + this._globalManagers = []; + Core._instance = this; + this._config = { + debug: true, + enableEntitySystems: true, + ...config + }; + this._timerManager = new TimerManager(); + Core.registerGlobalManager(this._timerManager); + this._performanceMonitor = PerformanceMonitor.instance; + if (this._config.debug) { + this._performanceMonitor.enable(); + } + this._poolManager = PoolManager.getInstance(); + Core.entitySystemsEnabled = this._config.enableEntitySystems ?? true; + this.debug = this._config.debug ?? true; + if (this._config.debugConfig?.enabled) { + this._debugManager = new DebugManager(this, this._config.debugConfig); + } + this.initialize(); + } + /** + * 获取核心实例 + * + * @returns 全局核心实例 + */ + static get Instance() { + return this._instance; + } + /** + * 获取当前活动的场景(属性访问器) + * + * @returns 当前场景实例,如果没有则返回null + */ + static get scene() { + return this.getScene(); + } + /** + * 获取当前活动的场景(方法调用) + * + * @returns 当前场景实例,如果没有则返回null + */ + static getScene() { + if (!this._instance) { + return null; + } + this._instance.ensureDefaultWorld(); + const defaultWorld = this._instance._worldManager.getWorld(this.DEFAULT_WORLD_ID); + return defaultWorld?.getScene(this.DEFAULT_SCENE_ID) || null; + } + /** + * 设置当前场景 + * + * @param scene - 要设置的场景实例 + * @returns 设置的场景实例,便于链式调用 + */ + static setScene(scene) { + if (!this._instance) { + throw new Error("Core实例未创建,请先调用Core.create()"); + } + this._instance.ensureDefaultWorld(); + const defaultWorld = this._instance._worldManager.getWorld(this.DEFAULT_WORLD_ID); + if (defaultWorld.getScene(this.DEFAULT_SCENE_ID)) { + defaultWorld.removeScene(this.DEFAULT_SCENE_ID); + } + defaultWorld.createScene(this.DEFAULT_SCENE_ID, scene); + defaultWorld.setSceneActive(this.DEFAULT_SCENE_ID, true); + this._instance.onSceneChanged(); + return scene; + } + /** + * 创建Core实例 + * + * 如果实例已存在,则返回现有实例。 + * + * @param config - Core配置,也可以直接传入boolean表示debug模式(向后兼容) + * @returns Core实例 + */ + static create(config = true) { + if (this._instance == null) { + const coreConfig = typeof config === "boolean" ? { debug: config, enableEntitySystems: true } : config; + this._instance = new Core(coreConfig); + } + return this._instance; + } + /** + * 更新游戏逻辑 + * + * 此方法应该在游戏引擎的更新循环中调用。 + * + * @param deltaTime - 外部引擎提供的帧时间间隔(秒) + * + * @example + * ```typescript + * // Laya引擎 + * Laya.timer.frameLoop(1, this, () => { + * const deltaTime = Laya.timer.delta / 1000; + * Core.update(deltaTime); + * }); + * + * // Cocos Creator + * update(deltaTime: number) { + * Core.update(deltaTime); + * } + * + + * ``` + */ + static update(deltaTime) { + if (!this._instance) { + Core._logger.warn("Core实例未创建,请先调用Core.create()"); + return; + } + this._instance.updateInternal(deltaTime); + } + /** + * 注册全局管理器 + * + * 将管理器添加到全局管理器列表中,并启用它。 + * + * @param manager - 要注册的全局管理器 + */ + static registerGlobalManager(manager) { + this._instance._globalManagers.push(manager); + manager.enabled = true; + } + /** + * 注销全局管理器 + * + * 从全局管理器列表中移除管理器,并禁用它。 + * + * @param manager - 要注销的全局管理器 + */ + static unregisterGlobalManager(manager) { + this._instance._globalManagers.splice(this._instance._globalManagers.indexOf(manager), 1); + manager.enabled = false; + } + /** + * 获取指定类型的全局管理器 + * + * @param type - 管理器类型构造函数 + * @returns 管理器实例,如果未找到则返回null + */ + static getGlobalManager(type) { + for (const manager of this._instance._globalManagers) { + if (manager instanceof type) + return manager; + } + return null; + } + /** + * 调度定时器 + * + * 创建一个定时器,在指定时间后执行回调函数。 + * + * @param timeInSeconds - 延迟时间(秒) + * @param repeats - 是否重复执行,默认为false + * @param context - 回调函数的上下文,默认为null + * @param onTime - 定时器触发时的回调函数 + * @returns 创建的定时器实例 + */ + static schedule(timeInSeconds, repeats = false, context, onTime) { + if (!onTime) { + throw new Error("onTime callback is required"); + } + return this._instance._timerManager.schedule(timeInSeconds, repeats, context, onTime); + } + /** + * 获取ECS流式API + * + * @returns ECS API实例,如果未初始化则返回null + */ + static get ecsAPI() { + return this._instance?._ecsAPI || null; + } + /** + * 启用调试功能 + * + * @param config 调试配置 + */ + static enableDebug(config) { + if (!this._instance) { + Core._logger.warn("Core实例未创建,请先调用Core.create()"); + return; + } + if (this._instance._debugManager) { + this._instance._debugManager.updateConfig(config); + } else { + this._instance._debugManager = new DebugManager(this._instance, config); + } + this._instance._config.debugConfig = config; + } + /** + * 禁用调试功能 + */ + static disableDebug() { + if (!this._instance) + return; + if (this._instance._debugManager) { + this._instance._debugManager.stop(); + this._instance._debugManager = void 0; + } + if (this._instance._config.debugConfig) { + this._instance._config.debugConfig.enabled = false; + } + } + /** + * 获取调试数据 + * + * @returns 当前调试数据,如果调试未启用则返回null + */ + static getDebugData() { + if (!this._instance?._debugManager) { + return null; + } + return this._instance._debugManager.getDebugData(); + } + /** + * 检查调试是否启用 + * + * @returns 调试状态 + */ + static get isDebugEnabled() { + return this._instance?._config.debugConfig?.enabled || false; + } + /** + * 获取WorldManager实例 + * + * @param config 可选的WorldManager配置,用于覆盖默认配置 + * @returns WorldManager实例,如果未初始化则自动创建 + */ + static getWorldManager(config) { + if (!this._instance) { + throw new Error("Core实例未创建,请先调用Core.create()"); + } + if (!this._instance._worldManager) { + const defaultConfig = { + maxWorlds: 50, + autoCleanup: true, + cleanupInterval: 6e4, + debug: this._instance._config.debug + }; + this._instance._worldManager = WorldManager.getInstance({ + ...defaultConfig, + ...config + // 用户传入的配置会覆盖默认配置 + }); + } + return this._instance._worldManager; + } + /** + * 启用World管理 + * + * 显式启用World功能,用于多房间/多世界架构 + * + * @param config 可选的WorldManager配置,用于覆盖默认配置 + */ + static enableWorldManager(config) { + return this.getWorldManager(config); + } + /** + * 确保默认World存在 + * + * 内部方法,用于懒初始化默认World + */ + ensureDefaultWorld() { + if (!this._worldManager) { + this._worldManager = WorldManager.getInstance({ + maxWorlds: 1, + // 单场景用户只需要1个World + autoCleanup: false, + // 单场景不需要自动清理 + cleanupInterval: 0, + // 禁用清理定时器 + debug: this._config.debug + }); + } + if (!this._worldManager.getWorld(Core.DEFAULT_WORLD_ID)) { + this._worldManager.createWorld(Core.DEFAULT_WORLD_ID, { + name: "DefaultWorld", + maxScenes: 1, + autoCleanup: false + }); + this._worldManager.setWorldActive(Core.DEFAULT_WORLD_ID, true); + } + } + /** + * 场景切换回调 + * + * 在场景切换时调用,用于重置时间系统等。 + */ + onSceneChanged() { + Time.sceneChanged(); + const currentScene = Core.getScene(); + if (currentScene && currentScene.querySystem && currentScene.eventSystem) { + this._ecsAPI = createECSAPI(currentScene, currentScene.querySystem, currentScene.eventSystem); + } + if (this._debugManager) { + queueMicrotask(() => { + this._debugManager?.onSceneChanged(); + }); + } + } + /** + * 初始化核心系统 + * + * 执行核心系统的初始化逻辑。 + */ + initialize() { + } + /** + * 内部更新方法 + * + * @param deltaTime - 帧时间间隔(秒) + */ + updateInternal(deltaTime) { + if (Core.paused) + return; + const frameStartTime = this._performanceMonitor.startMonitoring("Core.update"); + Time.update(deltaTime); + if ("updateFPS" in this._performanceMonitor && typeof this._performanceMonitor.updateFPS === "function") { + this._performanceMonitor.updateFPS(Time.deltaTime); + } + const managersStartTime = this._performanceMonitor.startMonitoring("GlobalManagers.update"); + for (const globalManager of this._globalManagers) { + if (globalManager.enabled) + globalManager.update(); + } + this._performanceMonitor.endMonitoring("GlobalManagers.update", managersStartTime, this._globalManagers.length); + this._poolManager.update(); + if (this._worldManager) { + const worldsStartTime = this._performanceMonitor.startMonitoring("Worlds.update"); + const activeWorlds = this._worldManager.getActiveWorlds(); + let totalWorldEntities = 0; + for (const world of activeWorlds) { + world.updateGlobalSystems(); + world.updateScenes(); + const worldStats = world.getStats(); + totalWorldEntities += worldStats.totalEntities; + } + this._performanceMonitor.endMonitoring("Worlds.update", worldsStartTime, totalWorldEntities); + } + if (this._debugManager) { + this._debugManager.onFrameUpdate(deltaTime); + } + this._performanceMonitor.endMonitoring("Core.update", frameStartTime); + } +} +Core.paused = false; +Core.DEFAULT_WORLD_ID = "__default__"; +Core.DEFAULT_SCENE_ID = "__main__"; +Core._logger = createLogger("Core"); +class Component { + /** + * 创建组件实例 + * + * 自动分配唯一ID给组件。 + */ + constructor() { + this._enabled = true; + this._updateOrder = 0; + this.id = Component._idGenerator++; + } + /** + * 获取组件启用状态 + * + * 组件的实际启用状态取决于自身状态和所属实体的状态。 + * + * @deprecated 不符合ECS架构规范,建议自己实现DisabledComponent标记组件替代 + * @returns 如果组件和所属实体都启用则返回true + */ + get enabled() { + return this.entity ? this.entity.enabled && this._enabled : this._enabled; + } + /** + * 设置组件启用状态 + * + * 当状态改变时会触发相应的生命周期回调。 + * + * @deprecated 不符合ECS架构规范,建议自己实现DisabledComponent标记组件替代 + * @param value - 新的启用状态 + */ + set enabled(value) { + if (this._enabled !== value) { + this._enabled = value; + if (this._enabled) { + this.onEnabled(); + } else { + this.onDisabled(); + } + } + } + /** + * 获取更新顺序 + * + * @deprecated 不符合ECS架构规范,更新顺序应该由EntitySystem管理 + * @see EntitySystem + * @returns 组件的更新顺序值 + */ + get updateOrder() { + return this._updateOrder; + } + /** + * 设置更新顺序 + * + * @deprecated 不符合ECS架构规范,更新顺序应该由EntitySystem管理 + * @see EntitySystem + * @param value - 新的更新顺序值 + */ + set updateOrder(value) { + this._updateOrder = value; + } + /** + * 组件添加到实体时的回调 + * + * 当组件被添加到实体时调用,可以在此方法中进行初始化操作。 + */ + onAddedToEntity() { + } + /** + * 组件从实体移除时的回调 + * + * 当组件从实体中移除时调用,可以在此方法中进行清理操作。 + */ + onRemovedFromEntity() { + } + /** + * 组件启用时的回调 + * + * 当组件被启用时调用。 + */ + onEnabled() { + } + /** + * 组件禁用时的回调 + * + * 当组件被禁用时调用。 + */ + onDisabled() { + } + /** + * 更新组件 + * + * @deprecated 不符合ECS架构规范,建议使用EntitySystem来处理更新逻辑 + */ + update() { + } +} +Component._idGenerator = 0; +class Matcher { + constructor() { + this.condition = { + all: [], + any: [], + none: [] + }; + } + /** + * 创建匹配器,要求所有指定的组件 + * @param types 组件类型 + */ + static all(...types) { + const matcher = new Matcher(); + return matcher.all(...types); + } + /** + * 创建匹配器,要求至少一个指定的组件 + * @param types 组件类型 + */ + static any(...types) { + const matcher = new Matcher(); + return matcher.any(...types); + } + /** + * 创建匹配器,排除指定的组件 + * @param types 组件类型 + */ + static none(...types) { + const matcher = new Matcher(); + return matcher.none(...types); + } + /** + * 创建按标签查询的匙配器 + * @param tag 标签值 + */ + static byTag(tag) { + const matcher = new Matcher(); + return matcher.withTag(tag); + } + /** + * 创建按名称查询的匙配器 + * @param name 实体名称 + */ + static byName(name) { + const matcher = new Matcher(); + return matcher.withName(name); + } + /** + * 创建单组件查询的匙配器 + * @param componentType 组件类型 + */ + static byComponent(componentType) { + const matcher = new Matcher(); + return matcher.withComponent(componentType); + } + /** + * 创建复杂查询构建器 + */ + static complex() { + return new Matcher(); + } + /** + * 创建空匙配器 + */ + static empty() { + return new Matcher(); + } + /** + * 必须包含所有指定组件 + * @param types 组件类型 + */ + all(...types) { + this.condition.all.push(...types); + return this; + } + /** + * 必须包含至少一个指定组件 + * @param types 组件类型 + */ + any(...types) { + this.condition.any.push(...types); + return this; + } + /** + * 不能包含任何指定组件 + * @param types 组件类型 + */ + none(...types) { + this.condition.none.push(...types); + return this; + } + /** + * 排除指定组件(别名方法) + * @param types 组件类型 + */ + exclude(...types) { + return this.none(...types); + } + /** + * 至少包含其中之一(别名方法) + * @param types 组件类型 + */ + one(...types) { + return this.any(...types); + } + /** + * 按标签查询 + * @param tag 标签值 + */ + withTag(tag) { + this.condition.tag = tag; + return this; + } + /** + * 按名称查询 + * @param name 实体名称 + */ + withName(name) { + this.condition.name = name; + return this; + } + /** + * 单组件查询 + * @param componentType 组件类型 + */ + withComponent(componentType) { + this.condition.component = componentType; + return this; + } + /** + * 移除标签条件 + */ + withoutTag() { + delete this.condition.tag; + return this; + } + /** + * 移除名称条件 + */ + withoutName() { + delete this.condition.name; + return this; + } + /** + * 移除单组件条件 + */ + withoutComponent() { + delete this.condition.component; + return this; + } + /** + * 获取查询条件(只读) + */ + getCondition() { + return { + all: [...this.condition.all], + any: [...this.condition.any], + none: [...this.condition.none], + tag: this.condition.tag, + name: this.condition.name, + component: this.condition.component + }; + } + /** + * 检查是否为空条件 + */ + isEmpty() { + return this.condition.all.length === 0 && this.condition.any.length === 0 && this.condition.none.length === 0 && this.condition.tag === void 0 && this.condition.name === void 0 && this.condition.component === void 0; + } + /** + * 重置所有条件 + */ + reset() { + this.condition.all.length = 0; + this.condition.any.length = 0; + this.condition.none.length = 0; + delete this.condition.tag; + delete this.condition.name; + delete this.condition.component; + return this; + } + /** + * 克隆匹配器 + */ + clone() { + const cloned = new Matcher(); + cloned.condition.all.push(...this.condition.all); + cloned.condition.any.push(...this.condition.any); + cloned.condition.none.push(...this.condition.none); + if (this.condition.tag !== void 0) { + cloned.condition.tag = this.condition.tag; + } + if (this.condition.name !== void 0) { + cloned.condition.name = this.condition.name; + } + if (this.condition.component !== void 0) { + cloned.condition.component = this.condition.component; + } + return cloned; + } + /** + * 字符串表示 + */ + toString() { + const parts = []; + if (this.condition.all.length > 0) { + parts.push(`all(${this.condition.all.map((t) => getComponentTypeName(t)).join(", ")})`); + } + if (this.condition.any.length > 0) { + parts.push(`any(${this.condition.any.map((t) => getComponentTypeName(t)).join(", ")})`); + } + if (this.condition.none.length > 0) { + parts.push(`none(${this.condition.none.map((t) => getComponentTypeName(t)).join(", ")})`); + } + if (this.condition.tag !== void 0) { + parts.push(`tag(${this.condition.tag})`); + } + if (this.condition.name !== void 0) { + parts.push(`name(${this.condition.name})`); + } + if (this.condition.component !== void 0) { + parts.push(`component(${getComponentTypeName(this.condition.component)})`); + } + return `Matcher[${parts.join(" & ")}]`; + } +} +class EntitySystem { + /** + * 获取系统处理的实体列表 + */ + get entities() { + if (this._entityCache.frame !== null) { + return this._entityCache.frame; + } + if (this._entityCache.persistent === null) { + this._entityCache.persistent = this.queryEntities(); + } + return this._entityCache.persistent; + } + /** + * 获取系统的更新时序 + */ + get updateOrder() { + return this._updateOrder; + } + set updateOrder(value) { + this.setUpdateOrder(value); + } + /** + * 获取系统的启用状态 + */ + get enabled() { + return this._enabled; + } + /** + * 设置系统的启用状态 + */ + set enabled(value) { + this._enabled = value; + } + /** + * 获取系统名称 + */ + get systemName() { + return this._systemName; + } + constructor(matcher) { + this._updateOrder = 0; + this._enabled = true; + this._performanceMonitor = PerformanceMonitor.instance; + this._systemName = getSystemInstanceTypeName(this); + this._initialized = false; + this._matcher = matcher || Matcher.empty(); + this._eventListeners = []; + this._scene = null; + this._entityIdMap = null; + this._entityIdMapVersion = -1; + this._entityIdMapSize = 0; + this._entityCache = { + frame: null, + persistent: null, + tracked: /* @__PURE__ */ new Set(), + invalidate() { + this.persistent = null; + }, + clearFrame() { + this.frame = null; + }, + clearAll() { + this.frame = null; + this.persistent = null; + this.tracked.clear(); + } + }; + } + /** + * 这个系统所属的场景 + */ + get scene() { + return this._scene; + } + set scene(value) { + this._scene = value; + } + /** + * 获取实体匹配器 + */ + get matcher() { + return this._matcher; + } + /** + * 设置更新时序 + * @param order 更新时序 + */ + setUpdateOrder(order) { + this._updateOrder = order; + if (this.scene && this.scene.entityProcessors) { + this.scene.entityProcessors.setDirty(); + } + } + /** + * 系统初始化(框架调用) + * + * 在系统创建时调用。框架内部使用,用户不应直接调用。 + */ + initialize() { + if (this._initialized) { + return; + } + this._initialized = true; + if (this.scene) { + this._entityCache.invalidate(); + this.queryEntities(); + } + this.onInitialize(); + } + /** + * 系统初始化回调 + * + * 子类可以重写此方法进行初始化操作。 + */ + onInitialize() { + } + /** + * 清除实体缓存(内部使用) + * 当Scene中的实体发生变化时调用 + */ + clearEntityCache() { + this._entityCache.invalidate(); + } + /** + * 重置系统状态 + * + * 当系统从场景中移除时调用,重置初始化状态以便重新添加时能正确初始化。 + */ + reset() { + this.scene = null; + this._initialized = false; + this._entityCache.clearAll(); + this._entityIdMap = null; + this._entityIdMapVersion = -1; + this._entityIdMapSize = 0; + this.cleanupEventListeners(); + this.onDestroy(); + } + /** + * 查询匹配的实体 + */ + queryEntities() { + if (!this.scene?.querySystem || !this._matcher) { + return []; + } + const condition = this._matcher.getCondition(); + const querySystem = this.scene.querySystem; + let currentEntities = []; + if (this._matcher.isEmpty()) { + currentEntities = querySystem.getAllEntities(); + } else if (this.isSingleCondition(condition)) { + currentEntities = this.executeSingleConditionQuery(condition, querySystem); + } else { + currentEntities = this.executeComplexQuery(condition, querySystem); + } + this.updateEntityTracking(currentEntities); + return currentEntities; + } + /** + * 检查是否为单一条件查询 + */ + isSingleCondition(condition) { + const flags = (condition.all.length > 0 ? 1 : 0) | (condition.any.length > 0 ? 2 : 0) | (condition.none.length > 0 ? 4 : 0) | (condition.tag !== void 0 ? 8 : 0) | (condition.name !== void 0 ? 16 : 0) | (condition.component !== void 0 ? 32 : 0); + return flags !== 0 && (flags & flags - 1) === 0; + } + /** + * 执行单一条件查询 + */ + executeSingleConditionQuery(condition, querySystem) { + if (condition.tag !== void 0) { + return querySystem.queryByTag(condition.tag).entities; + } + if (condition.name !== void 0) { + return querySystem.queryByName(condition.name).entities; + } + if (condition.component !== void 0) { + return querySystem.queryByComponent(condition.component).entities; + } + if (condition.all.length > 0 && condition.any.length === 0 && condition.none.length === 0) { + return querySystem.queryAll(...condition.all).entities; + } + if (condition.all.length === 0 && condition.any.length > 0 && condition.none.length === 0) { + return querySystem.queryAny(...condition.any).entities; + } + if (condition.all.length === 0 && condition.any.length === 0 && condition.none.length > 0) { + return querySystem.queryNone(...condition.none).entities; + } + return []; + } + /** + * 执行复合查询 + */ + executeComplexQueryWithIdSets(condition, querySystem) { + let resultIds = null; + if (condition.tag !== void 0) { + const tagResult = querySystem.queryByTag(condition.tag); + resultIds = this.extractEntityIds(tagResult.entities); + } + if (condition.name !== void 0) { + const nameIds = this.extractEntityIds(querySystem.queryByName(condition.name).entities); + resultIds = resultIds ? this.intersectIdSets(resultIds, nameIds) : nameIds; + } + if (condition.component !== void 0) { + const componentIds = this.extractEntityIds(querySystem.queryByComponent(condition.component).entities); + resultIds = resultIds ? this.intersectIdSets(resultIds, componentIds) : componentIds; + } + if (condition.all.length > 0) { + const allIds = this.extractEntityIds(querySystem.queryAll(...condition.all).entities); + resultIds = resultIds ? this.intersectIdSets(resultIds, allIds) : allIds; + } + if (condition.any.length > 0) { + const anyIds = this.extractEntityIds(querySystem.queryAny(...condition.any).entities); + resultIds = resultIds ? this.intersectIdSets(resultIds, anyIds) : anyIds; + } + if (condition.none.length > 0) { + if (!resultIds) { + resultIds = this.extractEntityIds(querySystem.getAllEntities()); + } + const noneResult = querySystem.queryAny(...condition.none); + const noneIds = this.extractEntityIds(noneResult.entities); + resultIds = this.differenceIdSets(resultIds, noneIds); + } + return resultIds ? this.idSetToEntityArray(resultIds, querySystem.getAllEntities()) : []; + } + /** + * 提取实体ID集合 + */ + extractEntityIds(entities) { + const len = entities.length; + const idSet = /* @__PURE__ */ new Set(); + for (let i = 0; i < len; i = i + 1 | 0) { + idSet.add(entities[i].id | 0); + } + return idSet; + } + /** + * ID集合交集运算 + */ + intersectIdSets(setA, setB) { + let smaller, larger; + if (setA.size <= setB.size) { + smaller = setA; + larger = setB; + } else { + smaller = setB; + larger = setA; + } + const result = /* @__PURE__ */ new Set(); + for (const id of smaller) { + if (larger.has(id)) { + result.add(id); + } + } + return result; + } + /** + * ID集合差集运算 + */ + differenceIdSets(setA, setB) { + const result = /* @__PURE__ */ new Set(); + for (const id of setA) { + if (!setB.has(id)) { + result.add(id); + } + } + return result; + } + /** + * 获取或构建实体ID映射 + */ + getEntityIdMap(allEntities) { + const currentVersion = this.scene?.querySystem?.version ?? 0; + if (this._entityIdMap !== null && this._entityIdMapVersion === currentVersion) { + return this._entityIdMap; + } + return this.rebuildEntityIdMap(allEntities, currentVersion); + } + /** + * 重建实体ID映射 + */ + rebuildEntityIdMap(allEntities, version) { + let entityMap = this._entityIdMap; + if (!entityMap) { + entityMap = /* @__PURE__ */ new Map(); + } else { + entityMap.clear(); + } + const len = allEntities.length; + for (let i = 0; i < len; i = i + 1 | 0) { + const entity = allEntities[i]; + entityMap.set(entity.id | 0, entity); + } + this._entityIdMap = entityMap; + this._entityIdMapVersion = version; + this._entityIdMapSize = len; + return entityMap; + } + /** + * 从ID集合构建Entity数组 + */ + idSetToEntityArray(idSet, allEntities) { + const entityMap = this.getEntityIdMap(allEntities); + const size = idSet.size; + const result = new Array(size); + let index = 0; + for (const id of idSet) { + const entity = entityMap.get(id); + if (entity !== void 0) { + result[index] = entity; + index = index + 1 | 0; + } + } + if (index < size) { + result.length = index; + } + return result; + } + /** + * 执行复合查询 + * + * 使用基于ID集合的单次扫描算法进行复杂查询 + */ + executeComplexQuery(condition, querySystem) { + return this.executeComplexQueryWithIdSets(condition, querySystem); + } + /** + * 更新系统 + */ + update() { + if (!this._enabled || !this.onCheckProcessing()) { + return; + } + const startTime = this._performanceMonitor.startMonitoring(this._systemName); + let entityCount = 0; + try { + this.onBegin(); + this._entityCache.frame = this.queryEntities(); + entityCount = this._entityCache.frame.length; + this.process(this._entityCache.frame); + } finally { + this._performanceMonitor.endMonitoring(this._systemName, startTime, entityCount); + } + } + /** + * 后期更新系统 + */ + lateUpdate() { + if (!this._enabled || !this.onCheckProcessing()) { + return; + } + const startTime = this._performanceMonitor.startMonitoring(`${this._systemName}_Late`); + let entityCount = 0; + try { + const entities = this._entityCache.frame || []; + entityCount = entities.length; + this.lateProcess(entities); + this.onEnd(); + } finally { + this._performanceMonitor.endMonitoring(`${this._systemName}_Late`, startTime, entityCount); + this._entityCache.clearFrame(); + } + } + /** + * 在系统处理开始前调用 + * + * 子类可以重写此方法进行预处理操作。 + */ + onBegin() { + } + /** + * 处理实体列表 + * + * 系统的核心逻辑,子类必须实现此方法来定义具体的处理逻辑。 + * + * @param entities 要处理的实体列表 + */ + process(entities) { + } + /** + * 后期处理实体列表 + * + * 在主要处理逻辑之后执行,子类可以重写此方法。 + * + * @param entities 要处理的实体列表 + */ + lateProcess(_entities) { + } + /** + * 系统处理完毕后调用 + * + * 子类可以重写此方法进行后处理操作。 + */ + onEnd() { + } + /** + * 检查系统是否需要处理 + * + * 在启用系统时有用,但仅偶尔需要处理。 + * 这只影响处理,不影响事件或订阅列表。 + * + * @returns 如果系统应该处理,则为true,如果不处理则为false + */ + onCheckProcessing() { + return true; + } + /** + * 获取系统的性能数据 + * + * @returns 性能数据或undefined + */ + getPerformanceData() { + return this._performanceMonitor.getSystemData(this._systemName); + } + /** + * 获取系统的性能统计 + * + * @returns 性能统计或undefined + */ + getPerformanceStats() { + return this._performanceMonitor.getSystemStats(this._systemName); + } + /** + * 重置系统的性能数据 + */ + resetPerformanceData() { + this._performanceMonitor.resetSystem(this._systemName); + } + /** + * 获取系统信息的字符串表示 + * + * @returns 系统信息字符串 + */ + toString() { + const entityCount = this.entities.length; + const perfData = this.getPerformanceData(); + const perfInfo = perfData ? ` (${perfData.executionTime.toFixed(2)}ms)` : ""; + return `${this._systemName}[${entityCount} entities]${perfInfo}`; + } + /** + * 更新实体跟踪,检查新增和移除的实体 + */ + updateEntityTracking(currentEntities) { + const currentSet = new Set(currentEntities); + let hasChanged = false; + for (const entity of currentEntities) { + if (!this._entityCache.tracked.has(entity)) { + this._entityCache.tracked.add(entity); + this.onAdded(entity); + hasChanged = true; + } + } + for (const entity of this._entityCache.tracked) { + if (!currentSet.has(entity)) { + this._entityCache.tracked.delete(entity); + this.onRemoved(entity); + hasChanged = true; + } + } + if (hasChanged) { + this._entityCache.invalidate(); + } + } + /** + * 当实体被添加到系统时调用 + * + * 子类可以重写此方法来处理实体添加事件。 + * + * @param entity 被添加的实体 + */ + onAdded(entity) { + } + /** + * 当实体从系统中移除时调用 + * + * 子类可以重写此方法来处理实体移除事件。 + * + * @param entity 被移除的实体 + */ + onRemoved(entity) { + } + /** + * 添加事件监听器 + * + * 推荐使用此方法而不是直接调用eventSystem.on(), + * 这样可以确保系统移除时自动清理监听器,避免内存泄漏。 + * + * @param eventType 事件类型 + * @param handler 事件处理函数 + * @param config 监听器配置 + */ + addEventListener(eventType, handler, config) { + if (!this.scene?.eventSystem) { + console.warn(`[${this.systemName}] Cannot add event listener: scene.eventSystem not available`); + return; + } + const listenerRef = this.scene.eventSystem.on(eventType, handler, config); + if (listenerRef) { + this._eventListeners.push({ + eventSystem: this.scene.eventSystem, + eventType, + handler, + listenerRef + }); + } + } + /** + * 移除特定的事件监听器 + * + * @param eventType 事件类型 + * @param handler 事件处理函数 + */ + removeEventListener(eventType, handler) { + const listenerIndex = this._eventListeners.findIndex((listener) => listener.eventType === eventType && listener.handler === handler); + if (listenerIndex >= 0) { + const listener = this._eventListeners[listenerIndex]; + listener.eventSystem.off(eventType, listener.listenerRef); + this._eventListeners.splice(listenerIndex, 1); + } + } + /** + * 清理所有事件监听器 + * + * 系统移除时自动调用,清理所有通过addEventListener添加的监听器。 + */ + cleanupEventListeners() { + for (const listener of this._eventListeners) { + try { + listener.eventSystem.off(listener.eventType, listener.listenerRef); + } catch (error) { + console.warn(`[${this.systemName}] Failed to remove event listener for "${listener.eventType}":`, error); + } + } + this._eventListeners.length = 0; + } + /** + * 系统销毁时的回调 + * + * 当系统从场景中移除时调用,子类可以重写此方法进行清理操作。 + * 注意:事件监听器会被框架自动清理,无需手动处理。 + */ + onDestroy() { + } +} +class WorkerEntitySystem extends EntitySystem { + constructor(matcher, config = {}) { + super(matcher); + this.workerPool = null; + this.isProcessing = false; + this.sharedBuffer = null; + this.sharedFloatArray = null; + this.config = { + enableWorker: config.enableWorker ?? true, + workerCount: config.workerCount ?? this.getOptimalWorkerCount(), + systemConfig: config.systemConfig, + useSharedArrayBuffer: config.useSharedArrayBuffer ?? this.isSharedArrayBufferSupported(), + entityDataSize: config.entityDataSize ?? this.getDefaultEntityDataSize(), + maxEntities: config.maxEntities ?? 1e4 + }; + if (this.config.enableWorker && this.isWorkerSupported()) { + if (this.config.useSharedArrayBuffer) { + this.initializeSharedArrayBuffer(); + } + this.initializeWorkerPool(); + } + } + /** + * 检查是否支持Worker + */ + isWorkerSupported() { + return typeof Worker !== "undefined" && typeof Blob !== "undefined"; + } + /** + * 检查是否支持SharedArrayBuffer + */ + isSharedArrayBufferSupported() { + return typeof SharedArrayBuffer !== "undefined" && self.crossOriginIsolated; + } + /** + * 获取最优Worker数量 + */ + getOptimalWorkerCount() { + if (typeof navigator !== "undefined" && navigator.hardwareConcurrency) { + return Math.min(navigator.hardwareConcurrency, 4); + } + return 2; + } + /** + * 初始化SharedArrayBuffer + */ + initializeSharedArrayBuffer() { + try { + const bufferSize = this.config.maxEntities * this.config.entityDataSize * 4; + this.sharedBuffer = new SharedArrayBuffer(bufferSize); + this.sharedFloatArray = new Float32Array(this.sharedBuffer); + } catch (error) { + console.warn(`[${this.systemName}] SharedArrayBuffer init failed:`, error); + this.config.useSharedArrayBuffer = false; + } + } + /** + * 初始化Worker池 + */ + initializeWorkerPool() { + try { + const script = this.createWorkerScript(); + this.workerPool = new WebWorkerPool( + this.config.workerCount, + script, + this.sharedBuffer + // 传递SharedArrayBuffer给Worker池 + ); + } catch (error) { + console.error(`[${this.systemName}] Failed to initialize worker pool:`, error); + this.config.enableWorker = false; + } + } + /** + * 创建Worker脚本 + */ + createWorkerScript() { + const methodStr = this.workerProcess.toString(); + const functionBodyMatch = methodStr.match(/\{([\s\S]*)\}/); + if (!functionBodyMatch) { + throw new Error("无法解析workerProcess方法"); + } + const functionBody = functionBodyMatch[1]; + const entityDataSize = this.config.entityDataSize; + const sharedProcessMethod = this.getSharedArrayBufferProcessFunction?.() || null; + let sharedProcessFunctionBody = ""; + if (sharedProcessMethod) { + const sharedMethodStr = sharedProcessMethod.toString(); + const sharedFunctionBodyMatch = sharedMethodStr.match(/\{([\s\S]*)\}/); + if (sharedFunctionBodyMatch) { + sharedProcessFunctionBody = sharedFunctionBodyMatch[1]; + } + } + return ` + // Worker脚本 - 支持SharedArrayBuffer + let sharedFloatArray = null; + const ENTITY_DATA_SIZE = ${entityDataSize}; + + self.onmessage = function(e) { + const { type, id, entities, deltaTime, systemConfig, startIndex, endIndex, sharedBuffer } = e.data; + + + try { + // 处理SharedArrayBuffer初始化 + if (type === 'init' && sharedBuffer) { + sharedFloatArray = new Float32Array(sharedBuffer); + self.postMessage({ type: 'init', success: true }); + return; + } + + // 处理SharedArrayBuffer数据 + if (type === 'shared' && sharedFloatArray) { + processSharedArrayBuffer(startIndex, endIndex, deltaTime, systemConfig); + self.postMessage({ id, result: null }); // SharedArrayBuffer不需要返回数据 + return; + } + + // 传统处理方式 + if (entities) { + // 定义处理函数 + function workerProcess(entities, deltaTime, systemConfig) { + ${functionBody} + } + + // 执行处理 + const result = workerProcess(entities, deltaTime, systemConfig); + + // 处理Promise返回值 + if (result && typeof result.then === 'function') { + result.then(finalResult => { + self.postMessage({ id, result: finalResult }); + }).catch(error => { + self.postMessage({ id, error: error.message }); + }); + } else { + self.postMessage({ id, result }); + } + } + } catch (error) { + self.postMessage({ id, error: error.message }); + } + }; + + // SharedArrayBuffer处理函数 - 由子类定义 + function processSharedArrayBuffer(startIndex, endIndex, deltaTime, systemConfig) { + if (!sharedFloatArray) return; + + ${sharedProcessFunctionBody ? ` + // 用户定义的处理函数 + const userProcessFunction = function(sharedFloatArray, startIndex, endIndex, deltaTime, systemConfig) { + ${sharedProcessFunctionBody} + }; + userProcessFunction(sharedFloatArray, startIndex, endIndex, deltaTime, systemConfig); + ` : ``} + } + `; + } + /** + * 重写process方法,支持Worker并行处理 + */ + process(entities) { + if (this.isProcessing) + return; + this.isProcessing = true; + try { + if (this.config.enableWorker && this.workerPool) { + if (this.config.useSharedArrayBuffer && this.sharedFloatArray) { + this.processWithSharedArrayBuffer(entities).finally(() => { + this.isProcessing = false; + }); + } else { + this.processWithWorker(entities).finally(() => { + this.isProcessing = false; + }); + } + } else { + this.processSynchronously(entities); + this.isProcessing = false; + } + } catch (error) { + this.isProcessing = false; + throw error; + } + } + /** + * 使用SharedArrayBuffer优化的Worker处理 + */ + async processWithSharedArrayBuffer(entities) { + if (!this.sharedFloatArray) { + throw new Error("SharedArrayBuffer not initialized"); + } + this.writeEntitiesToSharedBuffer(entities); + const promises = this.createSharedArrayBufferTasks(entities.length); + await Promise.all(promises); + this.readResultsFromSharedBuffer(entities); + } + /** + * 使用Worker并行处理 + */ + async processWithWorker(entities) { + const entityData = []; + for (let i = 0; i < entities.length; i++) { + entityData[i] = this.extractEntityData(entities[i]); + } + const batches = this.createBatches(entityData); + const deltaTime = Time.deltaTime; + const promises = batches.map((batch) => this.workerPool.execute({ + entities: batch, + deltaTime, + systemConfig: this.config.systemConfig + })); + const results = await Promise.all(promises); + let entityIndex = 0; + for (const batchResult of results) { + for (const result of batchResult) { + if (entityIndex < entities.length) { + const entity = entities[entityIndex]; + if (entity && result) { + this.applyResult(entity, result); + } + } + entityIndex++; + } + } + } + /** + * 同步处理(fallback) + */ + processSynchronously(entities) { + const entityData = entities.map((entity) => this.extractEntityData(entity)); + const deltaTime = Time.deltaTime; + const results = this.workerProcess(entityData, deltaTime, this.config.systemConfig); + if (results && typeof results.then === "function") { + results.then((finalResults) => { + entities.forEach((entity, index) => { + this.applyResult(entity, finalResults[index]); + }); + }); + } else { + entities.forEach((entity, index) => { + this.applyResult(entity, results[index]); + }); + } + } + /** + * 创建数据批次 - 按Worker数量平均分配 + */ + createBatches(data) { + const workerCount = this.config.workerCount; + const batches = []; + const batchSize = Math.ceil(data.length / workerCount); + for (let i = 0; i < workerCount; i++) { + const startIndex = i * batchSize; + const endIndex = Math.min(startIndex + batchSize, data.length); + if (startIndex < data.length) { + batches.push(data.slice(startIndex, endIndex)); + } + } + return batches; + } + /** + * 将实体数据写入SharedArrayBuffer + */ + writeEntitiesToSharedBuffer(entities) { + if (!this.sharedFloatArray) + return; + for (let i = 0; i < entities.length && i < this.config.maxEntities; i++) { + const entity = entities[i]; + const data = this.extractEntityData(entity); + const offset = i * this.config.entityDataSize; + this.writeEntityToBuffer(data, offset); + } + } + /** + * 创建SharedArrayBuffer任务 + */ + createSharedArrayBufferTasks(entityCount) { + const promises = []; + const entitiesPerWorker = Math.ceil(entityCount / this.config.workerCount); + for (let i = 0; i < this.config.workerCount; i++) { + const startIndex = i * entitiesPerWorker; + const endIndex = Math.min(startIndex + entitiesPerWorker, entityCount); + if (startIndex < entityCount) { + const promise = this.workerPool.executeSharedBuffer({ + startIndex, + endIndex, + deltaTime: Time.deltaTime, + systemConfig: this.config.systemConfig + }); + promises.push(promise); + } + } + return promises; + } + /** + * 从SharedArrayBuffer读取结果并应用 + */ + readResultsFromSharedBuffer(entities) { + if (!this.sharedFloatArray) + return; + for (let i = 0; i < entities.length && i < this.config.maxEntities; i++) { + const entity = entities[i]; + const offset = i * this.config.entityDataSize; + const result = this.readEntityFromBuffer(offset); + if (result) { + this.applyResult(entity, result); + } + } + } + /** + * 更新Worker配置 + */ + updateConfig(newConfig) { + Object.assign(this.config, newConfig); + if (!this.config.enableWorker && this.workerPool) { + this.workerPool.destroy(); + this.workerPool = null; + } + if (this.config.enableWorker && !this.workerPool && this.isWorkerSupported()) { + this.initializeWorkerPool(); + } + } + /** + * 获取系统性能信息 + */ + getWorkerInfo() { + return { + enabled: this.config.enableWorker, + workerCount: this.config.workerCount, + isProcessing: this.isProcessing + }; + } + /** + * 销毁系统时清理Worker池 + */ + onDestroy() { + super.onDestroy(); + if (this.workerPool) { + this.workerPool.destroy(); + this.workerPool = null; + } + } +} +class WebWorkerPool { + constructor(workerCount, script, sharedBuffer) { + this.workers = []; + this.taskQueue = []; + this.busyWorkers = /* @__PURE__ */ new Set(); + this.taskCounter = 0; + this.sharedBuffer = null; + this.sharedBuffer = sharedBuffer || null; + const blob = new Blob([script], { type: "application/javascript" }); + const scriptURL = URL.createObjectURL(blob); + for (let i = 0; i < workerCount; i++) { + const worker = new Worker(scriptURL); + worker.onmessage = (e) => this.handleWorkerMessage(i, e.data); + worker.onerror = (error) => this.handleWorkerError(i, error); + if (sharedBuffer) { + worker.postMessage({ + type: "init", + sharedBuffer + }); + } + this.workers.push(worker); + } + URL.revokeObjectURL(scriptURL); + } + /** + * 执行SharedArrayBuffer任务 + */ + executeSharedBuffer(data) { + return new Promise((resolve, reject) => { + const task = { + id: `shared-task-${++this.taskCounter}`, + data: { ...data, type: "shared" }, + resolve: () => resolve(), + // SharedArrayBuffer不需要返回数据 + reject + }; + this.taskQueue.push(task); + this.processQueue(); + }); + } + /** + * 执行任务 + */ + execute(data) { + return new Promise((resolve, reject) => { + const task = { + id: `task-${++this.taskCounter}`, + data, + resolve: (result) => { + resolve(result); + }, + reject + }; + this.taskQueue.push(task); + this.processQueue(); + }); + } + /** + * 处理任务队列 + */ + processQueue() { + if (this.taskQueue.length === 0) + return; + for (let i = 0; i < this.workers.length; i++) { + if (!this.busyWorkers.has(i) && this.taskQueue.length > 0) { + const task = this.taskQueue.shift(); + this.busyWorkers.add(i); + this.workers[i].postMessage({ + id: task.id, + ...task.data + }); + this.workers[i]._currentTask = task; + } + } + } + /** + * 处理Worker消息 + */ + handleWorkerMessage(workerIndex, data) { + const worker = this.workers[workerIndex]; + const task = worker._currentTask; + if (!task) + return; + this.busyWorkers.delete(workerIndex); + worker._currentTask = null; + if (data.error) { + task.reject(new Error(data.error)); + } else { + task.resolve(data.result); + } + this.processQueue(); + } + /** + * 处理Worker错误 + */ + handleWorkerError(workerIndex, error) { + const worker = this.workers[workerIndex]; + const task = worker._currentTask; + if (task) { + this.busyWorkers.delete(workerIndex); + worker._currentTask = null; + task.reject(new Error(error.message)); + } + this.processQueue(); + } + /** + * 销毁Worker池 + */ + destroy() { + for (const worker of this.workers) { + worker.terminate(); + } + this.workers.length = 0; + this.taskQueue.length = 0; + this.busyWorkers.clear(); + } +} +var __defProp$3 = Object.defineProperty; +var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor; +var __decorateClass$3 = (decorators, target, key, kind) => { + var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target; + for (var i = decorators.length - 1, decorator; i >= 0; i--) + if (decorator = decorators[i]) + result = (kind ? decorator(target, key, result) : decorator(result)) || result; + if (kind && result) + __defProp$3(target, key, result); + return result; +}; +let Position = class extends Component { + constructor(x = 0, y = 0) { + super(); + this.x = 0; + this.y = 0; + this.x = x; + this.y = y; + } + set(x, y) { + this.x = x; + this.y = y; + } +}; +Position = __decorateClass$3([ + ECSComponent("Position") +], Position); +let Velocity = class extends Component { + constructor(dx = 0, dy = 0) { + super(); + this.dx = 0; + this.dy = 0; + this.dx = dx; + this.dy = dy; + } + set(dx, dy) { + this.dx = dx; + this.dy = dy; + } + scale(factor) { + this.dx *= factor; + this.dy *= factor; + } +}; +Velocity = __decorateClass$3([ + ECSComponent("Velocity") +], Velocity); +let Physics = class extends Component { + constructor(mass = 1, bounce = 0.8, friction = 0.95) { + super(); + this.mass = 1; + this.bounce = 0.8; + this.friction = 0.95; + this.mass = mass; + this.bounce = bounce; + this.friction = friction; + } +}; +Physics = __decorateClass$3([ + ECSComponent("Physics") +], Physics); +let Renderable = class extends Component { + constructor(color = "#ffffff", size = 5, shape = "circle") { + super(); + this.color = "#ffffff"; + this.size = 5; + this.shape = "circle"; + this.color = color; + this.size = size; + this.shape = shape; + } +}; +Renderable = __decorateClass$3([ + ECSComponent("Renderable") +], Renderable); +let Lifetime = class extends Component { + constructor(maxAge = 5) { + super(); + this.maxAge = 5; + this.currentAge = 0; + this.maxAge = maxAge; + this.currentAge = 0; + } + isDead() { + return this.currentAge >= this.maxAge; + } +}; +Lifetime = __decorateClass$3([ + ECSComponent("Lifetime") +], Lifetime); +var __defProp$2 = Object.defineProperty; +var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor; +var __decorateClass$2 = (decorators, target, key, kind) => { + var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target; + for (var i = decorators.length - 1, decorator; i >= 0; i--) + if (decorator = decorators[i]) + result = (kind ? decorator(target, key, result) : decorator(result)) || result; + if (kind && result) + __defProp$2(target, key, result); + return result; +}; +let PhysicsWorkerSystem = class extends WorkerEntitySystem { + constructor(enableWorker = true) { + const defaultConfig = { + gravity: 100, + canvasWidth: 800, + canvasHeight: 600, + groundFriction: 0.98 + }; + super( + Matcher.empty().all(Position, Velocity, Physics), + { + enableWorker, + workerCount: navigator.hardwareConcurrency || 2, + systemConfig: defaultConfig, + useSharedArrayBuffer: true + // 启用SharedArrayBuffer优化 + } + ); + this.physicsConfig = { + gravity: 100, + canvasWidth: 800, + canvasHeight: 600, + groundFriction: 0.98 + // 减少地面摩擦 + }; + this.startTime = 0; + } + extractEntityData(entity) { + const position = entity.getComponent(Position); + const velocity = entity.getComponent(Velocity); + const physics = entity.getComponent(Physics); + const renderable = entity.getComponent(Renderable); + return { + id: entity.id, + x: position.x, + y: position.y, + dx: velocity.dx, + dy: velocity.dy, + mass: physics.mass, + bounce: physics.bounce, + friction: physics.friction, + radius: renderable.size + }; + } + /** + * Worker处理函数 - 纯函数,会被序列化到Worker中执行 + * 注意:这个函数内部不能访问外部变量,必须是纯函数 + * 添加了小球间碰撞检测,大大增加计算复杂度 + */ + workerProcess(entities, deltaTime, systemConfig) { + const config = systemConfig || { + gravity: 100, + canvasWidth: 800, + canvasHeight: 600, + groundFriction: 0.98 + }; + const result = entities.map((e) => ({ ...e })); + for (let i = 0; i < result.length; i++) { + const entity = result[i]; + entity.dy += config.gravity * deltaTime; + entity.x += entity.dx * deltaTime; + entity.y += entity.dy * deltaTime; + if (entity.x <= entity.radius) { + entity.x = entity.radius; + entity.dx = -entity.dx * entity.bounce; + } else if (entity.x >= config.canvasWidth - entity.radius) { + entity.x = config.canvasWidth - entity.radius; + entity.dx = -entity.dx * entity.bounce; + } + if (entity.y <= entity.radius) { + entity.y = entity.radius; + entity.dy = -entity.dy * entity.bounce; + } else if (entity.y >= config.canvasHeight - entity.radius) { + entity.y = config.canvasHeight - entity.radius; + entity.dy = -entity.dy * entity.bounce; + entity.dx *= config.groundFriction; + } + entity.dx *= entity.friction; + entity.dy *= entity.friction; + } + for (let i = 0; i < result.length; i++) { + for (let j = i + 1; j < result.length; j++) { + const ball1 = result[i]; + const ball2 = result[j]; + const dx = ball2.x - ball1.x; + const dy = ball2.y - ball1.y; + const distance = Math.sqrt(dx * dx + dy * dy); + const minDistance = ball1.radius + ball2.radius; + if (distance < minDistance && distance > 0) { + const nx = dx / distance; + const ny = dy / distance; + const overlap = minDistance - distance; + const separationX = nx * overlap * 0.5; + const separationY = ny * overlap * 0.5; + ball1.x -= separationX; + ball1.y -= separationY; + ball2.x += separationX; + ball2.y += separationY; + const relativeVelocityX = ball2.dx - ball1.dx; + const relativeVelocityY = ball2.dy - ball1.dy; + const velocityAlongNormal = relativeVelocityX * nx + relativeVelocityY * ny; + if (velocityAlongNormal > 0) + continue; + const restitution = (ball1.bounce + ball2.bounce) * 0.5; + const impulseScalar = -(1 + restitution) * velocityAlongNormal / (1 / ball1.mass + 1 / ball2.mass); + const impulseX = impulseScalar * nx; + const impulseY = impulseScalar * ny; + ball1.dx -= impulseX / ball1.mass; + ball1.dy -= impulseY / ball1.mass; + ball2.dx += impulseX / ball2.mass; + ball2.dy += impulseY / ball2.mass; + const energyLoss = 0.98; + ball1.dx *= energyLoss; + ball1.dy *= energyLoss; + ball2.dx *= energyLoss; + ball2.dy *= energyLoss; + } + } + } + return result; + } + /** + * 应用处理结果 - 将Worker计算结果应用回组件 + */ + applyResult(entity, result) { + if (!entity || !entity.enabled) { + return; + } + const position = entity.getComponent(Position); + const velocity = entity.getComponent(Velocity); + if (!position || !velocity) { + return; + } + position.set(result.x, result.y); + velocity.set(result.dx, result.dy); + } + /** + * 更新物理配置 + */ + updatePhysicsConfig(newConfig) { + Object.assign(this.physicsConfig, newConfig); + this.updateConfig({ systemConfig: this.physicsConfig }); + } + /** + * 获取物理配置 + */ + getPhysicsConfig() { + return { ...this.physicsConfig }; + } + /** + * 性能监控 - 重写onEnd来计算执行时间 + */ + onEnd() { + super.onEnd(); + const endTime = performance.now(); + const executionTime = endTime - this.startTime; + window.physicsExecutionTime = executionTime; + } + /** + * 获取实体数据大小 - 物理系统使用9个Float32值 + */ + getDefaultEntityDataSize() { + return 9; + } + /** + * 将实体数据写入SharedArrayBuffer + */ + writeEntityToBuffer(entityData, offset) { + const sharedArray = this.sharedFloatArray; + if (!sharedArray) + return; + const currentEntityCount = Math.floor(offset / 9) + 1; + sharedArray[0] = currentEntityCount; + const dataOffset = offset + 9; + sharedArray[dataOffset + 0] = entityData.id; + sharedArray[dataOffset + 1] = entityData.x; + sharedArray[dataOffset + 2] = entityData.y; + sharedArray[dataOffset + 3] = entityData.dx; + sharedArray[dataOffset + 4] = entityData.dy; + sharedArray[dataOffset + 5] = entityData.mass; + sharedArray[dataOffset + 6] = entityData.bounce; + sharedArray[dataOffset + 7] = entityData.friction; + sharedArray[dataOffset + 8] = entityData.radius; + } + /** + * 性能监控 - 重写onBegin来记录开始时间 + */ + onBegin() { + super.onBegin(); + this.startTime = performance.now(); + } + /** + * 从SharedArrayBuffer读取实体数据 + */ + readEntityFromBuffer(offset) { + const sharedArray = this.sharedFloatArray; + if (!sharedArray) + return null; + const dataOffset = offset + 9; + return { + id: sharedArray[dataOffset + 0], + x: sharedArray[dataOffset + 1], + y: sharedArray[dataOffset + 2], + dx: sharedArray[dataOffset + 3], + dy: sharedArray[dataOffset + 4], + mass: sharedArray[dataOffset + 5], + bounce: sharedArray[dataOffset + 6], + friction: sharedArray[dataOffset + 7], + radius: sharedArray[dataOffset + 8] + }; + } + /** + * 提供SharedArrayBuffer处理函数 - 物理系统的具体实现 + * 包含小球间碰撞检测的复杂计算 + */ + getSharedArrayBufferProcessFunction() { + return function(sharedFloatArray, startIndex, endIndex, deltaTime, systemConfig) { + const config = systemConfig || { + gravity: 100, + canvasWidth: 800, + canvasHeight: 600, + groundFriction: 0.98 + }; + const actualEntityCount = sharedFloatArray[0]; + for (let i = startIndex; i < endIndex && i < actualEntityCount; i++) { + const offset = i * 9 + 9; + const id = sharedFloatArray[offset + 0]; + if (id === 0) + continue; + let x = sharedFloatArray[offset + 1]; + let y = sharedFloatArray[offset + 2]; + let dx = sharedFloatArray[offset + 3]; + let dy = sharedFloatArray[offset + 4]; + sharedFloatArray[offset + 5]; + const bounce = sharedFloatArray[offset + 6]; + const friction = sharedFloatArray[offset + 7]; + const radius = sharedFloatArray[offset + 8]; + dy += config.gravity * deltaTime; + x += dx * deltaTime; + y += dy * deltaTime; + if (x <= radius) { + x = radius; + dx = -dx * bounce; + } else if (x >= config.canvasWidth - radius) { + x = config.canvasWidth - radius; + dx = -dx * bounce; + } + if (y <= radius) { + y = radius; + dy = -dy * bounce; + } else if (y >= config.canvasHeight - radius) { + y = config.canvasHeight - radius; + dy = -dy * bounce; + dx *= config.groundFriction; + } + dx *= friction; + dy *= friction; + sharedFloatArray[offset + 1] = x; + sharedFloatArray[offset + 2] = y; + sharedFloatArray[offset + 3] = dx; + sharedFloatArray[offset + 4] = dy; + } + for (let i = startIndex; i < endIndex && i < actualEntityCount; i++) { + const offset1 = i * 9 + 9; + const id1 = sharedFloatArray[offset1 + 0]; + if (id1 === 0) + continue; + let x1 = sharedFloatArray[offset1 + 1]; + let y1 = sharedFloatArray[offset1 + 2]; + let dx1 = sharedFloatArray[offset1 + 3]; + let dy1 = sharedFloatArray[offset1 + 4]; + const mass1 = sharedFloatArray[offset1 + 5]; + const bounce1 = sharedFloatArray[offset1 + 6]; + const radius1 = sharedFloatArray[offset1 + 8]; + for (let j = 0; j < actualEntityCount; j++) { + if (i === j) + continue; + const offset2 = j * 9 + 9; + const id2 = sharedFloatArray[offset2 + 0]; + if (id2 === 0) + continue; + const x2 = sharedFloatArray[offset2 + 1]; + const y2 = sharedFloatArray[offset2 + 2]; + const dx2 = sharedFloatArray[offset2 + 3]; + const dy2 = sharedFloatArray[offset2 + 4]; + const mass2 = sharedFloatArray[offset2 + 5]; + const bounce2 = sharedFloatArray[offset2 + 6]; + const radius2 = sharedFloatArray[offset2 + 8]; + if (isNaN(x2) || isNaN(y2) || isNaN(radius2) || radius2 <= 0) + continue; + const deltaX = x2 - x1; + const deltaY = y2 - y1; + const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); + const minDistance = radius1 + radius2; + if (distance < minDistance && distance > 0) { + const nx = deltaX / distance; + const ny = deltaY / distance; + const overlap = minDistance - distance; + const separationX = nx * overlap * 0.5; + const separationY = ny * overlap * 0.5; + x1 -= separationX; + y1 -= separationY; + const relativeVelocityX = dx2 - dx1; + const relativeVelocityY = dy2 - dy1; + const velocityAlongNormal = relativeVelocityX * nx + relativeVelocityY * ny; + if (velocityAlongNormal > 0) + continue; + const restitution = (bounce1 + bounce2) * 0.5; + const impulseScalar = -(1 + restitution) * velocityAlongNormal / (1 / mass1 + 1 / mass2); + const impulseX = impulseScalar * nx; + const impulseY = impulseScalar * ny; + dx1 -= impulseX / mass1; + dy1 -= impulseY / mass1; + if (i < j) { + const energyLoss = 0.98; + dx1 *= energyLoss; + dy1 *= energyLoss; + } + } + } + sharedFloatArray[offset1 + 1] = x1; + sharedFloatArray[offset1 + 2] = y1; + sharedFloatArray[offset1 + 3] = dx1; + sharedFloatArray[offset1 + 4] = dy1; + } + }; + } +}; +PhysicsWorkerSystem = __decorateClass$2([ + ECSSystem("PhysicsWorkerSystem") +], PhysicsWorkerSystem); +var __defProp$1 = Object.defineProperty; +var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor; +var __decorateClass$1 = (decorators, target, key, kind) => { + var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target; + for (var i = decorators.length - 1, decorator; i >= 0; i--) + if (decorator = decorators[i]) + result = (kind ? decorator(target, key, result) : decorator(result)) || result; + if (kind && result) + __defProp$1(target, key, result); + return result; +}; +let RenderSystem = class extends EntitySystem { + constructor(canvas) { + super(Matcher.empty().all(Position, Renderable)); + this.startTime = 0; + this.batchCount = 0; + this.drawCallCount = 0; + this.canvas = canvas; + this.ctx = canvas.getContext("2d"); + } + onBegin() { + super.onBegin(); + this.startTime = performance.now(); + this.ctx.fillStyle = "#000000"; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + } + process(entities) { + let lastColor = ""; + this.drawCallCount = 0; + for (const entity of entities) { + const position = entity.getComponent(Position); + const renderable = entity.getComponent(Renderable); + if (renderable.color !== lastColor) { + this.ctx.fillStyle = renderable.color; + lastColor = renderable.color; + } + if (renderable.shape === "circle") { + this.ctx.beginPath(); + this.ctx.arc(position.x, position.y, renderable.size, 0, Math.PI * 2); + this.ctx.fill(); + this.drawCallCount++; + } else if (renderable.shape === "square") { + this.ctx.fillRect( + position.x - renderable.size / 2, + position.y - renderable.size / 2, + renderable.size, + renderable.size + ); + this.drawCallCount++; + } + } + const uniqueColors = new Set(entities.map((e) => e.getComponent(Renderable).color)); + this.batchCount = uniqueColors.size; + } + onEnd() { + super.onEnd(); + const endTime = performance.now(); + const executionTime = endTime - this.startTime; + window.renderExecutionTime = executionTime; + this.drawDebugInfo(); + } + drawDebugInfo() { + const entities = this.entities; + this.ctx.fillStyle = "#00ff00"; + this.ctx.font = "14px Arial"; + this.ctx.fillText(`实体数量: ${entities.length}`, 10, 20); + this.ctx.fillText(`渲染批次: ${this.batchCount}`, 10, 140); + this.ctx.fillText(`绘制调用: ${this.drawCallCount}`, 10, 160); + const workerInfo = window.workerInfo; + if (workerInfo) { + this.ctx.fillStyle = workerInfo.enabled ? "#00ff00" : "#ff0000"; + this.ctx.fillText(`Worker: ${workerInfo.enabled ? "启用" : "禁用"}`, 10, 40); + if (workerInfo.enabled) { + this.ctx.fillStyle = "#ffff00"; + const entitiesPerWorker = Math.ceil(entities.length / workerInfo.workerCount); + this.ctx.fillText(`每个Worker实体: ${entitiesPerWorker}`, 10, 60); + this.ctx.fillText(`Worker数量: ${workerInfo.workerCount}`, 10, 80); + } + } + const physicsTime = window.physicsExecutionTime || 0; + const renderTime = window.renderExecutionTime || 0; + this.ctx.fillStyle = physicsTime > 16 ? "#ff0000" : physicsTime > 8 ? "#ffff00" : "#00ff00"; + this.ctx.fillText(`物理: ${physicsTime.toFixed(2)}ms`, 10, 100); + this.ctx.fillStyle = renderTime > 16 ? "#ff0000" : renderTime > 8 ? "#ffff00" : "#00ff00"; + this.ctx.fillText(`渲染: ${renderTime.toFixed(2)}ms`, 10, 120); + } +}; +RenderSystem = __decorateClass$1([ + ECSSystem("RenderSystem") +], RenderSystem); +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __decorateClass = (decorators, target, key, kind) => { + var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target; + for (var i = decorators.length - 1, decorator; i >= 0; i--) + if (decorator = decorators[i]) + result = (kind ? decorator(target, key, result) : decorator(result)) || result; + if (kind && result) + __defProp(target, key, result); + return result; +}; +let LifetimeSystem = class extends EntitySystem { + constructor() { + super(Matcher.empty().all(Lifetime)); + } + process(entities) { + const entitiesToRemove = []; + for (const entity of entities) { + const lifetime = entity.getComponent(Lifetime); + lifetime.currentAge += Time.deltaTime; + if (lifetime.isDead()) { + entitiesToRemove.push(entity); + } + } + for (const entity of entitiesToRemove) { + entity.destroy(); + } + } +}; +LifetimeSystem = __decorateClass([ + ECSSystem("LifetimeSystem") +], LifetimeSystem); +class GameScene extends Scene { + constructor(canvas) { + super(); + this.canvas = canvas; + } + initialize() { + this.name = "WorkerDemoScene"; + this.physicsSystem = new PhysicsWorkerSystem(true); + this.renderSystem = new RenderSystem(this.canvas); + this.lifetimeSystem = new LifetimeSystem(); + this.physicsSystem.updateOrder = 1; + this.lifetimeSystem.updateOrder = 2; + this.renderSystem.updateOrder = 3; + this.addSystem(this.physicsSystem); + this.addSystem(this.lifetimeSystem); + this.addSystem(this.renderSystem); + } + onStart() { + console.log("Worker演示场景已启动"); + this.spawnInitialEntities(); + } + unload() { + console.log("Worker演示场景已卸载"); + } + /** + * 生成初始实体 + */ + spawnInitialEntities(count = 1e3) { + this.clearAllEntities(); + for (let i = 0; i < count; i++) { + this.createParticle(); + } + } + /** + * 创建一个粒子实体 + */ + createParticle() { + const entity = this.createEntity(`Particle_${Date.now()}_${Math.random()}`); + const x = Math.random() * (this.canvas.width - 20) + 10; + const y = Math.random() * (this.canvas.height - 20) + 10; + const dx = (Math.random() - 0.5) * 200; + const dy = (Math.random() - 0.5) * 200; + const mass = Math.random() * 3 + 2; + const bounce = 0.85 + Math.random() * 0.15; + const friction = 0.998 + Math.random() * 2e-3; + const colors = [ + "#ff4444", + "#44ff44", + "#4444ff", + "#ffff44", + "#ff44ff", + "#44ffff", + "#ffffff", + "#ff8844", + "#88ff44", + "#4488ff", + "#ff4488", + "#88ff88", + "#8888ff", + "#ffaa44", + "#aaff44", + "#44aaff", + "#ff44aa", + "#aa44ff", + "#44ffaa", + "#cccccc" + ]; + const color = colors[Math.floor(Math.random() * colors.length)]; + const size = Math.random() * 6 + 3; + entity.addComponent(new Position(x, y)); + entity.addComponent(new Velocity(dx, dy)); + entity.addComponent(new Physics(mass, bounce, friction)); + entity.addComponent(new Renderable(color, size, "circle")); + entity.addComponent(new Lifetime(5 + Math.random() * 10)); + } + /** + * 生成粒子爆发效果 + */ + spawnParticleExplosion(centerX, centerY, count = 50) { + for (let i = 0; i < count; i++) { + const entity = this.createEntity(`Explosion_${Date.now()}_${i}`); + const angle = Math.PI * 2 * i / count + (Math.random() - 0.5) * 0.5; + const distance = Math.random() * 30; + const x = centerX + Math.cos(angle) * distance; + const y = centerY + Math.sin(angle) * distance; + const speed = 100 + Math.random() * 150; + const dx = Math.cos(angle) * speed; + const dy = Math.sin(angle) * speed; + const mass = 0.5 + Math.random() * 1; + const bounce = 0.8 + Math.random() * 0.2; + const colors = ["#ffaa00", "#ff6600", "#ff0066", "#ff3300", "#ffff00"]; + const color = colors[Math.floor(Math.random() * colors.length)]; + const size = Math.random() * 4 + 2; + entity.addComponent(new Position(x, y)); + entity.addComponent(new Velocity(dx, dy)); + entity.addComponent(new Physics(mass, bounce, 0.999)); + entity.addComponent(new Renderable(color, size, "circle")); + entity.addComponent(new Lifetime(2 + Math.random() * 3)); + } + } + /** + * 清空所有实体 + */ + clearAllEntities() { + const entities = [...this.entities.buffer]; + for (const entity of entities) { + entity.destroy(); + } + } + /** + * 切换Worker启用状态 + */ + toggleWorker() { + const workerInfo = this.physicsSystem.getWorkerInfo(); + const newWorkerEnabled = !workerInfo.enabled; + this.removeSystem(this.physicsSystem); + this.physicsSystem = new PhysicsWorkerSystem(newWorkerEnabled); + this.physicsSystem.updateOrder = 1; + this.addSystem(this.physicsSystem); + return newWorkerEnabled; + } + /** + * 更新Worker配置 + */ + updateWorkerConfig(config) { + if (config.gravity !== void 0 || config.friction !== void 0) { + const physicsConfig = this.physicsSystem.getPhysicsConfig(); + this.physicsSystem.updatePhysicsConfig({ + gravity: config.gravity ?? physicsConfig.gravity, + groundFriction: config.friction ?? physicsConfig.groundFriction + }); + } + } + /** + * 获取系统信息 + */ + getSystemInfo() { + return { + physics: this.physicsSystem.getWorkerInfo(), + entityCount: this.entities.count, + physicsConfig: this.physicsSystem.getPhysicsConfig() + }; + } +} +class WorkerDemo { + constructor() { + this.isRunning = false; + this.lastTime = 0; + this.frameCount = 0; + this.fpsUpdateTime = 0; + this.currentFPS = 0; + this.lastWorkerStatusUpdate = 0; + this.elements = {}; + this.gameLoop = () => { + if (!this.isRunning) + return; + const currentTime = performance.now(); + const deltaTime = (currentTime - this.lastTime) / 1e3; + this.lastTime = currentTime; + const frameStartTime = performance.now(); + Core.update(deltaTime); + const frameEndTime = performance.now(); + this.updatePerformanceStats({ + fps: this.currentFPS, + frameTime: frameEndTime - frameStartTime, + physicsTime: window.physicsExecutionTime || 0, + renderTime: window.renderExecutionTime || 0, + memoryUsage: this.getMemoryUsage() + }); + this.frameCount++; + if (currentTime - this.fpsUpdateTime >= 1e3) { + this.currentFPS = this.frameCount; + this.frameCount = 0; + this.fpsUpdateTime = currentTime; + } + this.updateUI(); + requestAnimationFrame(this.gameLoop); + }; + this.canvas = document.getElementById("gameCanvas"); + if (!this.canvas) { + throw new Error("Canvas element not found"); + } + this.initializeUIElements(); + Core.create({ + debug: true, + enableEntitySystems: true + }); + this.gameScene = new GameScene(this.canvas); + Core.setScene(this.gameScene); + this.bindEvents(); + this.start(); + } + initializeUIElements() { + const elementIds = [ + "entityCount", + "entityCountValue", + "toggleWorker", + "gravity", + "gravityValue", + "friction", + "frictionValue", + "spawnParticles", + "clearEntities", + "resetDemo", + "fps", + "entityCountStat", + "workerStatus", + "workerLoad", + "physicsTime", + "renderTime", + "frameTime", + "memoryUsage" + ]; + for (const id of elementIds) { + const element = document.getElementById(id); + if (element) { + this.elements[id] = element; + } else { + console.warn(`Element with id '${id}' not found`); + } + } + } + bindEvents() { + if (this.elements.entityCount && this.elements.entityCountValue) { + const slider = this.elements.entityCount; + slider.addEventListener("input", () => { + this.elements.entityCountValue.textContent = slider.value; + }); + slider.addEventListener("change", () => { + const count = parseInt(slider.value); + this.gameScene.spawnInitialEntities(count); + }); + } + if (this.elements.toggleWorker) { + this.elements.toggleWorker.addEventListener("click", () => { + const workerEnabled = this.gameScene.toggleWorker(); + this.elements.toggleWorker.textContent = workerEnabled ? "禁用 Worker" : "启用 Worker"; + this.updateWorkerStatus(); + }); + } + if (this.elements.gravity && this.elements.gravityValue) { + const slider = this.elements.gravity; + slider.addEventListener("input", () => { + this.elements.gravityValue.textContent = slider.value; + }); + slider.addEventListener("change", () => { + const gravity = parseInt(slider.value); + this.gameScene.updateWorkerConfig({ gravity }); + }); + } + if (this.elements.friction && this.elements.frictionValue) { + const slider = this.elements.friction; + slider.addEventListener("input", () => { + const value = parseInt(slider.value); + this.elements.frictionValue.textContent = `${value}%`; + }); + slider.addEventListener("change", () => { + const friction = parseInt(slider.value) / 100; + this.gameScene.updateWorkerConfig({ friction }); + }); + } + if (this.elements.spawnParticles) { + this.elements.spawnParticles.addEventListener("click", () => { + const centerX = this.canvas.width / 2; + const centerY = this.canvas.height / 2; + this.gameScene.spawnParticleExplosion(centerX, centerY, 100); + }); + } + if (this.elements.clearEntities) { + this.elements.clearEntities.addEventListener("click", () => { + this.gameScene.clearAllEntities(); + }); + } + if (this.elements.resetDemo) { + this.elements.resetDemo.addEventListener("click", () => { + this.resetDemo(); + }); + } + this.canvas.addEventListener("click", (event) => { + const rect = this.canvas.getBoundingClientRect(); + const x = event.clientX - rect.left; + const y = event.clientY - rect.top; + this.gameScene.spawnParticleExplosion(x, y, 30); + }); + } + start() { + this.isRunning = true; + this.lastTime = performance.now(); + this.gameLoop(); + console.log("Worker演示已启动"); + } + updatePerformanceStats(stats) { + if (this.elements.fps) { + this.elements.fps.textContent = stats.fps.toString(); + this.elements.fps.className = stats.fps >= 55 ? "performance-high" : stats.fps >= 30 ? "performance-medium" : "performance-low"; + } + if (this.elements.frameTime) { + this.elements.frameTime.textContent = stats.frameTime.toFixed(2); + this.elements.frameTime.className = stats.frameTime <= 16 ? "performance-high" : stats.frameTime <= 33 ? "performance-medium" : "performance-low"; + } + if (this.elements.physicsTime) { + this.elements.physicsTime.textContent = stats.physicsTime.toFixed(2); + this.elements.physicsTime.className = stats.physicsTime <= 8 ? "performance-high" : stats.physicsTime <= 16 ? "performance-medium" : "performance-low"; + } + if (this.elements.renderTime) { + this.elements.renderTime.textContent = stats.renderTime.toFixed(2); + this.elements.renderTime.className = stats.renderTime <= 8 ? "performance-high" : stats.renderTime <= 16 ? "performance-medium" : "performance-low"; + } + if (this.elements.memoryUsage) { + this.elements.memoryUsage.textContent = stats.memoryUsage.toFixed(1); + } + } + updateUI() { + const currentTime = performance.now(); + const systemInfo = this.gameScene.getSystemInfo(); + if (this.elements.entityCountStat) { + this.elements.entityCountStat.textContent = systemInfo.entityCount.toString(); + } + if (currentTime - this.lastWorkerStatusUpdate >= 500) { + this.updateWorkerStatus(); + this.lastWorkerStatusUpdate = currentTime; + } + window.workerInfo = systemInfo.physics; + } + updateWorkerStatus() { + const systemInfo = this.gameScene.getSystemInfo(); + const workerInfo = systemInfo.physics; + const entityCount = systemInfo.entityCount; + if (this.elements.workerStatus) { + if (workerInfo.enabled) { + this.elements.workerStatus.textContent = `启用 (${workerInfo.workerCount} Workers)`; + this.elements.workerStatus.className = "worker-enabled"; + } else { + this.elements.workerStatus.textContent = "禁用"; + this.elements.workerStatus.className = "worker-disabled"; + } + } + if (this.elements.workerLoad) { + if (workerInfo.enabled && entityCount > 0) { + const entitiesPerWorker = Math.ceil(entityCount / workerInfo.workerCount); + this.elements.workerLoad.textContent = `${entitiesPerWorker}/Worker (共${workerInfo.workerCount}个)`; + } else { + this.elements.workerLoad.textContent = "N/A"; + } + } + } + getMemoryUsage() { + if ("memory" in performance) { + const memory = performance.memory; + return memory.usedJSHeapSize / (1024 * 1024); + } + return 0; + } + resetDemo() { + if (this.elements.entityCount) { + this.elements.entityCount.value = "1000"; + this.elements.entityCountValue.textContent = "1000"; + } + if (this.elements.gravity) { + this.elements.gravity.value = "100"; + this.elements.gravityValue.textContent = "100"; + } + if (this.elements.friction) { + this.elements.friction.value = "95"; + this.elements.frictionValue.textContent = "95%"; + } + const workerInfo = this.gameScene.getSystemInfo().physics; + if (!workerInfo.enabled) { + this.gameScene.toggleWorker(); + } + if (this.elements.toggleWorker) { + this.elements.toggleWorker.textContent = "禁用 Worker"; + } + this.gameScene.spawnInitialEntities(1e3); + this.gameScene.updateWorkerConfig({ + gravity: 100, + friction: 0.95 + }); + console.log("演示已重置"); + } + stop() { + this.isRunning = false; + } +} +document.addEventListener("DOMContentLoaded", () => { + try { + new WorkerDemo(); + } catch (error) { + console.error("启动演示失败:", error); + document.body.innerHTML = ` +
+

启动失败

+

错误: ${error}

+

请确保浏览器支持Web Workers和Canvas API

+
+ `; + } +}); diff --git a/docs/public/demos/worker-system/index.html b/docs/public/demos/worker-system/index.html new file mode 100644 index 00000000..0d59412c --- /dev/null +++ b/docs/public/demos/worker-system/index.html @@ -0,0 +1,176 @@ + + + + + + ECS Framework Worker System Demo + + + + +
+

ECS Framework Worker System 演示

+ +
+
+ +
+ +
+
+ + + 1000 +
+ +
+ + +
+ +
+ + + +
+ +
+ + + + + + +
+
+
+ +
+

性能统计

+
FPS: 0
+
实体数量: 0
+
Worker状态: 未启用
+
Worker负载: N/A
+
物理系统耗时: 0ms
+
渲染系统耗时: 0ms
+
总帧时间: 0ms
+
内存使用: 0MB
+
+
+ + + + \ No newline at end of file