@esengine/ecs-framework 2.1.4 → 2.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/README.md +385 -0
  2. package/{bin/index.d.ts → index.d.ts} +9 -6
  3. package/index.js +7 -0
  4. package/index.js.map +7 -0
  5. package/package.json +20 -46
  6. package/bin/Core.d.ts +0 -198
  7. package/bin/Core.d.ts.map +0 -1
  8. package/bin/Core.js +0 -247
  9. package/bin/Core.js.map +0 -1
  10. package/bin/ECS/Component.d.ts +0 -119
  11. package/bin/ECS/Component.d.ts.map +0 -1
  12. package/bin/ECS/Component.js +0 -129
  13. package/bin/ECS/Component.js.map +0 -1
  14. package/bin/ECS/Components/IUpdatable.d.ts +0 -22
  15. package/bin/ECS/Components/IUpdatable.d.ts.map +0 -1
  16. package/bin/ECS/Components/IUpdatable.js +0 -22
  17. package/bin/ECS/Components/IUpdatable.js.map +0 -1
  18. package/bin/ECS/Components/SceneComponent.d.ts +0 -40
  19. package/bin/ECS/Components/SceneComponent.d.ts.map +0 -1
  20. package/bin/ECS/Components/SceneComponent.js +0 -61
  21. package/bin/ECS/Components/SceneComponent.js.map +0 -1
  22. package/bin/ECS/Core/BitMaskOptimizer.d.ts +0 -75
  23. package/bin/ECS/Core/BitMaskOptimizer.d.ts.map +0 -1
  24. package/bin/ECS/Core/BitMaskOptimizer.js +0 -161
  25. package/bin/ECS/Core/BitMaskOptimizer.js.map +0 -1
  26. package/bin/ECS/Core/ComponentPool.d.ts +0 -72
  27. package/bin/ECS/Core/ComponentPool.d.ts.map +0 -1
  28. package/bin/ECS/Core/ComponentPool.js +0 -123
  29. package/bin/ECS/Core/ComponentPool.js.map +0 -1
  30. package/bin/ECS/Core/ComponentStorage.d.ts +0 -182
  31. package/bin/ECS/Core/ComponentStorage.d.ts.map +0 -1
  32. package/bin/ECS/Core/ComponentStorage.js +0 -346
  33. package/bin/ECS/Core/ComponentStorage.js.map +0 -1
  34. package/bin/ECS/Core/EventSystem.d.ts +0 -236
  35. package/bin/ECS/Core/EventSystem.d.ts.map +0 -1
  36. package/bin/ECS/Core/EventSystem.js +0 -476
  37. package/bin/ECS/Core/EventSystem.js.map +0 -1
  38. package/bin/ECS/Core/FluentAPI.d.ts +0 -371
  39. package/bin/ECS/Core/FluentAPI.d.ts.map +0 -1
  40. package/bin/ECS/Core/FluentAPI.js +0 -543
  41. package/bin/ECS/Core/FluentAPI.js.map +0 -1
  42. package/bin/ECS/Core/IndexUpdateBatcher.d.ts +0 -100
  43. package/bin/ECS/Core/IndexUpdateBatcher.d.ts.map +0 -1
  44. package/bin/ECS/Core/IndexUpdateBatcher.js +0 -219
  45. package/bin/ECS/Core/IndexUpdateBatcher.js.map +0 -1
  46. package/bin/ECS/Core/QuerySystem.d.ts +0 -422
  47. package/bin/ECS/Core/QuerySystem.d.ts.map +0 -1
  48. package/bin/ECS/Core/QuerySystem.js +0 -937
  49. package/bin/ECS/Core/QuerySystem.js.map +0 -1
  50. package/bin/ECS/CoreEvents.d.ts +0 -19
  51. package/bin/ECS/CoreEvents.d.ts.map +0 -1
  52. package/bin/ECS/CoreEvents.js +0 -20
  53. package/bin/ECS/CoreEvents.js.map +0 -1
  54. package/bin/ECS/Entity.d.ts +0 -538
  55. package/bin/ECS/Entity.d.ts.map +0 -1
  56. package/bin/ECS/Entity.js +0 -1030
  57. package/bin/ECS/Entity.js.map +0 -1
  58. package/bin/ECS/Scene.d.ts +0 -226
  59. package/bin/ECS/Scene.d.ts.map +0 -1
  60. package/bin/ECS/Scene.js +0 -308
  61. package/bin/ECS/Scene.js.map +0 -1
  62. package/bin/ECS/Systems/EntitySystem.d.ts +0 -185
  63. package/bin/ECS/Systems/EntitySystem.d.ts.map +0 -1
  64. package/bin/ECS/Systems/EntitySystem.js +0 -278
  65. package/bin/ECS/Systems/EntitySystem.js.map +0 -1
  66. package/bin/ECS/Systems/IntervalSystem.d.ts +0 -33
  67. package/bin/ECS/Systems/IntervalSystem.d.ts.map +0 -1
  68. package/bin/ECS/Systems/IntervalSystem.js +0 -50
  69. package/bin/ECS/Systems/IntervalSystem.js.map +0 -1
  70. package/bin/ECS/Systems/PassiveSystem.d.ts +0 -20
  71. package/bin/ECS/Systems/PassiveSystem.d.ts.map +0 -1
  72. package/bin/ECS/Systems/PassiveSystem.js +0 -21
  73. package/bin/ECS/Systems/PassiveSystem.js.map +0 -1
  74. package/bin/ECS/Systems/ProcessingSystem.d.ts +0 -24
  75. package/bin/ECS/Systems/ProcessingSystem.d.ts.map +0 -1
  76. package/bin/ECS/Systems/ProcessingSystem.js +0 -22
  77. package/bin/ECS/Systems/ProcessingSystem.js.map +0 -1
  78. package/bin/ECS/Systems/index.d.ts +0 -5
  79. package/bin/ECS/Systems/index.d.ts.map +0 -1
  80. package/bin/ECS/Systems/index.js +0 -6
  81. package/bin/ECS/Systems/index.js.map +0 -1
  82. package/bin/ECS/Utils/Bits.d.ts +0 -74
  83. package/bin/ECS/Utils/Bits.d.ts.map +0 -1
  84. package/bin/ECS/Utils/Bits.js +0 -142
  85. package/bin/ECS/Utils/Bits.js.map +0 -1
  86. package/bin/ECS/Utils/ComponentTypeManager.d.ts +0 -50
  87. package/bin/ECS/Utils/ComponentTypeManager.d.ts.map +0 -1
  88. package/bin/ECS/Utils/ComponentTypeManager.js +0 -84
  89. package/bin/ECS/Utils/ComponentTypeManager.js.map +0 -1
  90. package/bin/ECS/Utils/EntityList.d.ts +0 -108
  91. package/bin/ECS/Utils/EntityList.d.ts.map +0 -1
  92. package/bin/ECS/Utils/EntityList.js +0 -249
  93. package/bin/ECS/Utils/EntityList.js.map +0 -1
  94. package/bin/ECS/Utils/EntityProcessorList.d.ts +0 -53
  95. package/bin/ECS/Utils/EntityProcessorList.d.ts.map +0 -1
  96. package/bin/ECS/Utils/EntityProcessorList.js +0 -96
  97. package/bin/ECS/Utils/EntityProcessorList.js.map +0 -1
  98. package/bin/ECS/Utils/IdentifierPool.d.ts +0 -18
  99. package/bin/ECS/Utils/IdentifierPool.d.ts.map +0 -1
  100. package/bin/ECS/Utils/IdentifierPool.js +0 -27
  101. package/bin/ECS/Utils/IdentifierPool.js.map +0 -1
  102. package/bin/ECS/Utils/Matcher.d.ts +0 -63
  103. package/bin/ECS/Utils/Matcher.d.ts.map +0 -1
  104. package/bin/ECS/Utils/Matcher.js +0 -140
  105. package/bin/ECS/Utils/Matcher.js.map +0 -1
  106. package/bin/ECS/Utils/index.d.ts +0 -7
  107. package/bin/ECS/Utils/index.d.ts.map +0 -1
  108. package/bin/ECS/Utils/index.js +0 -8
  109. package/bin/ECS/Utils/index.js.map +0 -1
  110. package/bin/ECS/index.d.ts +0 -7
  111. package/bin/ECS/index.d.ts.map +0 -1
  112. package/bin/ECS/index.js +0 -29
  113. package/bin/ECS/index.js.map +0 -1
  114. package/bin/Testing/Performance/benchmark.d.ts +0 -6
  115. package/bin/Testing/Performance/benchmark.d.ts.map +0 -1
  116. package/bin/Testing/Performance/benchmark.js +0 -639
  117. package/bin/Testing/Performance/benchmark.js.map +0 -1
  118. package/bin/Testing/Performance/component-performance.d.ts +0 -2
  119. package/bin/Testing/Performance/component-performance.d.ts.map +0 -1
  120. package/bin/Testing/Performance/component-performance.js +0 -43
  121. package/bin/Testing/Performance/component-performance.js.map +0 -1
  122. package/bin/Testing/Unit/bitmask-optimizer.test.d.ts +0 -2
  123. package/bin/Testing/Unit/bitmask-optimizer.test.d.ts.map +0 -1
  124. package/bin/Testing/Unit/bitmask-optimizer.test.js +0 -164
  125. package/bin/Testing/Unit/bitmask-optimizer.test.js.map +0 -1
  126. package/bin/Testing/Unit/component-pool.test.d.ts +0 -5
  127. package/bin/Testing/Unit/component-pool.test.d.ts.map +0 -1
  128. package/bin/Testing/Unit/component-pool.test.js +0 -149
  129. package/bin/Testing/Unit/component-pool.test.js.map +0 -1
  130. package/bin/Testing/test-runner.d.ts +0 -51
  131. package/bin/Testing/test-runner.d.ts.map +0 -1
  132. package/bin/Testing/test-runner.js +0 -159
  133. package/bin/Testing/test-runner.js.map +0 -1
  134. package/bin/Types/index.d.ts +0 -22
  135. package/bin/Types/index.d.ts.map +0 -1
  136. package/bin/Types/index.js +0 -20
  137. package/bin/Types/index.js.map +0 -1
  138. package/bin/Utils/Emitter.d.ts +0 -43
  139. package/bin/Utils/Emitter.d.ts.map +0 -1
  140. package/bin/Utils/Emitter.js +0 -69
  141. package/bin/Utils/Emitter.js.map +0 -1
  142. package/bin/Utils/Extensions/NumberExtension.d.ts +0 -13
  143. package/bin/Utils/Extensions/NumberExtension.d.ts.map +0 -1
  144. package/bin/Utils/Extensions/NumberExtension.js +0 -17
  145. package/bin/Utils/Extensions/NumberExtension.js.map +0 -1
  146. package/bin/Utils/Extensions/TypeUtils.d.ts +0 -13
  147. package/bin/Utils/Extensions/TypeUtils.d.ts.map +0 -1
  148. package/bin/Utils/Extensions/TypeUtils.js +0 -15
  149. package/bin/Utils/Extensions/TypeUtils.js.map +0 -1
  150. package/bin/Utils/Extensions/index.d.ts +0 -3
  151. package/bin/Utils/Extensions/index.d.ts.map +0 -1
  152. package/bin/Utils/Extensions/index.js +0 -4
  153. package/bin/Utils/Extensions/index.js.map +0 -1
  154. package/bin/Utils/GlobalManager.d.ts +0 -32
  155. package/bin/Utils/GlobalManager.d.ts.map +0 -1
  156. package/bin/Utils/GlobalManager.js +0 -53
  157. package/bin/Utils/GlobalManager.js.map +0 -1
  158. package/bin/Utils/PerformanceMonitor.d.ts +0 -211
  159. package/bin/Utils/PerformanceMonitor.d.ts.map +0 -1
  160. package/bin/Utils/PerformanceMonitor.js +0 -270
  161. package/bin/Utils/PerformanceMonitor.js.map +0 -1
  162. package/bin/Utils/Pool.d.ts +0 -239
  163. package/bin/Utils/Pool.d.ts.map +0 -1
  164. package/bin/Utils/Pool.js +0 -449
  165. package/bin/Utils/Pool.js.map +0 -1
  166. package/bin/Utils/Time.d.ts +0 -55
  167. package/bin/Utils/Time.d.ts.map +0 -1
  168. package/bin/Utils/Time.js +0 -78
  169. package/bin/Utils/Time.js.map +0 -1
  170. package/bin/Utils/Timers/ITimer.d.ts +0 -16
  171. package/bin/Utils/Timers/ITimer.d.ts.map +0 -1
  172. package/bin/Utils/Timers/ITimer.js +0 -2
  173. package/bin/Utils/Timers/ITimer.js.map +0 -1
  174. package/bin/Utils/Timers/Timer.d.ts +0 -22
  175. package/bin/Utils/Timers/Timer.d.ts.map +0 -1
  176. package/bin/Utils/Timers/Timer.js +0 -46
  177. package/bin/Utils/Timers/Timer.js.map +0 -1
  178. package/bin/Utils/Timers/TimerManager.d.ts +0 -19
  179. package/bin/Utils/Timers/TimerManager.d.ts.map +0 -1
  180. package/bin/Utils/Timers/TimerManager.js +0 -33
  181. package/bin/Utils/Timers/TimerManager.js.map +0 -1
  182. package/bin/Utils/WasmCore.d.ts +0 -234
  183. package/bin/Utils/WasmCore.d.ts.map +0 -1
  184. package/bin/Utils/WasmCore.js +0 -596
  185. package/bin/Utils/WasmCore.js.map +0 -1
  186. package/bin/Utils/index.d.ts +0 -16
  187. package/bin/Utils/index.d.ts.map +0 -1
  188. package/bin/Utils/index.js +0 -37
  189. package/bin/Utils/index.js.map +0 -1
  190. package/bin/index.cjs +0 -51
  191. package/bin/index.d.ts.map +0 -1
  192. package/bin/index.esm.d.ts +0 -45
  193. package/bin/index.esm.d.ts.map +0 -1
  194. package/bin/index.esm.js +0 -46
  195. package/bin/index.esm.js.map +0 -1
  196. package/bin/index.js.map +0 -1
  197. package/bin/wasm/ecs_wasm_core.d.ts +0 -141
  198. package/bin/wasm/ecs_wasm_core.js +0 -415
  199. package/bin/wasm/ecs_wasm_core_bg.wasm +0 -0
  200. package/bin/wasm/ecs_wasm_core_bg.wasm.d.ts +0 -29
  201. package/bin/wasm/package.json +0 -15
