@nimbus2d/core 0.0.1

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 (85) hide show
  1. package/dist/index.mjs +18433 -0
  2. package/package.json +39 -0
  3. package/src/base/EventEmitter.js +187 -0
  4. package/src/base/Subsystem.js +183 -0
  5. package/src/base/index.js +6 -0
  6. package/src/core/Application/AppState.js +27 -0
  7. package/src/core/Application/Application.js +480 -0
  8. package/src/core/Application/DefaultConfig.js +63 -0
  9. package/src/core/Application/index.js +7 -0
  10. package/src/core/AssetManager/AssetManager.js +711 -0
  11. package/src/core/AssetManager/AssetTypes.js +108 -0
  12. package/src/core/AssetManager/adapters/IResourceAdapter.js +50 -0
  13. package/src/core/AssetManager/adapters/PixiAdapter.js +90 -0
  14. package/src/core/AssetManager/core/RefCounter.js +167 -0
  15. package/src/core/AssetManager/core/ResourceCache.js +281 -0
  16. package/src/core/AssetManager/core/ResourceEntry.js +191 -0
  17. package/src/core/AssetManager/core/ResourceEventBus.js +127 -0
  18. package/src/core/AssetManager/handlers/IResourceHandler.js +45 -0
  19. package/src/core/AssetManager/index.js +26 -0
  20. package/src/core/AssetManager/plugins/IResourcePlugin.js +56 -0
  21. package/src/core/Camera/Camera.js +534 -0
  22. package/src/core/Camera/CameraTypes.js +59 -0
  23. package/src/core/Camera/index.js +13 -0
  24. package/src/core/ConfigSystem/ConfigLayer.js +230 -0
  25. package/src/core/ConfigSystem/ConfigLayerType.js +31 -0
  26. package/src/core/ConfigSystem/ConfigMerger.js +50 -0
  27. package/src/core/ConfigSystem/ConfigPath.js +96 -0
  28. package/src/core/ConfigSystem/ConfigSystem.js +378 -0
  29. package/src/core/ConfigSystem/ConfigTypes.js +29 -0
  30. package/src/core/ConfigSystem/ConfigWatcher.js +84 -0
  31. package/src/core/ConfigSystem/index.js +19 -0
  32. package/src/core/EventBus/EventBus.js +797 -0
  33. package/src/core/EventBus/Interceptor.js +26 -0
  34. package/src/core/EventBus/PerformanceStats.js +105 -0
  35. package/src/core/EventBus/index.js +7 -0
  36. package/src/core/Lifecycle/Lifecycle.js +265 -0
  37. package/src/core/Lifecycle/LifecycleState.js +31 -0
  38. package/src/core/Lifecycle/index.js +6 -0
  39. package/src/core/Logger/ConsoleHandler.js +55 -0
  40. package/src/core/Logger/LogHandler.js +34 -0
  41. package/src/core/Logger/LogLevel.js +38 -0
  42. package/src/core/Logger/Logger.js +234 -0
  43. package/src/core/Logger/index.js +8 -0
  44. package/src/core/PluginSystem/Plugin.js +156 -0
  45. package/src/core/PluginSystem/PluginEntry.js +102 -0
  46. package/src/core/PluginSystem/PluginState.js +30 -0
  47. package/src/core/PluginSystem/PluginSystem.js +530 -0
  48. package/src/core/PluginSystem/index.js +8 -0
  49. package/src/core/PoolManager/DefaultConfig.js +19 -0
  50. package/src/core/PoolManager/ObjectPool.js +326 -0
  51. package/src/core/PoolManager/PoolManager.js +253 -0
  52. package/src/core/PoolManager/PoolTypes.js +92 -0
  53. package/src/core/PoolManager/index.js +15 -0
  54. package/src/core/SceneManager/FadeTransition.js +64 -0
  55. package/src/core/SceneManager/MaskTransition.js +234 -0
  56. package/src/core/SceneManager/Scene.js +221 -0
  57. package/src/core/SceneManager/SceneManager.js +658 -0
  58. package/src/core/SceneManager/SceneState.js +29 -0
  59. package/src/core/SceneManager/SlideTransition.js +113 -0
  60. package/src/core/SceneManager/Transition.js +102 -0
  61. package/src/core/SceneManager/ZoomTransition.js +119 -0
  62. package/src/core/SceneManager/index.js +12 -0
  63. package/src/core/SpriteGPULayer/SpriteGPULayer.js +321 -0
  64. package/src/core/SpriteGPULayer/SpriteGPULayerTypes.js +49 -0
  65. package/src/core/SpriteGPULayer/index.js +11 -0
  66. package/src/core/Timeline/Clip.js +101 -0
  67. package/src/core/Timeline/DefaultConfig.js +41 -0
  68. package/src/core/Timeline/Easing.js +176 -0
  69. package/src/core/Timeline/Timeline.js +458 -0
  70. package/src/core/Timeline/TimelineTypes.js +89 -0
  71. package/src/core/Timeline/Track.js +202 -0
  72. package/src/core/Timeline/index.js +22 -0
  73. package/src/errors/ConfigError.js +47 -0
  74. package/src/errors/LifecycleError.js +58 -0
  75. package/src/errors/NimbusError.js +43 -0
  76. package/src/errors/PluginError.js +138 -0
  77. package/src/errors/ResourceError.js +166 -0
  78. package/src/errors/SceneError.js +124 -0
  79. package/src/errors/SubsystemError.js +68 -0
  80. package/src/errors/index.js +53 -0
  81. package/src/index.js +86 -0
  82. package/src/types/index.js +141 -0
  83. package/src/utils/MemoryChecker.js +374 -0
  84. package/src/utils/Validator.js +60 -0
  85. package/src/utils/index.js +84 -0
