@esengine/ecs-framework 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +277 -0
- package/bin/Core.d.ts +198 -0
- package/bin/Core.d.ts.map +1 -0
- package/bin/Core.js +249 -0
- package/bin/Core.js.map +1 -0
- package/bin/ECS/Component.d.ts +119 -0
- package/bin/ECS/Component.d.ts.map +1 -0
- package/bin/ECS/Component.js +129 -0
- package/bin/ECS/Component.js.map +1 -0
- package/bin/ECS/Components/IUpdatable.d.ts +22 -0
- package/bin/ECS/Components/IUpdatable.d.ts.map +1 -0
- package/bin/ECS/Components/IUpdatable.js +17 -0
- package/bin/ECS/Components/IUpdatable.js.map +1 -0
- package/bin/ECS/Components/SceneComponent.d.ts +40 -0
- package/bin/ECS/Components/SceneComponent.d.ts.map +1 -0
- package/bin/ECS/Components/SceneComponent.js +57 -0
- package/bin/ECS/Components/SceneComponent.js.map +1 -0
- package/bin/ECS/Core/ComponentStorage.d.ts +182 -0
- package/bin/ECS/Core/ComponentStorage.d.ts.map +1 -0
- package/bin/ECS/Core/ComponentStorage.js +346 -0
- package/bin/ECS/Core/ComponentStorage.js.map +1 -0
- package/bin/ECS/Core/EventSystem.d.ts +236 -0
- package/bin/ECS/Core/EventSystem.d.ts.map +1 -0
- package/bin/ECS/Core/EventSystem.js +476 -0
- package/bin/ECS/Core/EventSystem.js.map +1 -0
- package/bin/ECS/Core/FluentAPI.d.ts +392 -0
- package/bin/ECS/Core/FluentAPI.d.ts.map +1 -0
- package/bin/ECS/Core/FluentAPI.js +575 -0
- package/bin/ECS/Core/FluentAPI.js.map +1 -0
- package/bin/ECS/Core/QuerySystem.d.ts +574 -0
- package/bin/ECS/Core/QuerySystem.d.ts.map +1 -0
- package/bin/ECS/Core/QuerySystem.js +1356 -0
- package/bin/ECS/Core/QuerySystem.js.map +1 -0
- package/bin/ECS/CoreEvents.d.ts +19 -0
- package/bin/ECS/CoreEvents.d.ts.map +1 -0
- package/bin/ECS/CoreEvents.js +20 -0
- package/bin/ECS/CoreEvents.js.map +1 -0
- package/bin/ECS/Entity.d.ts +585 -0
- package/bin/ECS/Entity.d.ts.map +1 -0
- package/bin/ECS/Entity.js +1079 -0
- package/bin/ECS/Entity.js.map +1 -0
- package/bin/ECS/Scene.d.ts +210 -0
- package/bin/ECS/Scene.d.ts.map +1 -0
- package/bin/ECS/Scene.js +267 -0
- package/bin/ECS/Scene.js.map +1 -0
- package/bin/ECS/Systems/EntitySystem.d.ts +185 -0
- package/bin/ECS/Systems/EntitySystem.d.ts.map +1 -0
- package/bin/ECS/Systems/EntitySystem.js +278 -0
- package/bin/ECS/Systems/EntitySystem.js.map +1 -0
- package/bin/ECS/Systems/IntervalSystem.d.ts +33 -0
- package/bin/ECS/Systems/IntervalSystem.d.ts.map +1 -0
- package/bin/ECS/Systems/IntervalSystem.js +50 -0
- package/bin/ECS/Systems/IntervalSystem.js.map +1 -0
- package/bin/ECS/Systems/PassiveSystem.d.ts +20 -0
- package/bin/ECS/Systems/PassiveSystem.d.ts.map +1 -0
- package/bin/ECS/Systems/PassiveSystem.js +21 -0
- package/bin/ECS/Systems/PassiveSystem.js.map +1 -0
- package/bin/ECS/Systems/ProcessingSystem.d.ts +24 -0
- package/bin/ECS/Systems/ProcessingSystem.d.ts.map +1 -0
- package/bin/ECS/Systems/ProcessingSystem.js +22 -0
- package/bin/ECS/Systems/ProcessingSystem.js.map +1 -0
- package/bin/ECS/Systems/index.d.ts +5 -0
- package/bin/ECS/Systems/index.d.ts.map +1 -0
- package/bin/ECS/Systems/index.js +6 -0
- package/bin/ECS/Systems/index.js.map +1 -0
- package/bin/ECS/Transform.d.ts +178 -0
- package/bin/ECS/Transform.d.ts.map +1 -0
- package/bin/ECS/Transform.js +249 -0
- package/bin/ECS/Transform.js.map +1 -0
- package/bin/ECS/Utils/Bits.d.ts +74 -0
- package/bin/ECS/Utils/Bits.d.ts.map +1 -0
- package/bin/ECS/Utils/Bits.js +142 -0
- package/bin/ECS/Utils/Bits.js.map +1 -0
- package/bin/ECS/Utils/ComponentTypeManager.d.ts +50 -0
- package/bin/ECS/Utils/ComponentTypeManager.d.ts.map +1 -0
- package/bin/ECS/Utils/ComponentTypeManager.js +84 -0
- package/bin/ECS/Utils/ComponentTypeManager.js.map +1 -0
- package/bin/ECS/Utils/EntityList.d.ts +108 -0
- package/bin/ECS/Utils/EntityList.d.ts.map +1 -0
- package/bin/ECS/Utils/EntityList.js +249 -0
- package/bin/ECS/Utils/EntityList.js.map +1 -0
- package/bin/ECS/Utils/EntityProcessorList.d.ts +53 -0
- package/bin/ECS/Utils/EntityProcessorList.d.ts.map +1 -0
- package/bin/ECS/Utils/EntityProcessorList.js +96 -0
- package/bin/ECS/Utils/EntityProcessorList.js.map +1 -0
- package/bin/ECS/Utils/IdentifierPool.d.ts +18 -0
- package/bin/ECS/Utils/IdentifierPool.d.ts.map +1 -0
- package/bin/ECS/Utils/IdentifierPool.js +27 -0
- package/bin/ECS/Utils/IdentifierPool.js.map +1 -0
- package/bin/ECS/Utils/Matcher.d.ts +63 -0
- package/bin/ECS/Utils/Matcher.d.ts.map +1 -0
- package/bin/ECS/Utils/Matcher.js +140 -0
- package/bin/ECS/Utils/Matcher.js.map +1 -0
- package/bin/ECS/Utils/index.d.ts +7 -0
- package/bin/ECS/Utils/index.d.ts.map +1 -0
- package/bin/ECS/Utils/index.js +8 -0
- package/bin/ECS/Utils/index.js.map +1 -0
- package/bin/ECS/index.d.ts +8 -0
- package/bin/ECS/index.d.ts.map +1 -0
- package/bin/ECS/index.js +9 -0
- package/bin/ECS/index.js.map +1 -0
- package/bin/Math/Edge.d.ts +23 -0
- package/bin/Math/Edge.d.ts.map +1 -0
- package/bin/Math/Edge.js +24 -0
- package/bin/Math/Edge.js.map +1 -0
- package/bin/Math/MathHelper.d.ts +75 -0
- package/bin/Math/MathHelper.d.ts.map +1 -0
- package/bin/Math/MathHelper.js +91 -0
- package/bin/Math/MathHelper.js.map +1 -0
- package/bin/Math/Rectangle.d.ts +126 -0
- package/bin/Math/Rectangle.d.ts.map +1 -0
- package/bin/Math/Rectangle.js +181 -0
- package/bin/Math/Rectangle.js.map +1 -0
- package/bin/Math/Vector2.d.ts +229 -0
- package/bin/Math/Vector2.d.ts.map +1 -0
- package/bin/Math/Vector2.js +338 -0
- package/bin/Math/Vector2.js.map +1 -0
- package/bin/Math/index.d.ts +5 -0
- package/bin/Math/index.d.ts.map +1 -0
- package/bin/Math/index.js +6 -0
- package/bin/Math/index.js.map +1 -0
- package/bin/Types/index.d.ts +22 -0
- package/bin/Types/index.d.ts.map +1 -0
- package/bin/Types/index.js +20 -0
- package/bin/Types/index.js.map +1 -0
- package/bin/Utils/Emitter.d.ts +43 -0
- package/bin/Utils/Emitter.d.ts.map +1 -0
- package/bin/Utils/Emitter.js +69 -0
- package/bin/Utils/Emitter.js.map +1 -0
- package/bin/Utils/Extensions/EdgeExt.d.ts +26 -0
- package/bin/Utils/Extensions/EdgeExt.d.ts.map +1 -0
- package/bin/Utils/Extensions/EdgeExt.js +41 -0
- package/bin/Utils/Extensions/EdgeExt.js.map +1 -0
- package/bin/Utils/Extensions/NumberExtension.d.ts +13 -0
- package/bin/Utils/Extensions/NumberExtension.d.ts.map +1 -0
- package/bin/Utils/Extensions/NumberExtension.js +17 -0
- package/bin/Utils/Extensions/NumberExtension.js.map +1 -0
- package/bin/Utils/Extensions/TypeUtils.d.ts +13 -0
- package/bin/Utils/Extensions/TypeUtils.d.ts.map +1 -0
- package/bin/Utils/Extensions/TypeUtils.js +15 -0
- package/bin/Utils/Extensions/TypeUtils.js.map +1 -0
- package/bin/Utils/Extensions/index.d.ts +4 -0
- package/bin/Utils/Extensions/index.d.ts.map +1 -0
- package/bin/Utils/Extensions/index.js +5 -0
- package/bin/Utils/Extensions/index.js.map +1 -0
- package/bin/Utils/GlobalManager.d.ts +32 -0
- package/bin/Utils/GlobalManager.d.ts.map +1 -0
- package/bin/Utils/GlobalManager.js +53 -0
- package/bin/Utils/GlobalManager.js.map +1 -0
- package/bin/Utils/PerformanceMonitor.d.ts +211 -0
- package/bin/Utils/PerformanceMonitor.d.ts.map +1 -0
- package/bin/Utils/PerformanceMonitor.js +270 -0
- package/bin/Utils/PerformanceMonitor.js.map +1 -0
- package/bin/Utils/Pool.d.ts +239 -0
- package/bin/Utils/Pool.d.ts.map +1 -0
- package/bin/Utils/Pool.js +449 -0
- package/bin/Utils/Pool.js.map +1 -0
- package/bin/Utils/Screen.d.ts +12 -0
- package/bin/Utils/Screen.d.ts.map +1 -0
- package/bin/Utils/Screen.js +14 -0
- package/bin/Utils/Screen.js.map +1 -0
- package/bin/Utils/Time.d.ts +55 -0
- package/bin/Utils/Time.d.ts.map +1 -0
- package/bin/Utils/Time.js +78 -0
- package/bin/Utils/Time.js.map +1 -0
- package/bin/Utils/Timers/ITimer.d.ts +16 -0
- package/bin/Utils/Timers/ITimer.d.ts.map +1 -0
- package/bin/Utils/Timers/ITimer.js +2 -0
- package/bin/Utils/Timers/ITimer.js.map +1 -0
- package/bin/Utils/Timers/Timer.d.ts +22 -0
- package/bin/Utils/Timers/Timer.d.ts.map +1 -0
- package/bin/Utils/Timers/Timer.js +46 -0
- package/bin/Utils/Timers/Timer.js.map +1 -0
- package/bin/Utils/Timers/TimerManager.d.ts +19 -0
- package/bin/Utils/Timers/TimerManager.d.ts.map +1 -0
- package/bin/Utils/Timers/TimerManager.js +33 -0
- package/bin/Utils/Timers/TimerManager.js.map +1 -0
- package/bin/Utils/index.d.ts +6 -0
- package/bin/Utils/index.d.ts.map +1 -0
- package/bin/Utils/index.js +7 -0
- package/bin/Utils/index.js.map +1 -0
- package/bin/index.d.ts +21 -0
- package/bin/index.d.ts.map +1 -0
- package/bin/index.js +26 -0
- package/bin/index.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,1356 @@
|
|
|
1
|
+
import { ComponentRegistry } from './ComponentStorage';
|
|
2
|
+
/**
|
|
3
|
+
* 查询条件类型
|
|
4
|
+
*/
|
|
5
|
+
export var QueryConditionType;
|
|
6
|
+
(function (QueryConditionType) {
|
|
7
|
+
/** 必须包含所有指定组件 */
|
|
8
|
+
QueryConditionType["ALL"] = "all";
|
|
9
|
+
/** 必须包含任意一个指定组件 */
|
|
10
|
+
QueryConditionType["ANY"] = "any";
|
|
11
|
+
/** 不能包含任何指定组件 */
|
|
12
|
+
QueryConditionType["NONE"] = "none";
|
|
13
|
+
})(QueryConditionType || (QueryConditionType = {}));
|
|
14
|
+
/**
|
|
15
|
+
* 高性能实体查询系统
|
|
16
|
+
* 使用位掩码进行快速组件匹配,支持多级索引和智能缓存
|
|
17
|
+
*/
|
|
18
|
+
export class QuerySystem {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.entities = [];
|
|
21
|
+
this.queryCache = new Map();
|
|
22
|
+
this.cacheTimeout = 1000; // 缓存超时时间(毫秒)
|
|
23
|
+
this.maxCacheSize = 100; // 最大缓存数量
|
|
24
|
+
this.cacheHits = 0;
|
|
25
|
+
this.cacheMisses = 0;
|
|
26
|
+
// 多级索引系统
|
|
27
|
+
this.entityIndex = {
|
|
28
|
+
byMask: new Map(),
|
|
29
|
+
byComponentType: new Map(),
|
|
30
|
+
byTag: new Map(),
|
|
31
|
+
byName: new Map()
|
|
32
|
+
};
|
|
33
|
+
// 性能统计
|
|
34
|
+
this.performanceStats = {
|
|
35
|
+
totalQueries: 0,
|
|
36
|
+
averageExecutionTime: 0,
|
|
37
|
+
cacheHitRate: 0,
|
|
38
|
+
indexHitRate: 0,
|
|
39
|
+
slowQueries: []
|
|
40
|
+
};
|
|
41
|
+
// 索引更新标志
|
|
42
|
+
this.indexDirty = true;
|
|
43
|
+
this.lastIndexUpdate = 0;
|
|
44
|
+
this.indexUpdateThreshold = 100; // 毫秒
|
|
45
|
+
// 批量操作缓冲区
|
|
46
|
+
this.pendingEntityAdds = [];
|
|
47
|
+
this.pendingEntityRemoves = [];
|
|
48
|
+
this.batchUpdateScheduled = false;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 设置实体列表
|
|
52
|
+
* @param entities 实体数组
|
|
53
|
+
*/
|
|
54
|
+
setEntities(entities) {
|
|
55
|
+
this.entities = entities;
|
|
56
|
+
this.invalidateIndexes();
|
|
57
|
+
this.clearCache();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 添加实体
|
|
61
|
+
* @param entity 实体
|
|
62
|
+
*/
|
|
63
|
+
addEntity(entity) {
|
|
64
|
+
this.pendingEntityAdds.push(entity);
|
|
65
|
+
this.scheduleBatchUpdate();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 批量添加实体
|
|
69
|
+
* @param entities 实体数组
|
|
70
|
+
*/
|
|
71
|
+
addEntities(entities) {
|
|
72
|
+
this.pendingEntityAdds.push(...entities);
|
|
73
|
+
this.scheduleBatchUpdate();
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 移除实体
|
|
77
|
+
* @param entity 实体
|
|
78
|
+
*/
|
|
79
|
+
removeEntity(entity) {
|
|
80
|
+
this.pendingEntityRemoves.push(entity);
|
|
81
|
+
this.scheduleBatchUpdate();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 批量移除实体
|
|
85
|
+
* @param entities 实体数组
|
|
86
|
+
*/
|
|
87
|
+
removeEntities(entities) {
|
|
88
|
+
this.pendingEntityRemoves.push(...entities);
|
|
89
|
+
this.scheduleBatchUpdate();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 调度批量更新
|
|
93
|
+
*/
|
|
94
|
+
scheduleBatchUpdate() {
|
|
95
|
+
if (!this.batchUpdateScheduled) {
|
|
96
|
+
this.batchUpdateScheduled = true;
|
|
97
|
+
// 使用微任务确保在当前执行栈完成后立即执行
|
|
98
|
+
Promise.resolve().then(() => this.processBatchUpdates());
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 处理批量更新
|
|
103
|
+
*/
|
|
104
|
+
processBatchUpdates() {
|
|
105
|
+
this.batchUpdateScheduled = false;
|
|
106
|
+
// 处理添加
|
|
107
|
+
if (this.pendingEntityAdds.length > 0) {
|
|
108
|
+
this.entities.push(...this.pendingEntityAdds);
|
|
109
|
+
// 更新索引
|
|
110
|
+
for (const entity of this.pendingEntityAdds) {
|
|
111
|
+
this.addEntityToIndexes(entity);
|
|
112
|
+
}
|
|
113
|
+
this.pendingEntityAdds.length = 0;
|
|
114
|
+
}
|
|
115
|
+
// 处理移除
|
|
116
|
+
if (this.pendingEntityRemoves.length > 0) {
|
|
117
|
+
const removeSet = new Set(this.pendingEntityRemoves);
|
|
118
|
+
// 从实体列表中移除
|
|
119
|
+
this.entities = this.entities.filter(entity => !removeSet.has(entity));
|
|
120
|
+
// 从索引中移除
|
|
121
|
+
for (const entity of this.pendingEntityRemoves) {
|
|
122
|
+
this.removeEntityFromIndexes(entity);
|
|
123
|
+
}
|
|
124
|
+
this.pendingEntityRemoves.length = 0;
|
|
125
|
+
}
|
|
126
|
+
// 清空缓存
|
|
127
|
+
this.clearCache();
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 强制立即处理所有待处理的更新
|
|
131
|
+
*/
|
|
132
|
+
flushUpdates() {
|
|
133
|
+
if (this.batchUpdateScheduled) {
|
|
134
|
+
this.processBatchUpdates();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 无效化所有索引
|
|
139
|
+
*/
|
|
140
|
+
invalidateIndexes() {
|
|
141
|
+
this.indexDirty = true;
|
|
142
|
+
this.entityIndex.byMask.clear();
|
|
143
|
+
this.entityIndex.byComponentType.clear();
|
|
144
|
+
this.entityIndex.byTag.clear();
|
|
145
|
+
this.entityIndex.byName.clear();
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 将实体添加到索引
|
|
149
|
+
* @param entity 实体
|
|
150
|
+
*/
|
|
151
|
+
addEntityToIndexes(entity) {
|
|
152
|
+
// 按位掩码索引
|
|
153
|
+
const mask = entity.componentMask;
|
|
154
|
+
if (!this.entityIndex.byMask.has(mask)) {
|
|
155
|
+
this.entityIndex.byMask.set(mask, new Set());
|
|
156
|
+
}
|
|
157
|
+
this.entityIndex.byMask.get(mask).add(entity);
|
|
158
|
+
// 按组件类型索引
|
|
159
|
+
for (const component of entity.components) {
|
|
160
|
+
const componentType = component.constructor;
|
|
161
|
+
if (!this.entityIndex.byComponentType.has(componentType)) {
|
|
162
|
+
this.entityIndex.byComponentType.set(componentType, new Set());
|
|
163
|
+
}
|
|
164
|
+
this.entityIndex.byComponentType.get(componentType).add(entity);
|
|
165
|
+
}
|
|
166
|
+
// 按标签索引
|
|
167
|
+
const tag = entity.tag;
|
|
168
|
+
if (!this.entityIndex.byTag.has(tag)) {
|
|
169
|
+
this.entityIndex.byTag.set(tag, new Set());
|
|
170
|
+
}
|
|
171
|
+
this.entityIndex.byTag.get(tag).add(entity);
|
|
172
|
+
// 按名称索引
|
|
173
|
+
const name = entity.name;
|
|
174
|
+
if (!this.entityIndex.byName.has(name)) {
|
|
175
|
+
this.entityIndex.byName.set(name, new Set());
|
|
176
|
+
}
|
|
177
|
+
this.entityIndex.byName.get(name).add(entity);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* 从索引中移除实体
|
|
181
|
+
* @param entity 实体
|
|
182
|
+
*/
|
|
183
|
+
removeEntityFromIndexes(entity) {
|
|
184
|
+
// 从位掩码索引移除
|
|
185
|
+
const mask = entity.componentMask;
|
|
186
|
+
const maskSet = this.entityIndex.byMask.get(mask);
|
|
187
|
+
if (maskSet) {
|
|
188
|
+
maskSet.delete(entity);
|
|
189
|
+
if (maskSet.size === 0) {
|
|
190
|
+
this.entityIndex.byMask.delete(mask);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// 从组件类型索引移除
|
|
194
|
+
for (const component of entity.components) {
|
|
195
|
+
const componentType = component.constructor;
|
|
196
|
+
const typeSet = this.entityIndex.byComponentType.get(componentType);
|
|
197
|
+
if (typeSet) {
|
|
198
|
+
typeSet.delete(entity);
|
|
199
|
+
if (typeSet.size === 0) {
|
|
200
|
+
this.entityIndex.byComponentType.delete(componentType);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// 从标签索引移除
|
|
205
|
+
const tagSet = this.entityIndex.byTag.get(entity.tag);
|
|
206
|
+
if (tagSet) {
|
|
207
|
+
tagSet.delete(entity);
|
|
208
|
+
if (tagSet.size === 0) {
|
|
209
|
+
this.entityIndex.byTag.delete(entity.tag);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// 从名称索引移除
|
|
213
|
+
const nameSet = this.entityIndex.byName.get(entity.name);
|
|
214
|
+
if (nameSet) {
|
|
215
|
+
nameSet.delete(entity);
|
|
216
|
+
if (nameSet.size === 0) {
|
|
217
|
+
this.entityIndex.byName.delete(entity.name);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* 重建所有索引
|
|
223
|
+
*/
|
|
224
|
+
rebuildIndexes() {
|
|
225
|
+
if (!this.indexDirty)
|
|
226
|
+
return;
|
|
227
|
+
this.invalidateIndexes();
|
|
228
|
+
for (const entity of this.entities) {
|
|
229
|
+
this.addEntityToIndexes(entity);
|
|
230
|
+
}
|
|
231
|
+
this.indexDirty = false;
|
|
232
|
+
this.lastIndexUpdate = Date.now();
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* 确保索引是最新的
|
|
236
|
+
*/
|
|
237
|
+
ensureIndexesUpdated() {
|
|
238
|
+
const now = Date.now();
|
|
239
|
+
if (this.indexDirty || (now - this.lastIndexUpdate) > this.indexUpdateThreshold) {
|
|
240
|
+
this.rebuildIndexes();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* 查询包含所有指定组件的实体
|
|
245
|
+
* @param componentTypes 组件类型数组
|
|
246
|
+
* @returns 查询结果
|
|
247
|
+
*/
|
|
248
|
+
queryAll(...componentTypes) {
|
|
249
|
+
return this.query({
|
|
250
|
+
type: QueryConditionType.ALL,
|
|
251
|
+
componentTypes,
|
|
252
|
+
mask: this.createMask(componentTypes)
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* 查询包含任意指定组件的实体
|
|
257
|
+
* @param componentTypes 组件类型数组
|
|
258
|
+
* @returns 查询结果
|
|
259
|
+
*/
|
|
260
|
+
queryAny(...componentTypes) {
|
|
261
|
+
return this.query({
|
|
262
|
+
type: QueryConditionType.ANY,
|
|
263
|
+
componentTypes,
|
|
264
|
+
mask: this.createMask(componentTypes)
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* 查询不包含任何指定组件的实体
|
|
269
|
+
* @param componentTypes 组件类型数组
|
|
270
|
+
* @returns 查询结果
|
|
271
|
+
*/
|
|
272
|
+
queryNone(...componentTypes) {
|
|
273
|
+
return this.query({
|
|
274
|
+
type: QueryConditionType.NONE,
|
|
275
|
+
componentTypes,
|
|
276
|
+
mask: this.createMask(componentTypes)
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* 复合查询:同时满足多个条件
|
|
281
|
+
* @param conditions 查询条件数组
|
|
282
|
+
* @returns 查询结果
|
|
283
|
+
*/
|
|
284
|
+
queryComplex(...conditions) {
|
|
285
|
+
const startTime = performance.now();
|
|
286
|
+
// 生成复合查询的缓存键
|
|
287
|
+
const cacheKey = this.generateComplexCacheKey(conditions);
|
|
288
|
+
// 检查缓存
|
|
289
|
+
const cached = this.getCachedResult(cacheKey);
|
|
290
|
+
if (cached) {
|
|
291
|
+
return {
|
|
292
|
+
entities: cached.entities,
|
|
293
|
+
count: cached.entities.length,
|
|
294
|
+
executionTime: performance.now() - startTime,
|
|
295
|
+
fromCache: true
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
// 执行查询
|
|
299
|
+
let result = this.entities.slice(); // 从所有实体开始
|
|
300
|
+
for (const condition of conditions) {
|
|
301
|
+
result = this.filterEntitiesByCondition(result, condition);
|
|
302
|
+
}
|
|
303
|
+
const executionTime = performance.now() - startTime;
|
|
304
|
+
// 缓存结果
|
|
305
|
+
this.cacheResult(cacheKey, result);
|
|
306
|
+
return {
|
|
307
|
+
entities: result,
|
|
308
|
+
count: result.length,
|
|
309
|
+
executionTime,
|
|
310
|
+
fromCache: false
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* 流式查询构建器
|
|
315
|
+
* @returns 查询构建器实例
|
|
316
|
+
*/
|
|
317
|
+
createQuery() {
|
|
318
|
+
return new QueryBuilder(this);
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* 根据标签查询实体
|
|
322
|
+
* @param tag 标签
|
|
323
|
+
* @returns 查询结果
|
|
324
|
+
*/
|
|
325
|
+
queryByTag(tag) {
|
|
326
|
+
const startTime = performance.now();
|
|
327
|
+
this.ensureIndexesUpdated();
|
|
328
|
+
const entities = Array.from(this.entityIndex.byTag.get(tag) || []);
|
|
329
|
+
const executionTime = performance.now() - startTime;
|
|
330
|
+
this.updatePerformanceStats(executionTime, true);
|
|
331
|
+
return {
|
|
332
|
+
entities,
|
|
333
|
+
count: entities.length,
|
|
334
|
+
executionTime,
|
|
335
|
+
fromCache: false
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* 根据名称查询实体
|
|
340
|
+
* @param name 名称
|
|
341
|
+
* @returns 查询结果
|
|
342
|
+
*/
|
|
343
|
+
queryByName(name) {
|
|
344
|
+
const startTime = performance.now();
|
|
345
|
+
this.ensureIndexesUpdated();
|
|
346
|
+
const entities = Array.from(this.entityIndex.byName.get(name) || []);
|
|
347
|
+
const executionTime = performance.now() - startTime;
|
|
348
|
+
this.updatePerformanceStats(executionTime, true);
|
|
349
|
+
return {
|
|
350
|
+
entities,
|
|
351
|
+
count: entities.length,
|
|
352
|
+
executionTime,
|
|
353
|
+
fromCache: false
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* 根据单个组件类型快速查询
|
|
358
|
+
* @param componentType 组件类型
|
|
359
|
+
* @returns 查询结果
|
|
360
|
+
*/
|
|
361
|
+
queryByComponent(componentType) {
|
|
362
|
+
const startTime = performance.now();
|
|
363
|
+
this.ensureIndexesUpdated();
|
|
364
|
+
const entities = Array.from(this.entityIndex.byComponentType.get(componentType) || []);
|
|
365
|
+
const executionTime = performance.now() - startTime;
|
|
366
|
+
this.updatePerformanceStats(executionTime, true);
|
|
367
|
+
return {
|
|
368
|
+
entities,
|
|
369
|
+
count: entities.length,
|
|
370
|
+
executionTime,
|
|
371
|
+
fromCache: false
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* 类型安全的查询所有指定组件的实体
|
|
376
|
+
* @param componentTypes 组件类型数组
|
|
377
|
+
* @returns 类型安全的查询结果
|
|
378
|
+
*/
|
|
379
|
+
queryAllTyped(...componentTypes) {
|
|
380
|
+
const startTime = performance.now();
|
|
381
|
+
this.ensureIndexesUpdated();
|
|
382
|
+
const condition = {
|
|
383
|
+
type: QueryConditionType.ALL,
|
|
384
|
+
componentTypes: [...componentTypes],
|
|
385
|
+
mask: this.createMask([...componentTypes])
|
|
386
|
+
};
|
|
387
|
+
const entities = this.queryWithIndexOptimization(condition) ||
|
|
388
|
+
this.filterEntitiesByCondition(this.entities, condition);
|
|
389
|
+
// 提取组件
|
|
390
|
+
const components = [];
|
|
391
|
+
for (const entity of entities) {
|
|
392
|
+
const entityComponents = [];
|
|
393
|
+
let hasAllComponents = true;
|
|
394
|
+
for (const type of componentTypes) {
|
|
395
|
+
const component = entity.getComponent(type);
|
|
396
|
+
if (component === null) {
|
|
397
|
+
hasAllComponents = false;
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
entityComponents.push(component);
|
|
401
|
+
}
|
|
402
|
+
if (hasAllComponents) {
|
|
403
|
+
components.push(entityComponents);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const executionTime = performance.now() - startTime;
|
|
407
|
+
this.updatePerformanceStats(executionTime, false);
|
|
408
|
+
return {
|
|
409
|
+
entities,
|
|
410
|
+
components,
|
|
411
|
+
count: entities.length,
|
|
412
|
+
executionTime,
|
|
413
|
+
fromCache: false
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* 查询具有特定组件组合的实体并返回组件实例
|
|
418
|
+
* @param componentTypes 组件类型数组
|
|
419
|
+
* @returns 实体和对应组件的映射
|
|
420
|
+
*/
|
|
421
|
+
queryWithComponents(...componentTypes) {
|
|
422
|
+
const result = this.queryAllTyped(...componentTypes);
|
|
423
|
+
return result.entities.map((entity, index) => ({
|
|
424
|
+
entity,
|
|
425
|
+
components: result.components[index]
|
|
426
|
+
}));
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* 迭代查询结果,为每个匹配的实体执行回调
|
|
430
|
+
* @param componentTypes 组件类型数组
|
|
431
|
+
* @param callback 回调函数
|
|
432
|
+
*/
|
|
433
|
+
forEachWithComponents(componentTypes, callback) {
|
|
434
|
+
const result = this.queryAllTyped(...componentTypes);
|
|
435
|
+
for (let i = 0; i < result.entities.length; i++) {
|
|
436
|
+
callback(result.entities[i], result.components[i]);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* 查询单个组件类型的实体,返回类型安全的结果
|
|
441
|
+
* @param componentType 组件类型
|
|
442
|
+
* @returns 实体和组件的配对数组
|
|
443
|
+
*/
|
|
444
|
+
queryComponentTyped(componentType) {
|
|
445
|
+
const startTime = performance.now();
|
|
446
|
+
this.ensureIndexesUpdated();
|
|
447
|
+
const entities = Array.from(this.entityIndex.byComponentType.get(componentType) || []);
|
|
448
|
+
const result = [];
|
|
449
|
+
for (const entity of entities) {
|
|
450
|
+
const component = entity.getComponent(componentType);
|
|
451
|
+
if (component) {
|
|
452
|
+
result.push({ entity, component });
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
const executionTime = performance.now() - startTime;
|
|
456
|
+
this.updatePerformanceStats(executionTime, true);
|
|
457
|
+
return result;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* 查询两个组件类型的实体,返回类型安全的结果
|
|
461
|
+
* @param componentType1 第一个组件类型
|
|
462
|
+
* @param componentType2 第二个组件类型
|
|
463
|
+
* @returns 实体和组件的配对数组
|
|
464
|
+
*/
|
|
465
|
+
queryTwoComponents(componentType1, componentType2) {
|
|
466
|
+
const result = this.queryAllTyped(componentType1, componentType2);
|
|
467
|
+
return result.entities.map((entity, index) => ({
|
|
468
|
+
entity,
|
|
469
|
+
component1: result.components[index][0],
|
|
470
|
+
component2: result.components[index][1]
|
|
471
|
+
}));
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* 查询三个组件类型的实体,返回类型安全的结果
|
|
475
|
+
* @param componentType1 第一个组件类型
|
|
476
|
+
* @param componentType2 第二个组件类型
|
|
477
|
+
* @param componentType3 第三个组件类型
|
|
478
|
+
* @returns 实体和组件的配对数组
|
|
479
|
+
*/
|
|
480
|
+
queryThreeComponents(componentType1, componentType2, componentType3) {
|
|
481
|
+
const result = this.queryAllTyped(componentType1, componentType2, componentType3);
|
|
482
|
+
return result.entities.map((entity, index) => ({
|
|
483
|
+
entity,
|
|
484
|
+
component1: result.components[index][0],
|
|
485
|
+
component2: result.components[index][1],
|
|
486
|
+
component3: result.components[index][2]
|
|
487
|
+
}));
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* 执行单个条件查询
|
|
491
|
+
* @param condition 查询条件
|
|
492
|
+
* @returns 查询结果
|
|
493
|
+
*/
|
|
494
|
+
query(condition) {
|
|
495
|
+
const startTime = performance.now();
|
|
496
|
+
// 确保索引是最新的
|
|
497
|
+
this.ensureIndexesUpdated();
|
|
498
|
+
// 生成缓存键
|
|
499
|
+
const cacheKey = this.generateCacheKey(condition);
|
|
500
|
+
// 检查缓存
|
|
501
|
+
const cached = this.getCachedResult(cacheKey);
|
|
502
|
+
if (cached) {
|
|
503
|
+
this.updatePerformanceStats(performance.now() - startTime, false);
|
|
504
|
+
return {
|
|
505
|
+
entities: cached.entities,
|
|
506
|
+
count: cached.entities.length,
|
|
507
|
+
executionTime: performance.now() - startTime,
|
|
508
|
+
fromCache: true
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
// 尝试使用索引优化查询
|
|
512
|
+
let result = this.queryWithIndexOptimization(condition);
|
|
513
|
+
// 如果索引优化失败,回退到传统查询
|
|
514
|
+
if (!result) {
|
|
515
|
+
result = this.filterEntitiesByCondition(this.entities, condition);
|
|
516
|
+
}
|
|
517
|
+
const executionTime = performance.now() - startTime;
|
|
518
|
+
// 缓存结果
|
|
519
|
+
this.cacheResult(cacheKey, result);
|
|
520
|
+
// 更新性能统计
|
|
521
|
+
this.updatePerformanceStats(executionTime, false);
|
|
522
|
+
return {
|
|
523
|
+
entities: result,
|
|
524
|
+
count: result.length,
|
|
525
|
+
executionTime,
|
|
526
|
+
fromCache: false
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* 使用索引优化查询
|
|
531
|
+
* @param condition 查询条件
|
|
532
|
+
* @returns 查询结果或null(如果无法优化)
|
|
533
|
+
*/
|
|
534
|
+
queryWithIndexOptimization(condition) {
|
|
535
|
+
// 对于单组件查询,直接使用组件索引
|
|
536
|
+
if (condition.componentTypes.length === 1 && condition.type === QueryConditionType.ALL) {
|
|
537
|
+
const componentType = condition.componentTypes[0];
|
|
538
|
+
const entities = this.entityIndex.byComponentType.get(componentType);
|
|
539
|
+
return entities ? Array.from(entities) : [];
|
|
540
|
+
}
|
|
541
|
+
// 对于多组件ALL查询,找到最小的组件集合作为起点
|
|
542
|
+
if (condition.type === QueryConditionType.ALL && condition.componentTypes.length > 1) {
|
|
543
|
+
let smallestSet = null;
|
|
544
|
+
let smallestSize = Infinity;
|
|
545
|
+
for (const componentType of condition.componentTypes) {
|
|
546
|
+
const entities = this.entityIndex.byComponentType.get(componentType);
|
|
547
|
+
if (!entities)
|
|
548
|
+
return []; // 如果任何组件都没有实体,结果为空
|
|
549
|
+
if (entities.size < smallestSize) {
|
|
550
|
+
smallestSize = entities.size;
|
|
551
|
+
smallestSet = entities;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if (!smallestSet)
|
|
555
|
+
return [];
|
|
556
|
+
// 从最小集合开始,检查每个实体是否包含所有其他组件
|
|
557
|
+
const result = [];
|
|
558
|
+
for (const entity of smallestSet) {
|
|
559
|
+
if (this.matchesCondition(entity, condition)) {
|
|
560
|
+
result.push(entity);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return result;
|
|
564
|
+
}
|
|
565
|
+
// 对于ANY查询,合并所有相关组件的实体集合
|
|
566
|
+
if (condition.type === QueryConditionType.ANY) {
|
|
567
|
+
const entitySet = new Set();
|
|
568
|
+
for (const componentType of condition.componentTypes) {
|
|
569
|
+
const entities = this.entityIndex.byComponentType.get(componentType);
|
|
570
|
+
if (entities) {
|
|
571
|
+
for (const entity of entities) {
|
|
572
|
+
entitySet.add(entity);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return Array.from(entitySet);
|
|
577
|
+
}
|
|
578
|
+
// 对于NONE查询,从所有实体中排除包含指定组件的实体
|
|
579
|
+
if (condition.type === QueryConditionType.NONE) {
|
|
580
|
+
const excludeSet = new Set();
|
|
581
|
+
for (const componentType of condition.componentTypes) {
|
|
582
|
+
const entities = this.entityIndex.byComponentType.get(componentType);
|
|
583
|
+
if (entities) {
|
|
584
|
+
for (const entity of entities) {
|
|
585
|
+
excludeSet.add(entity);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return this.entities.filter(entity => !excludeSet.has(entity));
|
|
590
|
+
}
|
|
591
|
+
return null; // 无法优化
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* 更新性能统计
|
|
595
|
+
* @param executionTime 执行时间
|
|
596
|
+
* @param fromIndex 是否来自索引
|
|
597
|
+
*/
|
|
598
|
+
updatePerformanceStats(executionTime, fromIndex) {
|
|
599
|
+
this.performanceStats.totalQueries++;
|
|
600
|
+
// 更新平均执行时间
|
|
601
|
+
const totalTime = this.performanceStats.averageExecutionTime * (this.performanceStats.totalQueries - 1) + executionTime;
|
|
602
|
+
this.performanceStats.averageExecutionTime = totalTime / this.performanceStats.totalQueries;
|
|
603
|
+
// 更新缓存命中率
|
|
604
|
+
this.performanceStats.cacheHitRate = this.cacheHits / (this.cacheHits + this.cacheMisses);
|
|
605
|
+
// 更新索引命中率
|
|
606
|
+
if (fromIndex) {
|
|
607
|
+
this.performanceStats.indexHitRate = (this.performanceStats.indexHitRate * (this.performanceStats.totalQueries - 1) + 1) / this.performanceStats.totalQueries;
|
|
608
|
+
}
|
|
609
|
+
else {
|
|
610
|
+
this.performanceStats.indexHitRate = (this.performanceStats.indexHitRate * (this.performanceStats.totalQueries - 1)) / this.performanceStats.totalQueries;
|
|
611
|
+
}
|
|
612
|
+
// 记录慢查询
|
|
613
|
+
if (executionTime > 10) { // 超过10ms的查询被认为是慢查询
|
|
614
|
+
this.performanceStats.slowQueries.push({
|
|
615
|
+
query: `执行时间: ${executionTime.toFixed(2)}ms`,
|
|
616
|
+
executionTime,
|
|
617
|
+
timestamp: Date.now()
|
|
618
|
+
});
|
|
619
|
+
// 只保留最近的50个慢查询
|
|
620
|
+
if (this.performanceStats.slowQueries.length > 50) {
|
|
621
|
+
this.performanceStats.slowQueries.shift();
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* 根据条件过滤实体
|
|
627
|
+
* @param entities 实体数组
|
|
628
|
+
* @param condition 查询条件
|
|
629
|
+
* @returns 过滤后的实体数组
|
|
630
|
+
*/
|
|
631
|
+
filterEntitiesByCondition(entities, condition) {
|
|
632
|
+
const result = [];
|
|
633
|
+
for (const entity of entities) {
|
|
634
|
+
if (this.matchesCondition(entity, condition)) {
|
|
635
|
+
result.push(entity);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return result;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* 检查实体是否匹配条件
|
|
642
|
+
* @param entity 实体
|
|
643
|
+
* @param condition 查询条件
|
|
644
|
+
* @returns 是否匹配
|
|
645
|
+
*/
|
|
646
|
+
matchesCondition(entity, condition) {
|
|
647
|
+
const entityMask = entity.componentMask;
|
|
648
|
+
switch (condition.type) {
|
|
649
|
+
case QueryConditionType.ALL:
|
|
650
|
+
// 实体必须包含所有指定组件
|
|
651
|
+
return (entityMask & condition.mask) === condition.mask;
|
|
652
|
+
case QueryConditionType.ANY:
|
|
653
|
+
// 实体必须包含至少一个指定组件
|
|
654
|
+
return (entityMask & condition.mask) !== BigInt(0);
|
|
655
|
+
case QueryConditionType.NONE:
|
|
656
|
+
// 实体不能包含任何指定组件
|
|
657
|
+
return (entityMask & condition.mask) === BigInt(0);
|
|
658
|
+
default:
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* 创建组件类型的位掩码
|
|
664
|
+
* @param componentTypes 组件类型数组
|
|
665
|
+
* @returns 位掩码
|
|
666
|
+
*/
|
|
667
|
+
createMask(componentTypes) {
|
|
668
|
+
let mask = BigInt(0);
|
|
669
|
+
for (const componentType of componentTypes) {
|
|
670
|
+
if (ComponentRegistry.isRegistered(componentType)) {
|
|
671
|
+
mask |= ComponentRegistry.getBitMask(componentType);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return mask;
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* 生成缓存键
|
|
678
|
+
* @param condition 查询条件
|
|
679
|
+
* @returns 缓存键
|
|
680
|
+
*/
|
|
681
|
+
generateCacheKey(condition) {
|
|
682
|
+
const typeNames = condition.componentTypes.map(t => t.name).sort().join(',');
|
|
683
|
+
return `${condition.type}:${typeNames}`;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* 生成复合查询的缓存键
|
|
687
|
+
* @param conditions 查询条件数组
|
|
688
|
+
* @returns 缓存键
|
|
689
|
+
*/
|
|
690
|
+
generateComplexCacheKey(conditions) {
|
|
691
|
+
const conditionKeys = conditions.map(c => this.generateCacheKey(c));
|
|
692
|
+
return `complex:${conditionKeys.join('|')}`;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* 获取缓存结果
|
|
696
|
+
* @param cacheKey 缓存键
|
|
697
|
+
* @returns 缓存项或null
|
|
698
|
+
*/
|
|
699
|
+
getCachedResult(cacheKey) {
|
|
700
|
+
const cached = this.queryCache.get(cacheKey);
|
|
701
|
+
if (cached) {
|
|
702
|
+
const now = Date.now();
|
|
703
|
+
if (now - cached.lastUpdate < this.cacheTimeout) {
|
|
704
|
+
cached.hitCount++;
|
|
705
|
+
this.cacheHits++;
|
|
706
|
+
return cached;
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
// 缓存过期,删除
|
|
710
|
+
this.queryCache.delete(cacheKey);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
this.cacheMisses++;
|
|
714
|
+
return null;
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* 缓存查询结果
|
|
718
|
+
* @param cacheKey 缓存键
|
|
719
|
+
* @param entities 实体数组
|
|
720
|
+
*/
|
|
721
|
+
cacheResult(cacheKey, entities) {
|
|
722
|
+
// 如果缓存已满,删除最少使用的项
|
|
723
|
+
if (this.queryCache.size >= this.maxCacheSize) {
|
|
724
|
+
this.evictLeastUsedCache();
|
|
725
|
+
}
|
|
726
|
+
this.queryCache.set(cacheKey, {
|
|
727
|
+
entities: entities.slice(), // 创建副本
|
|
728
|
+
lastUpdate: Date.now(),
|
|
729
|
+
hitCount: 0
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* 清空查询缓存
|
|
734
|
+
*/
|
|
735
|
+
clearCache() {
|
|
736
|
+
this.queryCache.clear();
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* 删除最少使用的缓存项
|
|
740
|
+
*/
|
|
741
|
+
evictLeastUsedCache() {
|
|
742
|
+
let leastUsedKey = '';
|
|
743
|
+
let minHitCount = Number.MAX_VALUE;
|
|
744
|
+
for (const [key, item] of this.queryCache.entries()) {
|
|
745
|
+
if (item.hitCount < minHitCount) {
|
|
746
|
+
minHitCount = item.hitCount;
|
|
747
|
+
leastUsedKey = key;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
if (leastUsedKey) {
|
|
751
|
+
this.queryCache.delete(leastUsedKey);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* 获取详细的查询统计信息
|
|
756
|
+
*/
|
|
757
|
+
getStats() {
|
|
758
|
+
const totalQueries = this.cacheHits + this.cacheMisses;
|
|
759
|
+
const hitRate = totalQueries > 0 ? this.cacheHits / totalQueries : 0;
|
|
760
|
+
return {
|
|
761
|
+
entityCount: this.entities.length,
|
|
762
|
+
cacheSize: this.queryCache.size,
|
|
763
|
+
cacheHits: this.cacheHits,
|
|
764
|
+
cacheMisses: this.cacheMisses,
|
|
765
|
+
hitRate,
|
|
766
|
+
maxCacheSize: this.maxCacheSize,
|
|
767
|
+
indexStats: {
|
|
768
|
+
maskIndexSize: this.entityIndex.byMask.size,
|
|
769
|
+
componentIndexSize: this.entityIndex.byComponentType.size,
|
|
770
|
+
tagIndexSize: this.entityIndex.byTag.size,
|
|
771
|
+
nameIndexSize: this.entityIndex.byName.size
|
|
772
|
+
},
|
|
773
|
+
performanceStats: { ...this.performanceStats }
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* 获取性能报告
|
|
778
|
+
*/
|
|
779
|
+
getPerformanceReport() {
|
|
780
|
+
const stats = this.getStats();
|
|
781
|
+
let report = '=== 查询系统性能报告 ===\n';
|
|
782
|
+
report += `实体数量: ${stats.entityCount}\n`;
|
|
783
|
+
report += `总查询次数: ${stats.performanceStats.totalQueries}\n`;
|
|
784
|
+
report += `平均执行时间: ${stats.performanceStats.averageExecutionTime.toFixed(2)}ms\n`;
|
|
785
|
+
report += `缓存命中率: ${(stats.performanceStats.cacheHitRate * 100).toFixed(1)}%\n`;
|
|
786
|
+
report += `索引命中率: ${(stats.performanceStats.indexHitRate * 100).toFixed(1)}%\n`;
|
|
787
|
+
report += '\n=== 索引统计 ===\n';
|
|
788
|
+
report += `位掩码索引: ${stats.indexStats.maskIndexSize} 项\n`;
|
|
789
|
+
report += `组件类型索引: ${stats.indexStats.componentIndexSize} 项\n`;
|
|
790
|
+
report += `标签索引: ${stats.indexStats.tagIndexSize} 项\n`;
|
|
791
|
+
report += `名称索引: ${stats.indexStats.nameIndexSize} 项\n`;
|
|
792
|
+
if (stats.performanceStats.slowQueries.length > 0) {
|
|
793
|
+
report += '\n=== 慢查询记录 ===\n';
|
|
794
|
+
stats.performanceStats.slowQueries.slice(-10).forEach((query, index) => {
|
|
795
|
+
const time = new Date(query.timestamp).toLocaleTimeString();
|
|
796
|
+
report += `${index + 1}. ${query.query} (${time})\n`;
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
return report;
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* 优化索引配置
|
|
803
|
+
*/
|
|
804
|
+
optimizeIndexes() {
|
|
805
|
+
// 根据查询模式优化索引更新频率
|
|
806
|
+
if (this.performanceStats.totalQueries > 1000) {
|
|
807
|
+
// 高频查询场景,降低索引更新阈值
|
|
808
|
+
this.indexUpdateThreshold = 50;
|
|
809
|
+
}
|
|
810
|
+
else {
|
|
811
|
+
// 低频查询场景,提高索引更新阈值
|
|
812
|
+
this.indexUpdateThreshold = 200;
|
|
813
|
+
}
|
|
814
|
+
// 根据缓存命中率调整缓存大小
|
|
815
|
+
if (this.performanceStats.cacheHitRate < 0.5 && this.maxCacheSize < 200) {
|
|
816
|
+
this.maxCacheSize = Math.min(200, this.maxCacheSize * 1.5);
|
|
817
|
+
}
|
|
818
|
+
else if (this.performanceStats.cacheHitRate > 0.9 && this.maxCacheSize > 50) {
|
|
819
|
+
this.maxCacheSize = Math.max(50, this.maxCacheSize * 0.8);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* 批量查询多个条件
|
|
824
|
+
* @param queries 查询条件数组
|
|
825
|
+
* @returns 查询结果数组
|
|
826
|
+
*/
|
|
827
|
+
batchQuery(queries) {
|
|
828
|
+
const startTime = performance.now();
|
|
829
|
+
this.ensureIndexesUpdated();
|
|
830
|
+
const results = [];
|
|
831
|
+
for (const query of queries) {
|
|
832
|
+
const result = this.query(query);
|
|
833
|
+
results.push(result);
|
|
834
|
+
}
|
|
835
|
+
const totalTime = performance.now() - startTime;
|
|
836
|
+
console.log(`批量查询 ${queries.length} 个条件,总耗时: ${totalTime.toFixed(2)}ms`);
|
|
837
|
+
return results;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* 设置缓存配置
|
|
841
|
+
* @param maxSize 最大缓存大小
|
|
842
|
+
* @param timeout 缓存超时时间(毫秒)
|
|
843
|
+
*/
|
|
844
|
+
setCacheConfig(maxSize, timeout) {
|
|
845
|
+
this.maxCacheSize = maxSize;
|
|
846
|
+
this.cacheTimeout = timeout;
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* 重置统计信息
|
|
850
|
+
*/
|
|
851
|
+
resetStats() {
|
|
852
|
+
this.cacheHits = 0;
|
|
853
|
+
this.cacheMisses = 0;
|
|
854
|
+
this.performanceStats = {
|
|
855
|
+
totalQueries: 0,
|
|
856
|
+
averageExecutionTime: 0,
|
|
857
|
+
cacheHitRate: 0,
|
|
858
|
+
indexHitRate: 0,
|
|
859
|
+
slowQueries: []
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
/**
|
|
863
|
+
* 预热查询缓存
|
|
864
|
+
* @param commonQueries 常用查询条件数组
|
|
865
|
+
*/
|
|
866
|
+
warmUpCache(commonQueries) {
|
|
867
|
+
console.log('开始预热查询缓存...');
|
|
868
|
+
const startTime = performance.now();
|
|
869
|
+
for (const condition of commonQueries) {
|
|
870
|
+
this.query(condition);
|
|
871
|
+
}
|
|
872
|
+
const endTime = performance.now();
|
|
873
|
+
console.log(`缓存预热完成,耗时: ${(endTime - startTime).toFixed(2)}ms`);
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* 获取实体变更监听器
|
|
877
|
+
* @param condition 查询条件
|
|
878
|
+
* @param callback 变更回调
|
|
879
|
+
* @returns 取消监听的函数
|
|
880
|
+
*/
|
|
881
|
+
watchQuery(condition, callback) {
|
|
882
|
+
let lastResult = this.query(condition).entities;
|
|
883
|
+
const checkChanges = () => {
|
|
884
|
+
const currentResult = this.query(condition).entities;
|
|
885
|
+
// 检查新增的实体
|
|
886
|
+
const added = currentResult.filter(entity => !lastResult.includes(entity));
|
|
887
|
+
if (added.length > 0) {
|
|
888
|
+
callback(added, 'added');
|
|
889
|
+
}
|
|
890
|
+
// 检查移除的实体
|
|
891
|
+
const removed = lastResult.filter(entity => !currentResult.includes(entity));
|
|
892
|
+
if (removed.length > 0) {
|
|
893
|
+
callback(removed, 'removed');
|
|
894
|
+
}
|
|
895
|
+
lastResult = currentResult;
|
|
896
|
+
};
|
|
897
|
+
// 使用定时器定期检查变更(实际项目中可能需要更高效的实现)
|
|
898
|
+
const intervalId = setInterval(checkChanges, 100);
|
|
899
|
+
return () => {
|
|
900
|
+
clearInterval(intervalId);
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* 获取查询结果的快照
|
|
905
|
+
* @param condition 查询条件
|
|
906
|
+
* @returns 查询快照
|
|
907
|
+
*/
|
|
908
|
+
createSnapshot(condition) {
|
|
909
|
+
const result = this.query(condition);
|
|
910
|
+
return {
|
|
911
|
+
entities: [...result.entities], // 创建副本
|
|
912
|
+
timestamp: Date.now(),
|
|
913
|
+
condition: { ...condition }
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* 比较两个查询快照
|
|
918
|
+
* @param snapshot1 第一个快照
|
|
919
|
+
* @param snapshot2 第二个快照
|
|
920
|
+
* @returns 比较结果
|
|
921
|
+
*/
|
|
922
|
+
compareSnapshots(snapshot1, snapshot2) {
|
|
923
|
+
const set1 = new Set(snapshot1.entities);
|
|
924
|
+
const set2 = new Set(snapshot2.entities);
|
|
925
|
+
const added = snapshot2.entities.filter(entity => !set1.has(entity));
|
|
926
|
+
const removed = snapshot1.entities.filter(entity => !set2.has(entity));
|
|
927
|
+
const unchanged = snapshot1.entities.filter(entity => set2.has(entity));
|
|
928
|
+
return { added, removed, unchanged };
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* 执行并行查询
|
|
932
|
+
* @param conditions 查询条件数组
|
|
933
|
+
* @returns Promise<查询结果数组>
|
|
934
|
+
*/
|
|
935
|
+
async parallelQuery(conditions) {
|
|
936
|
+
const promises = conditions.map(condition => Promise.resolve(this.query(condition)));
|
|
937
|
+
return Promise.all(promises);
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* 获取查询建议
|
|
941
|
+
* @param entities 实体数组
|
|
942
|
+
* @returns 查询优化建议
|
|
943
|
+
*/
|
|
944
|
+
getQuerySuggestions(entities) {
|
|
945
|
+
const suggestions = [];
|
|
946
|
+
// 分析组件使用频率
|
|
947
|
+
const componentFrequency = new Map();
|
|
948
|
+
for (const entity of entities) {
|
|
949
|
+
for (const component of entity.components) {
|
|
950
|
+
const type = component.constructor;
|
|
951
|
+
componentFrequency.set(type, (componentFrequency.get(type) || 0) + 1);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
// 建议基于高频组件的查询
|
|
955
|
+
const sortedComponents = Array.from(componentFrequency.entries())
|
|
956
|
+
.sort((a, b) => b[1] - a[1])
|
|
957
|
+
.slice(0, 5);
|
|
958
|
+
for (const [componentType, count] of sortedComponents) {
|
|
959
|
+
suggestions.push(`考虑为组件 ${componentType.name} 创建专门的查询(使用频率: ${count})`);
|
|
960
|
+
}
|
|
961
|
+
// 建议缓存配置
|
|
962
|
+
if (this.performanceStats.cacheHitRate < 0.5) {
|
|
963
|
+
suggestions.push('缓存命中率较低,考虑增加缓存大小或调整缓存策略');
|
|
964
|
+
}
|
|
965
|
+
// 建议索引优化
|
|
966
|
+
if (this.performanceStats.indexHitRate < 0.7) {
|
|
967
|
+
suggestions.push('索引命中率较低,考虑重建索引或优化查询条件');
|
|
968
|
+
}
|
|
969
|
+
return suggestions;
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* 导出查询统计数据
|
|
973
|
+
* @returns 统计数据的JSON字符串
|
|
974
|
+
*/
|
|
975
|
+
exportStats() {
|
|
976
|
+
const stats = this.getStats();
|
|
977
|
+
return JSON.stringify(stats, null, 2);
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* 导入查询统计数据
|
|
981
|
+
* @param statsJson 统计数据的JSON字符串
|
|
982
|
+
*/
|
|
983
|
+
importStats(statsJson) {
|
|
984
|
+
try {
|
|
985
|
+
const stats = JSON.parse(statsJson);
|
|
986
|
+
this.cacheHits = stats.cacheHits || 0;
|
|
987
|
+
this.cacheMisses = stats.cacheMisses || 0;
|
|
988
|
+
this.performanceStats = stats.performanceStats || this.performanceStats;
|
|
989
|
+
}
|
|
990
|
+
catch (error) {
|
|
991
|
+
console.error('导入统计数据失败:', error);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* 流式查询构建器
|
|
997
|
+
* 提供链式调用的查询API
|
|
998
|
+
*/
|
|
999
|
+
export class QueryBuilder {
|
|
1000
|
+
constructor(querySystem) {
|
|
1001
|
+
this.conditions = [];
|
|
1002
|
+
this.querySystem = querySystem;
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* 添加"包含所有"条件
|
|
1006
|
+
* @param componentTypes 组件类型
|
|
1007
|
+
* @returns 查询构建器
|
|
1008
|
+
*/
|
|
1009
|
+
withAll(...componentTypes) {
|
|
1010
|
+
this.conditions.push({
|
|
1011
|
+
type: QueryConditionType.ALL,
|
|
1012
|
+
componentTypes,
|
|
1013
|
+
mask: this.createMask(componentTypes)
|
|
1014
|
+
});
|
|
1015
|
+
return this;
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* 添加"包含任意"条件
|
|
1019
|
+
* @param componentTypes 组件类型
|
|
1020
|
+
* @returns 查询构建器
|
|
1021
|
+
*/
|
|
1022
|
+
withAny(...componentTypes) {
|
|
1023
|
+
this.conditions.push({
|
|
1024
|
+
type: QueryConditionType.ANY,
|
|
1025
|
+
componentTypes,
|
|
1026
|
+
mask: this.createMask(componentTypes)
|
|
1027
|
+
});
|
|
1028
|
+
return this;
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* 添加"不包含"条件
|
|
1032
|
+
* @param componentTypes 组件类型
|
|
1033
|
+
* @returns 查询构建器
|
|
1034
|
+
*/
|
|
1035
|
+
without(...componentTypes) {
|
|
1036
|
+
this.conditions.push({
|
|
1037
|
+
type: QueryConditionType.NONE,
|
|
1038
|
+
componentTypes,
|
|
1039
|
+
mask: this.createMask(componentTypes)
|
|
1040
|
+
});
|
|
1041
|
+
return this;
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* 执行查询
|
|
1045
|
+
* @returns 查询结果
|
|
1046
|
+
*/
|
|
1047
|
+
execute() {
|
|
1048
|
+
let result;
|
|
1049
|
+
if (this.conditions.length === 0) {
|
|
1050
|
+
// 如果没有组件条件,但有其他过滤条件
|
|
1051
|
+
if (this.tagFilter !== undefined) {
|
|
1052
|
+
result = this.querySystem.queryByTag(this.tagFilter);
|
|
1053
|
+
}
|
|
1054
|
+
else if (this.nameFilter !== undefined) {
|
|
1055
|
+
result = this.querySystem.queryByName(this.nameFilter);
|
|
1056
|
+
}
|
|
1057
|
+
else {
|
|
1058
|
+
return {
|
|
1059
|
+
entities: [],
|
|
1060
|
+
count: 0,
|
|
1061
|
+
executionTime: 0,
|
|
1062
|
+
fromCache: false
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
else if (this.conditions.length === 1) {
|
|
1067
|
+
// 单条件查询,使用优化路径
|
|
1068
|
+
const condition = this.conditions[0];
|
|
1069
|
+
switch (condition.type) {
|
|
1070
|
+
case QueryConditionType.ALL:
|
|
1071
|
+
result = this.querySystem.queryAll(...condition.componentTypes);
|
|
1072
|
+
break;
|
|
1073
|
+
case QueryConditionType.ANY:
|
|
1074
|
+
result = this.querySystem.queryAny(...condition.componentTypes);
|
|
1075
|
+
break;
|
|
1076
|
+
case QueryConditionType.NONE:
|
|
1077
|
+
result = this.querySystem.queryNone(...condition.componentTypes);
|
|
1078
|
+
break;
|
|
1079
|
+
default:
|
|
1080
|
+
return {
|
|
1081
|
+
entities: [],
|
|
1082
|
+
count: 0,
|
|
1083
|
+
executionTime: 0,
|
|
1084
|
+
fromCache: false
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
else {
|
|
1089
|
+
// 多条件查询
|
|
1090
|
+
result = this.querySystem.queryComplex(...this.conditions);
|
|
1091
|
+
}
|
|
1092
|
+
// 应用额外的过滤条件
|
|
1093
|
+
let entities = result.entities;
|
|
1094
|
+
// 标签过滤
|
|
1095
|
+
if (this.tagFilter !== undefined) {
|
|
1096
|
+
entities = entities.filter(entity => entity.tag === this.tagFilter);
|
|
1097
|
+
}
|
|
1098
|
+
// 名称过滤
|
|
1099
|
+
if (this.nameFilter !== undefined) {
|
|
1100
|
+
entities = entities.filter(entity => entity.name === this.nameFilter);
|
|
1101
|
+
}
|
|
1102
|
+
// 排序
|
|
1103
|
+
if (this.sortFunction) {
|
|
1104
|
+
entities = [...entities].sort(this.sortFunction);
|
|
1105
|
+
}
|
|
1106
|
+
// 偏移
|
|
1107
|
+
if (this.offsetCount !== undefined && this.offsetCount > 0) {
|
|
1108
|
+
entities = entities.slice(this.offsetCount);
|
|
1109
|
+
}
|
|
1110
|
+
// 限制
|
|
1111
|
+
if (this.limitCount !== undefined && this.limitCount > 0) {
|
|
1112
|
+
entities = entities.slice(0, this.limitCount);
|
|
1113
|
+
}
|
|
1114
|
+
return {
|
|
1115
|
+
entities,
|
|
1116
|
+
count: entities.length,
|
|
1117
|
+
executionTime: result.executionTime,
|
|
1118
|
+
fromCache: result.fromCache
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
/**
|
|
1122
|
+
* 获取第一个匹配的实体
|
|
1123
|
+
* @returns 实体或null
|
|
1124
|
+
*/
|
|
1125
|
+
first() {
|
|
1126
|
+
const result = this.execute();
|
|
1127
|
+
return result.entities.length > 0 ? result.entities[0] : null;
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* 检查是否有匹配的实体
|
|
1131
|
+
* @returns 是否有匹配
|
|
1132
|
+
*/
|
|
1133
|
+
any() {
|
|
1134
|
+
const result = this.execute();
|
|
1135
|
+
return result.count > 0;
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* 获取匹配实体的数量
|
|
1139
|
+
* @returns 实体数量
|
|
1140
|
+
*/
|
|
1141
|
+
count() {
|
|
1142
|
+
const result = this.execute();
|
|
1143
|
+
return result.count;
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* 对每个匹配的实体执行操作
|
|
1147
|
+
* @param callback 回调函数
|
|
1148
|
+
*/
|
|
1149
|
+
forEach(callback) {
|
|
1150
|
+
const result = this.execute();
|
|
1151
|
+
result.entities.forEach(callback);
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* 转换为数组
|
|
1155
|
+
* @returns 实体数组
|
|
1156
|
+
*/
|
|
1157
|
+
toArray() {
|
|
1158
|
+
const result = this.execute();
|
|
1159
|
+
return result.entities;
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* 创建组件类型的位掩码
|
|
1163
|
+
* @param componentTypes 组件类型数组
|
|
1164
|
+
* @returns 位掩码
|
|
1165
|
+
*/
|
|
1166
|
+
createMask(componentTypes) {
|
|
1167
|
+
let mask = BigInt(0);
|
|
1168
|
+
for (const componentType of componentTypes) {
|
|
1169
|
+
if (ComponentRegistry.isRegistered(componentType)) {
|
|
1170
|
+
mask |= ComponentRegistry.getBitMask(componentType);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
return mask;
|
|
1174
|
+
}
|
|
1175
|
+
/**
|
|
1176
|
+
* 重置查询条件
|
|
1177
|
+
* @returns 查询构建器
|
|
1178
|
+
*/
|
|
1179
|
+
reset() {
|
|
1180
|
+
this.conditions.length = 0;
|
|
1181
|
+
this.tagFilter = undefined;
|
|
1182
|
+
this.nameFilter = undefined;
|
|
1183
|
+
this.limitCount = undefined;
|
|
1184
|
+
this.offsetCount = undefined;
|
|
1185
|
+
this.sortFunction = undefined;
|
|
1186
|
+
return this;
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* 添加标签过滤条件
|
|
1190
|
+
* @param tag 标签
|
|
1191
|
+
* @returns 查询构建器实例
|
|
1192
|
+
*/
|
|
1193
|
+
withTag(tag) {
|
|
1194
|
+
this.tagFilter = tag;
|
|
1195
|
+
return this;
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* 添加名称过滤条件
|
|
1199
|
+
* @param name 名称
|
|
1200
|
+
* @returns 查询构建器实例
|
|
1201
|
+
*/
|
|
1202
|
+
withName(name) {
|
|
1203
|
+
this.nameFilter = name;
|
|
1204
|
+
return this;
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1207
|
+
* 限制结果数量
|
|
1208
|
+
* @param limit 最大结果数量
|
|
1209
|
+
* @returns 查询构建器实例
|
|
1210
|
+
*/
|
|
1211
|
+
limit(limit) {
|
|
1212
|
+
this.limitCount = limit;
|
|
1213
|
+
return this;
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* 跳过指定数量的结果
|
|
1217
|
+
* @param offset 跳过的数量
|
|
1218
|
+
* @returns 查询构建器实例
|
|
1219
|
+
*/
|
|
1220
|
+
offset(offset) {
|
|
1221
|
+
this.offsetCount = offset;
|
|
1222
|
+
return this;
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* 对结果进行排序
|
|
1226
|
+
* @param compareFn 比较函数
|
|
1227
|
+
* @returns 查询构建器实例
|
|
1228
|
+
*/
|
|
1229
|
+
orderBy(compareFn) {
|
|
1230
|
+
this.sortFunction = compareFn;
|
|
1231
|
+
return this;
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* 按更新顺序排序
|
|
1235
|
+
* @returns 查询构建器实例
|
|
1236
|
+
*/
|
|
1237
|
+
orderByUpdateOrder() {
|
|
1238
|
+
return this.orderBy((a, b) => a.updateOrder - b.updateOrder);
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* 按ID排序
|
|
1242
|
+
* @returns 查询构建器实例
|
|
1243
|
+
*/
|
|
1244
|
+
orderById() {
|
|
1245
|
+
return this.orderBy((a, b) => a.id - b.id);
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* 按名称排序
|
|
1249
|
+
* @returns 查询构建器实例
|
|
1250
|
+
*/
|
|
1251
|
+
orderByName() {
|
|
1252
|
+
return this.orderBy((a, b) => a.name.localeCompare(b.name));
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* 克隆查询构建器
|
|
1256
|
+
* @returns 新的查询构建器
|
|
1257
|
+
*/
|
|
1258
|
+
clone() {
|
|
1259
|
+
const newBuilder = new QueryBuilder(this.querySystem);
|
|
1260
|
+
newBuilder.conditions = this.conditions.map(c => ({ ...c }));
|
|
1261
|
+
newBuilder.tagFilter = this.tagFilter;
|
|
1262
|
+
newBuilder.nameFilter = this.nameFilter;
|
|
1263
|
+
newBuilder.limitCount = this.limitCount;
|
|
1264
|
+
newBuilder.offsetCount = this.offsetCount;
|
|
1265
|
+
newBuilder.sortFunction = this.sortFunction;
|
|
1266
|
+
return newBuilder;
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* 添加自定义过滤器
|
|
1270
|
+
* @param predicate 过滤谓词
|
|
1271
|
+
* @returns 查询构建器实例
|
|
1272
|
+
*/
|
|
1273
|
+
filter(predicate) {
|
|
1274
|
+
const originalExecute = this.execute.bind(this);
|
|
1275
|
+
this.execute = () => {
|
|
1276
|
+
const result = originalExecute();
|
|
1277
|
+
const filteredEntities = result.entities.filter(predicate);
|
|
1278
|
+
return {
|
|
1279
|
+
...result,
|
|
1280
|
+
entities: filteredEntities,
|
|
1281
|
+
count: filteredEntities.length
|
|
1282
|
+
};
|
|
1283
|
+
};
|
|
1284
|
+
return this;
|
|
1285
|
+
}
|
|
1286
|
+
/**
|
|
1287
|
+
* 映射查询结果
|
|
1288
|
+
* @param mapper 映射函数
|
|
1289
|
+
* @returns 映射后的结果数组
|
|
1290
|
+
*/
|
|
1291
|
+
map(mapper) {
|
|
1292
|
+
const result = this.execute();
|
|
1293
|
+
return result.entities.map(mapper);
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1296
|
+
* 查找第一个满足条件的实体
|
|
1297
|
+
* @param predicate 查找谓词
|
|
1298
|
+
* @returns 实体或null
|
|
1299
|
+
*/
|
|
1300
|
+
find(predicate) {
|
|
1301
|
+
const result = this.execute();
|
|
1302
|
+
if (predicate) {
|
|
1303
|
+
return result.entities.find(predicate) || null;
|
|
1304
|
+
}
|
|
1305
|
+
return result.entities[0] || null;
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* 检查是否所有实体都满足条件
|
|
1309
|
+
* @param predicate 检查谓词
|
|
1310
|
+
* @returns 是否所有实体都满足条件
|
|
1311
|
+
*/
|
|
1312
|
+
every(predicate) {
|
|
1313
|
+
const result = this.execute();
|
|
1314
|
+
return result.entities.every(predicate);
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* 检查是否有实体满足条件
|
|
1318
|
+
* @param predicate 检查谓词
|
|
1319
|
+
* @returns 是否有实体满足条件
|
|
1320
|
+
*/
|
|
1321
|
+
some(predicate) {
|
|
1322
|
+
const result = this.execute();
|
|
1323
|
+
return result.entities.some(predicate);
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* 获取查询的调试信息
|
|
1327
|
+
* @returns 调试信息字符串
|
|
1328
|
+
*/
|
|
1329
|
+
getDebugInfo() {
|
|
1330
|
+
let info = '=== 查询构建器调试信息 ===\n';
|
|
1331
|
+
if (this.conditions.length > 0) {
|
|
1332
|
+
info += '组件条件:\n';
|
|
1333
|
+
this.conditions.forEach((condition, index) => {
|
|
1334
|
+
const typeNames = condition.componentTypes.map(t => t.name).join(', ');
|
|
1335
|
+
info += ` ${index + 1}. ${condition.type}: [${typeNames}]\n`;
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
if (this.tagFilter !== undefined) {
|
|
1339
|
+
info += `标签过滤: ${this.tagFilter}\n`;
|
|
1340
|
+
}
|
|
1341
|
+
if (this.nameFilter !== undefined) {
|
|
1342
|
+
info += `名称过滤: ${this.nameFilter}\n`;
|
|
1343
|
+
}
|
|
1344
|
+
if (this.limitCount !== undefined) {
|
|
1345
|
+
info += `限制数量: ${this.limitCount}\n`;
|
|
1346
|
+
}
|
|
1347
|
+
if (this.offsetCount !== undefined) {
|
|
1348
|
+
info += `偏移量: ${this.offsetCount}\n`;
|
|
1349
|
+
}
|
|
1350
|
+
if (this.sortFunction) {
|
|
1351
|
+
info += '已设置排序函数\n';
|
|
1352
|
+
}
|
|
1353
|
+
return info;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
//# sourceMappingURL=QuerySystem.js.map
|