@@ -1,937 +0,0 @@
1
- import { ComponentRegistry } from './ComponentStorage';
2
- import { ecsCore } from '../../Utils/WasmCore';
3
- import { ComponentPoolManager } from './ComponentPool';
4
- import { BitMaskOptimizer } from './BitMaskOptimizer';
5
- import { IndexUpdateBatcher } from './IndexUpdateBatcher';
6
- /**
7
- * 查询条件类型
8
- */
9
- export var QueryConditionType;
10
- (function (QueryConditionType) {
11
- /** 必须包含所有指定组件 */
12
- QueryConditionType["ALL"] = "all";
13
- /** 必须包含任意一个指定组件 */
14
- QueryConditionType["ANY"] = "any";
15
- /** 不能包含任何指定组件 */
16
- QueryConditionType["NONE"] = "none";
17
- })(QueryConditionType || (QueryConditionType = {}));
18
- /**
19
- * 高性能实体查询系统
20
- *
21
- * 提供快速的实体查询功能,支持按组件类型、标签、名称等多种方式查询实体。
22
- * 系统采用多级索引和智能缓存机制,确保在大量实体场景下的查询性能。
23
- *
24
- * 主要特性:
25
- * - 支持单组件和多组件查询
26
- * - 自动索引管理和缓存优化
27
- * - WebAssembly计算加速(如果可用)
28
- * - 详细的性能统计信息
29
- *
30
- * @example
31
- * ```typescript
32
- * // 查询所有包含Position和Velocity组件的实体
33
- * const movingEntities = querySystem.queryAll(PositionComponent, VelocityComponent);
34
- *
35
- * // 查询特定标签的实体
36
- * const playerEntities = querySystem.queryByTag(PLAYER_TAG);
37
- * ```
38
- */
39
- export class QuerySystem {
40
- constructor() {
41
- this.entities = [];
42
- this.wasmAvailable = false;
43
- this.indexDirty = true;
44
- // 查询缓存系统
45
- this.queryCache = new Map();
46
- this.cacheMaxSize = 1000;
47
- this.cacheTimeout = 5000; // 5秒缓存过期
48
- // 性能统计
49
- this.queryStats = {
50
- totalQueries: 0,
51
- cacheHits: 0,
52
- indexHits: 0,
53
- linearScans: 0
54
- };
55
- this.entityIndex = {
56
- byMask: new Map(),
57
- byComponentType: new Map(),
58
- byTag: new Map(),
59
- byName: new Map()
60
- };
61
- // 初始化优化组件
62
- this.componentPoolManager = ComponentPoolManager.getInstance();
63
- this.bitMaskOptimizer = BitMaskOptimizer.getInstance();
64
- this.indexUpdateBatcher = new IndexUpdateBatcher();
65
- // 设置索引更新批处理器的回调
66
- this.indexUpdateBatcher.onBatchAdd = (entities) => {
67
- for (const entity of entities) {
68
- this.addEntityToIndexes(entity);
69
- }
70
- };
71
- this.indexUpdateBatcher.onBatchRemove = (entities) => {
72
- for (const entity of entities) {
73
- this.removeEntityFromIndexes(entity);
74
- }
75
- };
76
- this.indexUpdateBatcher.onBatchUpdate = (updates) => {
77
- for (const update of updates) {
78
- this.removeEntityFromIndexes(update.entity);
79
- this.addEntityToIndexes(update.entity);
80
- }
81
- };
82
- this.initializeWasm();
83
- }
84
- /**
85
- * 初始化WebAssembly支持
86
- *
87
- * 自动检测运行环境并启用WebAssembly计算加速。
88
- * 如果WebAssembly不可用,系统将自动回退到JavaScript实现。
89
- */
90
- async initializeWasm() {
91
- try {
92
- const wasmLoaded = await ecsCore.initialize();
93
- this.wasmAvailable = wasmLoaded && ecsCore.isUsingWasm();
94
- if (this.wasmAvailable) {
95
- console.log('QuerySystem: WebAssembly计算加速已启用');
96
- }
97
- else {
98
- console.log('QuerySystem: 使用JavaScript实现');
99
- }
100
- }
101
- catch (error) {
102
- console.warn('QuerySystem: WebAssembly初始化失败,使用JavaScript实现:', error);
103
- this.wasmAvailable = false;
104
- }
105
- }
106
- /**
107
- * 设置实体列表并重建索引
108
- *
109
- * 当实体集合发生大规模变化时调用此方法。
110
- * 系统将重新构建所有索引以确保查询性能。
111
- *
112
- * @param entities 新的实体列表
113
- */
114
- setEntities(entities) {
115
- this.entities = entities;
116
- this.clearQueryCache();
117
- this.rebuildIndexes();
118
- }
119
- /**
120
- * 添加单个实体到查询系统
121
- *
122
- * 将新实体添加到查询系统中,并自动更新相关索引。
123
- * 为了提高批量添加性能,可以延迟缓存清理。
124
- *
125
- * @param entity 要添加的实体
126
- * @param deferCacheClear 是否延迟缓存清理(用于批量操作)
127
- */
128
- addEntity(entity, deferCacheClear = false) {
129
- if (!this.entities.includes(entity)) {
130
- this.entities.push(entity);
131
- this.addEntityToIndexes(entity);
132
- // 只有在非延迟模式下才立即清理缓存
133
- if (!deferCacheClear) {
134
- this.clearQueryCache();
135
- }
136
- }
137
- }
138
- /**
139
- * 批量添加实体
140
- *
141
- * 高效地批量添加多个实体,减少缓存清理次数。
142
- * 使用Set来避免O(n)的重复检查。
143
- *
144
- * @param entities 要添加的实体列表
145
- */
146
- addEntities(entities) {
147
- if (entities.length === 0)
148
- return;
149
- // 使用Set来快速检查重复
150
- const existingIds = new Set(this.entities.map(e => e.id));
151
- let addedCount = 0;
152
- for (const entity of entities) {
153
- if (!existingIds.has(entity.id)) {
154
- this.entities.push(entity);
155
- this.addEntityToIndexes(entity);
156
- existingIds.add(entity.id);
157
- addedCount++;
158
- }
159
- }
160
- // 只在有实体被添加时才清理缓存
161
- if (addedCount > 0) {
162
- this.clearQueryCache();
163
- }
164
- }
165
- /**
166
- * 批量添加实体(无重复检查版本)
167
- *
168
- * 假设所有实体都是新的,跳过重复检查以获得最大性能。
169
- * 仅在确保没有重复实体时使用。
170
- *
171
- * @param entities 要添加的实体列表
172
- */
173
- addEntitiesUnchecked(entities) {
174
- if (entities.length === 0)
175
- return;
176
- // 避免调用栈溢出,分批添加
177
- for (const entity of entities) {
178
- this.entities.push(entity);
179
- }
180
- // 批量更新索引
181
- for (const entity of entities) {
182
- this.addEntityToIndexes(entity);
183
- }
184
- // 清理缓存
185
- this.clearQueryCache();
186
- }
187
- /**
188
- * 从查询系统移除实体
189
- *
190
- * 从查询系统中移除指定实体,并清理相关索引。
191
- *
192
- * @param entity 要移除的实体
193
- */
194
- removeEntity(entity) {
195
- const index = this.entities.indexOf(entity);
196
- if (index !== -1) {
197
- this.entities.splice(index, 1);
198
- this.removeEntityFromIndexes(entity);
199
- this.clearQueryCache();
200
- }
201
- }
202
- /**
203
- * 将实体添加到各种索引中(优化版本)
204
- */
205
- addEntityToIndexes(entity) {
206
- const mask = entity.componentMask;
207
- // 组件掩码索引 - 优化Map操作
208
- let maskSet = this.entityIndex.byMask.get(mask);
209
- if (!maskSet) {
210
- maskSet = new Set();
211
- this.entityIndex.byMask.set(mask, maskSet);
212
- }
213
- maskSet.add(entity);
214
- // 组件类型索引 - 批量处理
215
- const components = entity.components;
216
- for (let i = 0; i < components.length; i++) {
217
- const componentType = components[i].constructor;
218
- let typeSet = this.entityIndex.byComponentType.get(componentType);
219
- if (!typeSet) {
220
- typeSet = new Set();
221
- this.entityIndex.byComponentType.set(componentType, typeSet);
222
- }
223
- typeSet.add(entity);
224
- }
225
- // 标签索引 - 只在有标签时处理
226
- const tag = entity.tag;
227
- if (tag !== undefined) {
228
- let tagSet = this.entityIndex.byTag.get(tag);
229
- if (!tagSet) {
230
- tagSet = new Set();
231
- this.entityIndex.byTag.set(tag, tagSet);
232
- }
233
- tagSet.add(entity);
234
- }
235
- // 名称索引 - 只在有名称时处理
236
- const name = entity.name;
237
- if (name) {
238
- let nameSet = this.entityIndex.byName.get(name);
239
- if (!nameSet) {
240
- nameSet = new Set();
241
- this.entityIndex.byName.set(name, nameSet);
242
- }
243
- nameSet.add(entity);
244
- }
245
- }
246
- /**
247
- * 从各种索引中移除实体
248
- */
249
- removeEntityFromIndexes(entity) {
250
- const mask = entity.componentMask;
251
- // 从组件掩码索引移除
252
- const maskSet = this.entityIndex.byMask.get(mask);
253
- if (maskSet) {
254
- maskSet.delete(entity);
255
- if (maskSet.size === 0) {
256
- this.entityIndex.byMask.delete(mask);
257
- }
258
- }
259
- // 从组件类型索引移除
260
- for (const component of entity.components) {
261
- const componentType = component.constructor;
262
- const typeSet = this.entityIndex.byComponentType.get(componentType);
263
- if (typeSet) {
264
- typeSet.delete(entity);
265
- if (typeSet.size === 0) {
266
- this.entityIndex.byComponentType.delete(componentType);
267
- }
268
- }
269
- }
270
- // 从标签索引移除
271
- if (entity.tag !== undefined) {
272
- const tagSet = this.entityIndex.byTag.get(entity.tag);
273
- if (tagSet) {
274
- tagSet.delete(entity);
275
- if (tagSet.size === 0) {
276
- this.entityIndex.byTag.delete(entity.tag);
277
- }
278
- }
279
- }
280
- // 从名称索引移除
281
- if (entity.name) {
282
- const nameSet = this.entityIndex.byName.get(entity.name);
283
- if (nameSet) {
284
- nameSet.delete(entity);
285
- if (nameSet.size === 0) {
286
- this.entityIndex.byName.delete(entity.name);
287
- }
288
- }
289
- }
290
- }
291
- /**
292
- * 重建所有索引
293
- *
294
- * 清空并重新构建所有查询索引。
295
- * 通常在大量实体变更后调用以确保索引一致性。
296
- */
297
- rebuildIndexes() {
298
- this.entityIndex.byMask.clear();
299
- this.entityIndex.byComponentType.clear();
300
- this.entityIndex.byTag.clear();
301
- this.entityIndex.byName.clear();
302
- for (const entity of this.entities) {
303
- this.addEntityToIndexes(entity);
304
- }
305
- this.indexDirty = false;
306
- }
307
- /**
308
- * 查询包含所有指定组件的实体
309
- *
310
- * 返回同时包含所有指定组件类型的实体列表。
311
- * 系统会自动选择最高效的查询策略,包括索引查找和缓存机制。
312
- *
313
- * @param componentTypes 要查询的组件类型列表
314
- * @returns 查询结果,包含匹配的实体和性能信息
315
- *
316
- * @example
317
- * ```typescript
318
- * // 查询同时具有位置和速度组件的实体
319
- * const result = querySystem.queryAll(PositionComponent, VelocityComponent);
320
- * console.log(`找到 ${result.count} 个移动实体`);
321
- * ```
322
- */
323
- queryAll(...componentTypes) {
324
- const startTime = performance.now();
325
- this.queryStats.totalQueries++;
326
- // 生成缓存键
327
- const cacheKey = `all:${componentTypes.map(t => t.name).sort().join(',')}`;
328
- // 检查缓存
329
- const cached = this.getFromCache(cacheKey);
330
- if (cached) {
331
- this.queryStats.cacheHits++;
332
- return {
333
- entities: cached,
334
- count: cached.length,
335
- executionTime: performance.now() - startTime,
336
- fromCache: true
337
- };
338
- }
339
- let entities;
340
- // 单组件查询:直接使用索引
341
- if (componentTypes.length === 1) {
342
- this.queryStats.indexHits++;
343
- entities = Array.from(this.entityIndex.byComponentType.get(componentTypes[0]) || []);
344
- }
345
- else {
346
- // 多组件查询:使用高效算法
347
- entities = this.queryMultipleComponents(componentTypes);
348
- }
349
- // 缓存结果
350
- this.addToCache(cacheKey, entities);
351
- return {
352
- entities,
353
- count: entities.length,
354
- executionTime: performance.now() - startTime,
355
- fromCache: false
356
- };
357
- }
358
- /**
359
- * 多组件查询算法
360
- *
361
- * 针对多组件查询场景的高效算法实现。
362
- * 通过选择最小的组件集合作为起点,减少需要检查的实体数量。
363
- *
364
- * @param componentTypes 组件类型列表
365
- * @returns 匹配的实体列表
366
- */
367
- queryMultipleComponents(componentTypes) {
368
- // 找到最小的组件集合作为起点
369
- let smallestSet = null;
370
- let smallestSize = Infinity;
371
- for (const componentType of componentTypes) {
372
- const set = this.entityIndex.byComponentType.get(componentType);
373
- if (!set || set.size === 0) {
374
- return []; // 如果任何组件没有实体,直接返回空结果
375
- }
376
- if (set.size < smallestSize) {
377
- smallestSize = set.size;
378
- smallestSet = set;
379
- }
380
- }
381
- if (!smallestSet) {
382
- this.queryStats.linearScans++;
383
- return this.queryByLinearScan(componentTypes);
384
- }
385
- // 从最小集合开始,逐步过滤
386
- const mask = this.createComponentMask(componentTypes);
387
- const result = [];
388
- for (const entity of smallestSet) {
389
- if ((entity.componentMask & mask) === mask) {
390
- result.push(entity);
391
- }
392
- }
393
- return result;
394
- }
395
- /**
396
- * 线性扫描查询
397
- *
398
- * 当索引不可用时的备用查询方法。
399
- * 遍历所有实体进行组件匹配检查。
400
- *
401
- * @param componentTypes 组件类型列表
402
- * @returns 匹配的实体列表
403
- */
404
- queryByLinearScan(componentTypes) {
405
- const mask = this.createComponentMask(componentTypes);
406
- return this.entities.filter(entity => (entity.componentMask & mask) === mask);
407
- }
408
- /**
409
- * 查询包含任意指定组件的实体
410
- *
411
- * 返回包含任意一个指定组件类型的实体列表。
412
- * 使用集合合并算法确保高效的查询性能。
413
- *
414
- * @param componentTypes 要查询的组件类型列表
415
- * @returns 查询结果,包含匹配的实体和性能信息
416
- *
417
- * @example
418
- * ```typescript
419
- * // 查询具有武器或护甲组件的实体
420
- * const result = querySystem.queryAny(WeaponComponent, ArmorComponent);
421
- * console.log(`找到 ${result.count} 个装备实体`);
422
- * ```
423
- */
424
- queryAny(...componentTypes) {
425
- const startTime = performance.now();
426
- this.queryStats.totalQueries++;
427
- const cacheKey = `any:${componentTypes.map(t => t.name).sort().join(',')}`;
428
- // 检查缓存
429
- const cached = this.getFromCache(cacheKey);
430
- if (cached) {
431
- this.queryStats.cacheHits++;
432
- return {
433
- entities: cached,
434
- count: cached.length,
435
- executionTime: performance.now() - startTime,
436
- fromCache: true
437
- };
438
- }
439
- // 使用集合合并
440
- const entitySet = new Set();
441
- for (const componentType of componentTypes) {
442
- const typeEntities = this.entityIndex.byComponentType.get(componentType);
443
- if (typeEntities) {
444
- for (const entity of typeEntities) {
445
- entitySet.add(entity);
446
- }
447
- }
448
- }
449
- const entities = Array.from(entitySet);
450
- this.addToCache(cacheKey, entities);
451
- return {
452
- entities,
453
- count: entities.length,
454
- executionTime: performance.now() - startTime,
455
- fromCache: false
456
- };
457
- }
458
- /**
459
- * 查询不包含任何指定组件的实体
460
- *
461
- * 返回不包含任何指定组件类型的实体列表。
462
- * 适用于排除特定类型实体的查询场景。
463
- *
464
- * @param componentTypes 要排除的组件类型列表
465
- * @returns 查询结果,包含匹配的实体和性能信息
466
- *
467
- * @example
468
- * ```typescript
469
- * // 查询不具有AI和玩家控制组件的实体(如静态物体)
470
- * const result = querySystem.queryNone(AIComponent, PlayerControlComponent);
471
- * console.log(`找到 ${result.count} 个静态实体`);
472
- * ```
473
- */
474
- queryNone(...componentTypes) {
475
- const startTime = performance.now();
476
- this.queryStats.totalQueries++;
477
- const cacheKey = `none:${componentTypes.map(t => t.name).sort().join(',')}`;
478
- // 检查缓存
479
- const cached = this.getFromCache(cacheKey);
480
- if (cached) {
481
- this.queryStats.cacheHits++;
482
- return {
483
- entities: cached,
484
- count: cached.length,
485
- executionTime: performance.now() - startTime,
486
- fromCache: true
487
- };
488
- }
489
- const mask = this.createComponentMask(componentTypes);
490
- const entities = this.entities.filter(entity => (entity.componentMask & mask) === BigInt(0));
491
- this.addToCache(cacheKey, entities);
492
- return {
493
- entities,
494
- count: entities.length,
495
- executionTime: performance.now() - startTime,
496
- fromCache: false
497
- };
498
- }
499
- /**
500
- * 按标签查询实体
501
- *
502
- * 返回具有指定标签的所有实体。
503
- * 标签查询使用专用索引,具有很高的查询性能。
504
- *
505
- * @param tag 要查询的标签值
506
- * @returns 查询结果,包含匹配的实体和性能信息
507
- *
508
- * @example
509
- * ```typescript
510
- * // 查询所有玩家实体
511
- * const players = querySystem.queryByTag(PLAYER_TAG);
512
- * ```
513
- */
514
- queryByTag(tag) {
515
- const startTime = performance.now();
516
- this.queryStats.totalQueries++;
517
- const cacheKey = `tag:${tag}`;
518
- // 检查缓存
519
- const cached = this.getFromCache(cacheKey);
520
- if (cached) {
521
- this.queryStats.cacheHits++;
522
- return {
523
- entities: cached,
524
- count: cached.length,
525
- executionTime: performance.now() - startTime,
526
- fromCache: true
527
- };
528
- }
529
- // 使用索引查询
530
- this.queryStats.indexHits++;
531
- const entities = Array.from(this.entityIndex.byTag.get(tag) || []);
532
- // 缓存结果
533
- this.addToCache(cacheKey, entities);
534
- return {
535
- entities,
536
- count: entities.length,
537
- executionTime: performance.now() - startTime,
538
- fromCache: false
539
- };
540
- }
541
- /**
542
- * 按名称查询实体
543
- *
544
- * 返回具有指定名称的所有实体。
545
- * 名称查询使用专用索引,适用于查找特定的命名实体。
546
- *
547
- * @param name 要查询的实体名称
548
- * @returns 查询结果,包含匹配的实体和性能信息
549
- *
550
- * @example
551
- * ```typescript
552
- * // 查找名为"Player"的实体
553
- * const player = querySystem.queryByName("Player");
554
- * ```
555
- */
556
- queryByName(name) {
557
- const startTime = performance.now();
558
- this.queryStats.totalQueries++;
559
- const cacheKey = `name:${name}`;
560
- // 检查缓存
561
- const cached = this.getFromCache(cacheKey);
562
- if (cached) {
563
- this.queryStats.cacheHits++;
564
- return {
565
- entities: cached,
566
- count: cached.length,
567
- executionTime: performance.now() - startTime,
568
- fromCache: true
569
- };
570
- }
571
- // 使用索引查询
572
- this.queryStats.indexHits++;
573
- const entities = Array.from(this.entityIndex.byName.get(name) || []);
574
- // 缓存结果
575
- this.addToCache(cacheKey, entities);
576
- return {
577
- entities,
578
- count: entities.length,
579
- executionTime: performance.now() - startTime,
580
- fromCache: false
581
- };
582
- }
583
- /**
584
- * 按单个组件类型查询实体
585
- *
586
- * 返回包含指定组件类型的所有实体。
587
- * 这是最基础的查询方法,具有最高的查询性能。
588
- *
589
- * @param componentType 要查询的组件类型
590
- * @returns 查询结果,包含匹配的实体和性能信息
591
- *
592
- * @example
593
- * ```typescript
594
- * // 查询所有具有位置组件的实体
595
- * const entitiesWithPosition = querySystem.queryByComponent(PositionComponent);
596
- * ```
597
- */
598
- queryByComponent(componentType) {
599
- const startTime = performance.now();
600
- this.queryStats.totalQueries++;
601
- const cacheKey = `component:${componentType.name}`;
602
- // 检查缓存
603
- const cached = this.getFromCache(cacheKey);
604
- if (cached) {
605
- this.queryStats.cacheHits++;
606
- return {
607
- entities: cached,
608
- count: cached.length,
609
- executionTime: performance.now() - startTime,
610
- fromCache: true
611
- };
612
- }
613
- // 使用索引查询
614
- this.queryStats.indexHits++;
615
- const entities = Array.from(this.entityIndex.byComponentType.get(componentType) || []);
616
- // 缓存结果
617
- this.addToCache(cacheKey, entities);
618
- return {
619
- entities,
620
- count: entities.length,
621
- executionTime: performance.now() - startTime,
622
- fromCache: false
623
- };
624
- }
625
- /**
626
- * 从缓存获取查询结果
627
- */
628
- getFromCache(cacheKey) {
629
- const entry = this.queryCache.get(cacheKey);
630
- if (!entry)
631
- return null;
632
- // 检查缓存是否过期
633
- if (Date.now() - entry.timestamp > this.cacheTimeout) {
634
- this.queryCache.delete(cacheKey);
635
- return null;
636
- }
637
- entry.hitCount++;
638
- return entry.entities;
639
- }
640
- /**
641
- * 添加查询结果到缓存
642
- */
643
- addToCache(cacheKey, entities) {
644
- // 如果缓存已满,清理最少使用的条目
645
- if (this.queryCache.size >= this.cacheMaxSize) {
646
- this.cleanupCache();
647
- }
648
- this.queryCache.set(cacheKey, {
649
- entities: [...entities], // 复制数组避免引用问题
650
- timestamp: Date.now(),
651
- hitCount: 0
652
- });
653
- }
654
- /**
655
- * 清理缓存
656
- */
657
- cleanupCache() {
658
- // 移除过期的缓存条目
659
- const now = Date.now();
660
- for (const [key, entry] of this.queryCache.entries()) {
661
- if (now - entry.timestamp > this.cacheTimeout) {
662
- this.queryCache.delete(key);
663
- }
664
- }
665
- // 如果还是太满,移除最少使用的条目
666
- if (this.queryCache.size >= this.cacheMaxSize) {
667
- const entries = Array.from(this.queryCache.entries());
668
- entries.sort((a, b) => a[1].hitCount - b[1].hitCount);
669
- const toRemove = Math.floor(this.cacheMaxSize * 0.2); // 移除20%
670
- for (let i = 0; i < toRemove && i < entries.length; i++) {
671
- this.queryCache.delete(entries[i][0]);
672
- }
673
- }
674
- }
675
- /**
676
- * 清除所有查询缓存
677
- */
678
- clearQueryCache() {
679
- this.queryCache.clear();
680
- }
681
- /**
682
- * 公共方法:清理查询缓存
683
- *
684
- * 用于外部调用清理缓存,通常在批量操作后使用。
685
- */
686
- clearCache() {
687
- this.clearQueryCache();
688
- }
689
- /**
690
- * 批量更新实体组件
691
- *
692
- * 对大量实体进行批量组件更新操作。
693
- * 当更新数量超过阈值时,系统会自动使用WebAssembly加速。
694
- *
695
- * @param updates 更新操作列表,包含实体ID和新的组件掩码
696
- *
697
- * @example
698
- * ```typescript
699
- * // 批量更新实体的组件配置
700
- * const updates = [
701
- * { entityId: 1, componentMask: BigInt(0b1011) },
702
- * { entityId: 2, componentMask: BigInt(0b1101) }
703
- * ];
704
- * querySystem.batchUpdateComponents(updates);
705
- * ```
706
- */
707
- batchUpdateComponents(updates) {
708
- if (this.wasmAvailable && updates.length > 100) {
709
- try {
710
- const entityIds = updates.map(u => u.entityId);
711
- const masks = updates.map(u => u.componentMask);
712
- ecsCore.batchUpdateMasks(entityIds, masks);
713
- console.log(`WebAssembly加速批量更新 ${updates.length} 个实体`);
714
- }
715
- catch (error) {
716
- console.warn('WebAssembly批量更新失败,回退到JavaScript实现:', error);
717
- this.batchUpdateComponentsJS(updates);
718
- }
719
- }
720
- else {
721
- this.batchUpdateComponentsJS(updates);
722
- }
723
- // 批量更新后清除缓存
724
- this.clearQueryCache();
725
- }
726
- /**
727
- * JavaScript实现的批量更新
728
- */
729
- batchUpdateComponentsJS(updates) {
730
- for (const update of updates) {
731
- const entity = this.entities.find(e => e.id === update.entityId);
732
- if (entity) {
733
- // 注意:componentMask是只读属性,实际应用中需要通过添加/移除组件来更新
734
- console.log(`更新实体 ${update.entityId} 的组件掩码: ${update.componentMask}`);
735
- }
736
- }
737
- this.rebuildIndexes();
738
- }
739
- /**
740
- * 获取加速状态信息
741
- *
742
- * 返回当前查询系统的加速状态和性能信息。
743
- * 包括WebAssembly可用性、缓存统计等详细信息。
744
- *
745
- * @returns 加速状态信息对象
746
- */
747
- getAccelerationStatus() {
748
- return {
749
- wasmEnabled: this.wasmAvailable,
750
- currentProvider: this.wasmAvailable ? 'hybrid' : 'javascript',
751
- availableProviders: ['javascript', 'hybrid'],
752
- performanceInfo: {
753
- entityCount: this.entities.length,
754
- wasmEnabled: this.wasmAvailable,
755
- cacheStats: {
756
- size: this.queryCache.size,
757
- hitRate: this.queryStats.totalQueries > 0 ?
758
- (this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + '%' : '0%'
759
- }
760
- }
761
- };
762
- }
763
- /**
764
- * 切换加速提供者
765
- *
766
- * 兼容性接口,保持向后兼容。
767
- * 系统会自动选择最佳的实现方式。
768
- *
769
- * @param providerName 提供者名称
770
- * @returns 是否切换成功
771
- */
772
- async switchAccelerationProvider(providerName) {
773
- return true;
774
- }
775
- /**
776
- * 创建组件掩码
777
- *
778
- * 根据组件类型列表生成对应的位掩码。
779
- * 使用位掩码优化器进行缓存和预计算。
780
- *
781
- * @param componentTypes 组件类型列表
782
- * @returns 生成的位掩码
783
- */
784
- createComponentMask(componentTypes) {
785
- // 使用位掩码优化器创建掩码
786
- const componentNames = componentTypes.map(type => type.name);
787
- // 确保组件类型已注册到优化器
788
- for (const name of componentNames) {
789
- this.bitMaskOptimizer.registerComponentType(name);
790
- }
791
- return this.bitMaskOptimizer.createCombinedMask(componentNames);
792
- }
793
- /**
794
- * 获取系统统计信息
795
- *
796
- * 返回查询系统的详细统计信息,包括实体数量、索引状态、
797
- * 查询性能统计等,用于性能监控和调试。
798
- *
799
- * @returns 系统统计信息对象
800
- */
801
- getStats() {
802
- return {
803
- entityCount: this.entities.length,
804
- indexStats: {
805
- maskIndexSize: this.entityIndex.byMask.size,
806
- componentIndexSize: this.entityIndex.byComponentType.size,
807
- tagIndexSize: this.entityIndex.byTag.size,
808
- nameIndexSize: this.entityIndex.byName.size
809
- },
810
- accelerationStatus: this.getAccelerationStatus(),
811
- queryStats: {
812
- ...this.queryStats,
813
- cacheHitRate: this.queryStats.totalQueries > 0 ?
814
- (this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + '%' : '0%'
815
- }
816
- };
817
- }
818
- }
819
- /**
820
- * 查询构建器
821
- *
822
- * 提供链式API来构建复杂的实体查询条件。
823
- * 支持组合多种查询条件,创建灵活的查询表达式。
824
- *
825
- * @example
826
- * ```typescript
827
- * const result = new QueryBuilder(querySystem)
828
- * .withAll(PositionComponent, VelocityComponent)
829
- * .without(DeadComponent)
830
- * .execute();
831
- * ```
832
- */
833
- export class QueryBuilder {
834
- constructor(querySystem) {
835
- this.conditions = [];
836
- this.querySystem = querySystem;
837
- }
838
- /**
839
- * 添加"必须包含所有组件"条件
840
- *
841
- * @param componentTypes 必须包含的组件类型
842
- * @returns 查询构建器实例,支持链式调用
843
- */
844
- withAll(...componentTypes) {
845
- this.conditions.push({
846
- type: QueryConditionType.ALL,
847
- componentTypes,
848
- mask: this.createComponentMask(componentTypes)
849
- });
850
- return this;
851
- }
852
- /**
853
- * 添加"必须包含任意组件"条件
854
- *
855
- * @param componentTypes 必须包含其中任意一个的组件类型
856
- * @returns 查询构建器实例,支持链式调用
857
- */
858
- withAny(...componentTypes) {
859
- this.conditions.push({
860
- type: QueryConditionType.ANY,
861
- componentTypes,
862
- mask: this.createComponentMask(componentTypes)
863
- });
864
- return this;
865
- }
866
- /**
867
- * 添加"不能包含任何组件"条件
868
- *
869
- * @param componentTypes 不能包含的组件类型
870
- * @returns 查询构建器实例,支持链式调用
871
- */
872
- without(...componentTypes) {
873
- this.conditions.push({
874
- type: QueryConditionType.NONE,
875
- componentTypes,
876
- mask: this.createComponentMask(componentTypes)
877
- });
878
- return this;
879
- }
880
- /**
881
- * 执行查询并返回结果
882
- *
883
- * 根据已添加的查询条件执行实体查询。
884
- *
885
- * @returns 查询结果,包含匹配的实体和性能信息
886
- */
887
- execute() {
888
- const startTime = performance.now();
889
- // 简化实现:目前只支持单一条件
890
- if (this.conditions.length === 1) {
891
- const condition = this.conditions[0];
892
- switch (condition.type) {
893
- case QueryConditionType.ALL:
894
- return this.querySystem.queryAll(...condition.componentTypes);
895
- case QueryConditionType.ANY:
896
- return this.querySystem.queryAny(...condition.componentTypes);
897
- case QueryConditionType.NONE:
898
- return this.querySystem.queryNone(...condition.componentTypes);
899
- }
900
- }
901
- // 多条件查询的复杂实现留待后续扩展
902
- return {
903
- entities: [],
904
- count: 0,
905
- executionTime: performance.now() - startTime,
906
- fromCache: false
907
- };
908
- }
909
- /**
910
- * 创建组件掩码
911
- */
912
- createComponentMask(componentTypes) {
913
- let mask = BigInt(0);
914
- for (const type of componentTypes) {
915
- try {
916
- const bitMask = ComponentRegistry.getBitMask(type);
917
- mask |= bitMask;
918
- }
919
- catch (error) {
920
- console.warn(`组件类型 ${type.name} 未注册,跳过`);
921
- }
922
- }
923
- return mask;
924
- }
925
- /**
926
- * 重置查询构建器
927
- *
928
- * 清除所有已添加的查询条件,重新开始构建查询。
929
- *
930
- * @returns 查询构建器实例,支持链式调用
931
- */
932
- reset() {
933
- this.conditions = [];
934
- return this;
935
- }
936
- }
937
- //# sourceMappingURL=QuerySystem.js.map