@@ -0,0 +1,530 @@
1
+ // ============================================================================
2
+ // Nimbus2D - PluginSystem 插件管理
3
+ // ----------------------------------------------------------------------------
4
+ // 职责:
5
+ // 1. 强制继承 Plugin 类
6
+ // 2. install/uninstall 两阶段生命周期
7
+ // 3. 静态依赖声明 + 拓扑排序安装
8
+ // 4. 完整插件状态机:REGISTERED → INSTALLING → INSTALLED → UNINSTALLING → UNREGISTERED / ERROR
9
+ // 5. 错误隔离(单个插件失败不影响其他插件)
10
+ // 6. 生命周期钩子(三期新增):beforeInstall/afterInstall/beforeUninstall/afterUninstall
11
+ // 双模式:插件定义钩子方法 + 事件广播 + onHook 外部订阅
12
+ //
13
+ // 继承关系:
14
+ // EventEmitter → Subsystem → PluginSystem(Lifecycle 内第四个/最后初始化)
15
+ // ============================================================================
16
+
17
+ import { Subsystem } from '../../base/Subsystem.js'
18
+ import { Plugin } from './Plugin.js'
19
+ import { PluginEntry } from './PluginEntry.js'
20
+ import { PluginState } from './PluginState.js'
21
+ import {
22
+ PluginNotFoundError,
23
+ PluginDuplicateError,
24
+ PluginDependencyError,
25
+ PluginStateError,
26
+ PluginError
27
+ } from '../../errors/PluginError.js'
28
+
29
+ class PluginSystem extends Subsystem {
30
+ /**
31
+ * 构造函数
32
+ * @param {import('../EventBus/EventBus.js').EventBus} eventBus - 全局事件总线
33
+ * @param {import('../ConfigSystem/ConfigSystem.js').ConfigSystem} config - 配置系统
34
+ * @param {import('../Logger/Logger.js').Logger} logger - 日志系统
35
+ * @param {object} app - Application 实例(传给 plugin.install)
36
+ */
37
+ constructor(eventBus, config, logger, app) {
38
+ super(eventBus, config, logger)
39
+
40
+ /** @type {object} Application 实例 */
41
+ this._app = app
42
+
43
+ /** @type {Map<string, PluginEntry>} 插件映射(name → entry) */
44
+ this._entries = new Map()
45
+
46
+ /**
47
+ * 钩子监听器映射(三期新增)
48
+ * hookName → Set<Function>,支持外部订阅插件生命周期钩子
49
+ * @type {Map<string, Set<Function>>}
50
+ */
51
+ this._hookListeners = null
52
+ }
53
+
54
+ // --------------------------------------------------------------------------
55
+ // 插件管理
56
+ // --------------------------------------------------------------------------
57
+
58
+ /**
59
+ * 注册插件
60
+ * 如果 PluginSystem 已初始化,则自动安装并等待安装完成
61
+ * @param {Plugin} plugin - 插件实例
62
+ * @param {Object} [options={}] - 插件配置
63
+ * @returns {Promise<PluginSystem>} - 返回 Promise 支持异步等待安装完成
64
+ * @throws {PluginDuplicateError} 插件重复注册
65
+ */
66
+ async register(plugin, options = {}) {
67
+ // 检查是否为 Plugin 实例
68
+ if (!Plugin.isPlugin(plugin)) {
69
+ throw new Error('插件必须继承 Plugin 类')
70
+ }
71
+
72
+ const name = plugin.name
73
+
74
+ // 检查重复
75
+ if (this._entries.has(name)) {
76
+ throw new PluginDuplicateError(name)
77
+ }
78
+
79
+ // 创建条目并存储
80
+ const entry = new PluginEntry(plugin, options)
81
+ this._entries.set(name, entry)
82
+
83
+ this.emit('plugin:registered', { name, plugin })
84
+
85
+ // 如果 PluginSystem 已初始化(应用已启动),等待安装完成
86
+ if (this._isInitialized) {
87
+ await this.install(name)
88
+ }
89
+
90
+ return this
91
+ }
92
+
93
+ /**
94
+ * 注销插件(已安装则先卸载)
95
+ * @param {string} name - 插件名称
96
+ * @returns {Promise<void>}
97
+ */
98
+ async unregister(name) {
99
+ const entry = this._getEntryOrThrow(name)
100
+
101
+ // 已安装则先卸载
102
+ if (entry.state === PluginState.INSTALLED) {
103
+ await this.uninstall(name)
104
+ }
105
+
106
+ // 设置为已注销
107
+ entry.setState(PluginState.UNREGISTERED)
108
+
109
+ // 从映射移除
110
+ this._entries.delete(name)
111
+
112
+ this.emit('plugin:unregistered', { name })
113
+ }
114
+
115
+ /**
116
+ * 安装单个插件
117
+ * 执行流程:beforeInstall 钩子 → 安装逻辑 → afterInstall 钩子
118
+ * @param {string} name - 插件名称
119
+ * @returns {Promise<void>}
120
+ */
121
+ async install(name) {
122
+ const entry = this._getEntryOrThrow(name)
123
+
124
+ // 状态检查
125
+ if (entry.state !== PluginState.REGISTERED) {
126
+ throw new PluginStateError(name, entry.state, PluginState.REGISTERED)
127
+ }
128
+
129
+ // 检查依赖是否已安装
130
+ for (const dep of entry.dependencies) {
131
+ const depEntry = this._entries.get(dep)
132
+ if (!depEntry || depEntry.state !== PluginState.INSTALLED) {
133
+ throw new PluginDependencyError(name, `依赖插件 ${dep} 未安装`)
134
+ }
135
+ }
136
+
137
+ // 1. 执行 beforeInstall 钩子(在状态变更前)
138
+ await this._executeHook('beforeInstall', {
139
+ name: entry.name,
140
+ plugin: entry.plugin,
141
+ options: entry.options
142
+ })
143
+
144
+ // 2. 设置为安装中
145
+ entry.setState(PluginState.INSTALLING)
146
+ this.emit('plugin:installing', { name: entry.name, plugin: entry.plugin })
147
+
148
+ try {
149
+ // 调用插件的 install 方法
150
+ await entry.plugin.install(this._app, entry.options)
151
+
152
+ // 标记为已安装
153
+ entry.markInstalled()
154
+
155
+ this.emit('plugin:installed', { name: entry.name, plugin: entry.plugin })
156
+ } catch (e) {
157
+ // 安装失败设为 ERROR 状态
158
+ entry.setState(PluginState.ERROR)
159
+ this.emit('plugin:error', { name: entry.name, error: e })
160
+ throw e
161
+ }
162
+
163
+ // 3. 执行 afterInstall 钩子(安装成功后)
164
+ await this._executeHook('afterInstall', {
165
+ name: entry.name,
166
+ plugin: entry.plugin,
167
+ options: entry.options
168
+ })
169
+ }
170
+
171
+ /**
172
+ * 卸载单个插件
173
+ * 执行流程:beforeUninstall 钩子 → 卸载逻辑 → afterUninstall 钩子
174
+ * @param {string} name - 插件名称
175
+ * @returns {Promise<void>}
176
+ */
177
+ async uninstall(name) {
178
+ const entry = this._getEntryOrThrow(name)
179
+
180
+ // 状态检查
181
+ if (entry.state !== PluginState.INSTALLED) {
182
+ throw new PluginStateError(name, entry.state, PluginState.INSTALLED)
183
+ }
184
+
185
+ // 1. 执行 beforeUninstall 钩子(在状态变更前)
186
+ // 传递完整 context(包含 app),供钩子方法访问应用实例
187
+ await this._executeHook('beforeUninstall', {
188
+ name: entry.name,
189
+ plugin: entry.plugin,
190
+ app: this._app
191
+ })
192
+
193
+ // 2. 设置为卸载中
194
+ entry.setState(PluginState.UNINSTALLING)
195
+ this.emit('plugin:uninstalling', { name: entry.name, plugin: entry.plugin })
196
+
197
+ try {
198
+ // 调用插件的 uninstall 方法
199
+ await entry.plugin.uninstall(this._app)
200
+
201
+ // 设置为已注册(可重新安装),通过公共方法重置安装时间戳
202
+ entry.setState(PluginState.REGISTERED)
203
+ entry.resetInstallTime()
204
+
205
+ this.emit('plugin:uninstalled', { name: entry.name, plugin: entry.plugin })
206
+ } catch (e) {
207
+ // 卸载失败设为 ERROR 状态
208
+ entry.setState(PluginState.ERROR)
209
+ this.emit('plugin:error', { name: entry.name, error: e })
210
+ throw e
211
+ }
212
+
213
+ // 3. 执行 afterUninstall 钩子(卸载成功后)
214
+ // 传递完整 context(包含 app),供钩子方法访问应用实例
215
+ await this._executeHook('afterUninstall', {
216
+ name: entry.name,
217
+ plugin: entry.plugin,
218
+ app: this._app
219
+ })
220
+ }
221
+
222
+ // --------------------------------------------------------------------------
223
+ // 查询方法
224
+ // --------------------------------------------------------------------------
225
+
226
+ /**
227
+ * 获取插件实例
228
+ * @param {string} name - 插件名称
229
+ * @returns {Plugin|null}
230
+ */
231
+ get(name) {
232
+ const entry = this._entries.get(name)
233
+ return entry ? entry.plugin : null
234
+ }
235
+
236
+ /**
237
+ * 是否已注册
238
+ * @param {string} name - 插件名称
239
+ * @returns {boolean}
240
+ */
241
+ has(name) {
242
+ return this._entries.has(name)
243
+ }
244
+
245
+ /**
246
+ * 是否已安装
247
+ * @param {string} name - 插件名称
248
+ * @returns {boolean}
249
+ */
250
+ isInstalled(name) {
251
+ const entry = this._entries.get(name)
252
+ return entry ? entry.state === PluginState.INSTALLED : false
253
+ }
254
+
255
+ /**
256
+ * 列出所有插件名称
257
+ * @returns {string[]}
258
+ */
259
+ list() {
260
+ return [...this._entries.keys()]
261
+ }
262
+
263
+ /**
264
+ * 列出已安装插件名称
265
+ * @returns {string[]}
266
+ */
267
+ listInstalled() {
268
+ const result = []
269
+ for (const [name, entry] of this._entries) {
270
+ if (entry.state === PluginState.INSTALLED) {
271
+ result.push(name)
272
+ }
273
+ }
274
+ return result
275
+ }
276
+
277
+ // --------------------------------------------------------------------------
278
+ // 钩子(三期新增)
279
+ // --------------------------------------------------------------------------
280
+
281
+ /**
282
+ * 订阅插件生命周期钩子
283
+ * 钩子执行时,onHook 订阅者会在插件定义的钩子方法和事件广播之后被调用
284
+ *
285
+ * @param {string} hookName - 钩子名称
286
+ * 可选值:'beforeInstall'/'afterInstall'/'beforeUninstall'/'afterUninstall'
287
+ * @param {Function} callback - 回调函数 ({ name, plugin, options? }) => void
288
+ * @returns {Function} - 取消订阅函数
289
+ * @throws {PluginError} 无效的钩子名称或 callback 不是函数
290
+ */
291
+ onHook(hookName, callback) {
292
+ // 已销毁检查
293
+ if (this.isDestroyed) return () => {}
294
+
295
+ // 未初始化检查(_hookListeners 在 initialize() 中创建)
296
+ if (!this._hookListeners) {
297
+ console.warn('[PluginSystem] onHook() 在初始化前调用,已忽略')
298
+ return () => {}
299
+ }
300
+
301
+ // 参数校验
302
+ const validHooks = ['beforeInstall', 'afterInstall', 'beforeUninstall', 'afterUninstall']
303
+ if (!validHooks.includes(hookName)) {
304
+ throw new PluginError(`无效的钩子名称: '${hookName}',可选值: ${validHooks.join(', ')}`)
305
+ }
306
+ if (typeof callback !== 'function') {
307
+ throw new PluginError('callback 必须是函数')
308
+ }
309
+
310
+ if (!this._hookListeners.has(hookName)) {
311
+ this._hookListeners.set(hookName, new Set())
312
+ }
313
+ this._hookListeners.get(hookName).add(callback)
314
+
315
+ // 返回取消订阅函数
316
+ return () => {
317
+ const listeners = this._hookListeners.get(hookName)
318
+ if (listeners) {
319
+ listeners.delete(callback)
320
+ }
321
+ }
322
+ }
323
+
324
+ // --------------------------------------------------------------------------
325
+ // 生命周期(继承自 Subsystem)
326
+ // --------------------------------------------------------------------------
327
+
328
+ /**
329
+ * 初始化:拓扑排序后按顺序安装所有 REGISTERED 插件
330
+ * @returns {Promise<void>}
331
+ */
332
+ async initialize() {
333
+ await super.initialize()
334
+
335
+ // 初始化钩子监听器映射
336
+ this._hookListeners = new Map()
337
+
338
+ // 拓扑排序
339
+ const sorted = this._topologicalSort()
340
+
341
+ // 按排序顺序安装所有 REGISTERED 插件
342
+ for (const name of sorted) {
343
+ const entry = this._entries.get(name)
344
+ if (entry && entry.state === PluginState.REGISTERED) {
345
+ try {
346
+ await this.install(name)
347
+ } catch (e) {
348
+ // 单个插件安装失败不影响其他插件
349
+ this._safeLog('error', `插件 ${name} 安装失败`, { error: e })
350
+ }
351
+ }
352
+ }
353
+ }
354
+
355
+ /**
356
+ * 调用所有已安装插件的 update
357
+ * @param {number} delta - 帧间隔(秒)
358
+ */
359
+ update(delta) {
360
+ for (const [name, entry] of this._entries) {
361
+ if (entry.state === PluginState.INSTALLED) {
362
+ try {
363
+ entry.plugin.update(delta, this._app)
364
+ } catch (e) {
365
+ this.emit('plugin:error', { name, error: e })
366
+ }
367
+ }
368
+ }
369
+ }
370
+
371
+ /**
372
+ * 反向卸载所有已安装插件,清理钩子监听器
373
+ * @returns {Promise<void>}
374
+ */
375
+ async destroy() {
376
+ if (this._isDestroyed) return
377
+
378
+ // 反向卸载所有已安装插件
379
+ const installedNames = this.listInstalled().reverse()
380
+ for (const name of installedNames) {
381
+ try {
382
+ await this.uninstall(name)
383
+ } catch (e) {
384
+ // 销毁阶段错误不中断
385
+ this._safeLog('error', `插件 ${name} 卸载失败`, { error: e })
386
+ }
387
+ }
388
+
389
+ // 清理钩子监听器
390
+ if (this._hookListeners) {
391
+ for (const listeners of this._hookListeners.values()) {
392
+ listeners.clear()
393
+ }
394
+ this._hookListeners.clear()
395
+ }
396
+ this._hookListeners = null
397
+
398
+ this._entries.clear()
399
+ this._app = null
400
+
401
+ await super.destroy()
402
+ }
403
+
404
+ // --------------------------------------------------------------------------
405
+ // 私有方法
406
+ // --------------------------------------------------------------------------
407
+
408
+ /**
409
+ * 拓扑排序
410
+ * @returns {string[]} 安装顺序
411
+ * @throws {PluginDependencyError} 检测到循环依赖
412
+ * @private
413
+ */
414
+ _topologicalSort() {
415
+ const sorted = []
416
+ const visited = new Set()
417
+ const visiting = new Set()
418
+
419
+ const visit = (name) => {
420
+ if (visited.has(name)) return
421
+ if (visiting.has(name)) {
422
+ throw new PluginDependencyError(name, `检测到循环依赖:${name}`)
423
+ }
424
+ visiting.add(name)
425
+
426
+ const entry = this._entries.get(name)
427
+ if (!entry) {
428
+ throw new PluginNotFoundError(name)
429
+ }
430
+
431
+ // 先安装依赖
432
+ const deps = entry.dependencies || []
433
+ for (const dep of deps) {
434
+ visit(dep)
435
+ }
436
+
437
+ visiting.delete(name)
438
+ visited.add(name)
439
+ sorted.push(name)
440
+ }
441
+
442
+ for (const name of this._entries.keys()) {
443
+ visit(name)
444
+ }
445
+
446
+ return sorted
447
+ }
448
+
449
+ /**
450
+ * 获取插件条目,不存在则抛错
451
+ * @param {string} name - 插件名称
452
+ * @returns {PluginEntry}
453
+ * @throws {PluginNotFoundError}
454
+ * @private
455
+ */
456
+ _getEntryOrThrow(name) {
457
+ const entry = this._entries.get(name)
458
+ if (!entry) {
459
+ throw new PluginNotFoundError(name)
460
+ }
461
+ return entry
462
+ }
463
+
464
+ /**
465
+ * 防御性日志方法
466
+ * @param {string} level - 日志级别
467
+ * @param {string} message - 日志消息
468
+ * @param {Object} [context={}] - 上下文
469
+ * @private
470
+ */
471
+ _safeLog(level, message, context = {}) {
472
+ try {
473
+ if (this._logger && !this._logger.isDestroyed) {
474
+ this._logger[level](message, context)
475
+ }
476
+ } catch (e) {
477
+ // 完全忽略日志错误
478
+ }
479
+ }
480
+
481
+ /**
482
+ * 执行钩子(内部方法,三期新增)
483
+ * 执行流程:
484
+ * 1. 调用插件定义的钩子方法(如 plugin.onBeforeInstall)
485
+ * 2. 通过 EventBus 广播事件(如 plugin:beforeInstall)
486
+ * 3. 调用 onHook 订阅者回调
487
+ *
488
+ * @param {string} hookName - 钩子名称(如 'beforeInstall')
489
+ * @param {Object} context - 钩子上下文 { name, plugin, options? }
490
+ * @returns {Promise<void>}
491
+ * @private
492
+ */
493
+ async _executeHook(hookName, context) {
494
+ // 1. 调用插件定义的钩子方法
495
+ // 将 hookName 转为方法名:'beforeInstall' → 'onBeforeInstall'
496
+ const methodName = 'on' + hookName.charAt(0).toUpperCase() + hookName.slice(1)
497
+ if (typeof context.plugin[methodName] === 'function') {
498
+ try {
499
+ // 安装钩子(beforeInstall/afterInstall)传递 options 参数(向后兼容)
500
+ // 卸载钩子(beforeUninstall/afterUninstall)传递完整 context(含 app/name/plugin)
501
+ const isInstallHook = hookName === 'beforeInstall' || hookName === 'afterInstall'
502
+ const arg = isInstallHook ? context.options : context
503
+ await context.plugin[methodName](arg)
504
+ } catch (e) {
505
+ // 钩子异常仅记录日志,不中断安装/卸载流程
506
+ this._safeLog('error', `插件 '${context.name}' 的 ${methodName} 钩子执行失败`, { error: e })
507
+ }
508
+ }
509
+
510
+ // 2. 通过 EventBus 广播事件
511
+ this._eventBus.emit(`plugin:${hookName}`, context)
512
+
513
+ // 3. 调用 onHook 订阅者
514
+ if (this._hookListeners) {
515
+ const listeners = this._hookListeners.get(hookName)
516
+ if (listeners) {
517
+ for (const callback of listeners) {
518
+ try {
519
+ callback(context)
520
+ } catch (e) {
521
+ // 订阅者异常仅记录日志,不中断其他订阅者
522
+ this._safeLog('error', `钩子 '${hookName}' 的订阅者执行失败`, { error: e })
523
+ }
524
+ }
525
+ }
526
+ }
527
+ }
528
+ }
529
+
530
+ export { PluginSystem }
@@ -0,0 +1,8 @@
1
+ // ============================================================================
2
+ // Nimbus2D - PluginSystem 模块统一导出
3
+ // ============================================================================
4
+
5
+ export { PluginSystem } from './PluginSystem.js'
6
+ export { Plugin } from './Plugin.js'
7
+ export { PluginEntry } from './PluginEntry.js'
8
+ export { PluginState } from './PluginState.js'
@@ -0,0 +1,19 @@
1
+ // ============================================================================
2
+ // Nimbus2D - 对象池默认配置
3
+ // ----------------------------------------------------------------------------
4
+ // PoolManager 的默认配置,写入 ConfigSystem 的 DEFAULT 层。
5
+ // 各池的具体配置由插件通过 ConfigSystem.loadModule() 注册到 MODULE 层。
6
+ // ============================================================================
7
+
8
+ /**
9
+ * 对象池默认配置
10
+ * @type {Object}
11
+ */
12
+ const PoolDefaultConfig = {
13
+ /** 对象池管理器配置 */
14
+ poolManager: {
15
+ // 默认无配置,各池的配置由插件自己的 loadModule 注册
16
+ }
17
+ }
18
+
19
+ export { PoolDefaultConfig }