@esengine/timer 1.0.0
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 +21 -0
- package/dist/index.d.ts +459 -0
- package/dist/index.js +762 -0
- package/dist/index.js.map +1 -0
- package/module.json +23 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ESEngine Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import * as _esengine_ecs_framework from '@esengine/ecs-framework';
|
|
2
|
+
import { BlueprintNodeTemplate, INodeExecutor, BlueprintNode, ExecutionResult } from '@esengine/blueprint';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @zh 定时器服务接口
|
|
6
|
+
* @en Timer Service Interfaces
|
|
7
|
+
*
|
|
8
|
+
* @zh 提供定时器和冷却系统的核心接口
|
|
9
|
+
* @en Provides core interfaces for timer and cooldown systems
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* @zh 定时器句柄,用于取消定时器
|
|
13
|
+
* @en Timer handle for cancelling timers
|
|
14
|
+
*/
|
|
15
|
+
interface TimerHandle {
|
|
16
|
+
/**
|
|
17
|
+
* @zh 定时器 ID
|
|
18
|
+
* @en Timer ID
|
|
19
|
+
*/
|
|
20
|
+
readonly id: string;
|
|
21
|
+
/**
|
|
22
|
+
* @zh 是否有效(未被取消)
|
|
23
|
+
* @en Whether the timer is still valid (not cancelled)
|
|
24
|
+
*/
|
|
25
|
+
readonly isValid: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* @zh 取消定时器
|
|
28
|
+
* @en Cancel the timer
|
|
29
|
+
*/
|
|
30
|
+
cancel(): void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* @zh 定时器信息
|
|
34
|
+
* @en Timer information
|
|
35
|
+
*/
|
|
36
|
+
interface TimerInfo {
|
|
37
|
+
/**
|
|
38
|
+
* @zh 定时器 ID
|
|
39
|
+
* @en Timer ID
|
|
40
|
+
*/
|
|
41
|
+
readonly id: string;
|
|
42
|
+
/**
|
|
43
|
+
* @zh 剩余时间(毫秒)
|
|
44
|
+
* @en Remaining time in milliseconds
|
|
45
|
+
*/
|
|
46
|
+
readonly remaining: number;
|
|
47
|
+
/**
|
|
48
|
+
* @zh 是否重复执行
|
|
49
|
+
* @en Whether the timer repeats
|
|
50
|
+
*/
|
|
51
|
+
readonly repeating: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* @zh 间隔时间(毫秒,仅重复定时器)
|
|
54
|
+
* @en Interval in milliseconds (only for repeating timers)
|
|
55
|
+
*/
|
|
56
|
+
readonly interval?: number;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* @zh 冷却信息
|
|
60
|
+
* @en Cooldown information
|
|
61
|
+
*/
|
|
62
|
+
interface CooldownInfo {
|
|
63
|
+
/**
|
|
64
|
+
* @zh 冷却 ID
|
|
65
|
+
* @en Cooldown ID
|
|
66
|
+
*/
|
|
67
|
+
readonly id: string;
|
|
68
|
+
/**
|
|
69
|
+
* @zh 总持续时间(毫秒)
|
|
70
|
+
* @en Total duration in milliseconds
|
|
71
|
+
*/
|
|
72
|
+
readonly duration: number;
|
|
73
|
+
/**
|
|
74
|
+
* @zh 剩余时间(毫秒)
|
|
75
|
+
* @en Remaining time in milliseconds
|
|
76
|
+
*/
|
|
77
|
+
readonly remaining: number;
|
|
78
|
+
/**
|
|
79
|
+
* @zh 进度(0-1,0 表示刚开始,1 表示结束)
|
|
80
|
+
* @en Progress from 0 to 1 (0 = just started, 1 = finished)
|
|
81
|
+
*/
|
|
82
|
+
readonly progress: number;
|
|
83
|
+
/**
|
|
84
|
+
* @zh 是否已就绪(冷却完成)
|
|
85
|
+
* @en Whether the cooldown is ready (finished)
|
|
86
|
+
*/
|
|
87
|
+
readonly isReady: boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* @zh 定时器回调函数
|
|
91
|
+
* @en Timer callback function
|
|
92
|
+
*/
|
|
93
|
+
type TimerCallback = () => void;
|
|
94
|
+
/**
|
|
95
|
+
* @zh 带时间参数的定时器回调
|
|
96
|
+
* @en Timer callback with time parameter
|
|
97
|
+
*/
|
|
98
|
+
type TimerCallbackWithTime = (deltaTime: number) => void;
|
|
99
|
+
/**
|
|
100
|
+
* @zh 定时器服务接口
|
|
101
|
+
* @en Timer service interface
|
|
102
|
+
*
|
|
103
|
+
* @zh 提供定时器调度和冷却管理功能
|
|
104
|
+
* @en Provides timer scheduling and cooldown management
|
|
105
|
+
*/
|
|
106
|
+
interface ITimerService {
|
|
107
|
+
/**
|
|
108
|
+
* @zh 调度一次性定时器
|
|
109
|
+
* @en Schedule a one-time timer
|
|
110
|
+
*
|
|
111
|
+
* @param id - @zh 定时器标识 @en Timer identifier
|
|
112
|
+
* @param delay - @zh 延迟时间(毫秒)@en Delay in milliseconds
|
|
113
|
+
* @param callback - @zh 回调函数 @en Callback function
|
|
114
|
+
* @returns @zh 定时器句柄 @en Timer handle
|
|
115
|
+
*/
|
|
116
|
+
schedule(id: string, delay: number, callback: TimerCallback): TimerHandle;
|
|
117
|
+
/**
|
|
118
|
+
* @zh 调度重复定时器
|
|
119
|
+
* @en Schedule a repeating timer
|
|
120
|
+
*
|
|
121
|
+
* @param id - @zh 定时器标识 @en Timer identifier
|
|
122
|
+
* @param interval - @zh 间隔时间(毫秒)@en Interval in milliseconds
|
|
123
|
+
* @param callback - @zh 回调函数 @en Callback function
|
|
124
|
+
* @param immediate - @zh 是否立即执行一次 @en Whether to execute immediately
|
|
125
|
+
* @returns @zh 定时器句柄 @en Timer handle
|
|
126
|
+
*/
|
|
127
|
+
scheduleRepeating(id: string, interval: number, callback: TimerCallback, immediate?: boolean): TimerHandle;
|
|
128
|
+
/**
|
|
129
|
+
* @zh 取消定时器
|
|
130
|
+
* @en Cancel a timer
|
|
131
|
+
*
|
|
132
|
+
* @param handle - @zh 定时器句柄 @en Timer handle
|
|
133
|
+
*/
|
|
134
|
+
cancel(handle: TimerHandle): void;
|
|
135
|
+
/**
|
|
136
|
+
* @zh 通过 ID 取消定时器
|
|
137
|
+
* @en Cancel timer by ID
|
|
138
|
+
*
|
|
139
|
+
* @param id - @zh 定时器标识 @en Timer identifier
|
|
140
|
+
*/
|
|
141
|
+
cancelById(id: string): void;
|
|
142
|
+
/**
|
|
143
|
+
* @zh 检查定时器是否存在
|
|
144
|
+
* @en Check if a timer exists
|
|
145
|
+
*
|
|
146
|
+
* @param id - @zh 定时器标识 @en Timer identifier
|
|
147
|
+
* @returns @zh 是否存在 @en Whether the timer exists
|
|
148
|
+
*/
|
|
149
|
+
hasTimer(id: string): boolean;
|
|
150
|
+
/**
|
|
151
|
+
* @zh 获取定时器信息
|
|
152
|
+
* @en Get timer information
|
|
153
|
+
*
|
|
154
|
+
* @param id - @zh 定时器标识 @en Timer identifier
|
|
155
|
+
* @returns @zh 定时器信息或 null @en Timer info or null
|
|
156
|
+
*/
|
|
157
|
+
getTimerInfo(id: string): TimerInfo | null;
|
|
158
|
+
/**
|
|
159
|
+
* @zh 开始冷却
|
|
160
|
+
* @en Start a cooldown
|
|
161
|
+
*
|
|
162
|
+
* @param id - @zh 冷却标识 @en Cooldown identifier
|
|
163
|
+
* @param duration - @zh 持续时间(毫秒)@en Duration in milliseconds
|
|
164
|
+
*/
|
|
165
|
+
startCooldown(id: string, duration: number): void;
|
|
166
|
+
/**
|
|
167
|
+
* @zh 检查是否在冷却中
|
|
168
|
+
* @en Check if on cooldown
|
|
169
|
+
*
|
|
170
|
+
* @param id - @zh 冷却标识 @en Cooldown identifier
|
|
171
|
+
* @returns @zh 是否在冷却中 @en Whether on cooldown
|
|
172
|
+
*/
|
|
173
|
+
isOnCooldown(id: string): boolean;
|
|
174
|
+
/**
|
|
175
|
+
* @zh 检查冷却是否就绪
|
|
176
|
+
* @en Check if cooldown is ready
|
|
177
|
+
*
|
|
178
|
+
* @param id - @zh 冷却标识 @en Cooldown identifier
|
|
179
|
+
* @returns @zh 是否已就绪 @en Whether ready
|
|
180
|
+
*/
|
|
181
|
+
isCooldownReady(id: string): boolean;
|
|
182
|
+
/**
|
|
183
|
+
* @zh 获取剩余冷却时间
|
|
184
|
+
* @en Get remaining cooldown time
|
|
185
|
+
*
|
|
186
|
+
* @param id - @zh 冷却标识 @en Cooldown identifier
|
|
187
|
+
* @returns @zh 剩余时间(毫秒),0 表示无冷却 @en Remaining time in ms, 0 if no cooldown
|
|
188
|
+
*/
|
|
189
|
+
getCooldownRemaining(id: string): number;
|
|
190
|
+
/**
|
|
191
|
+
* @zh 获取冷却进度
|
|
192
|
+
* @en Get cooldown progress
|
|
193
|
+
*
|
|
194
|
+
* @param id - @zh 冷却标识 @en Cooldown identifier
|
|
195
|
+
* @returns @zh 进度(0-1),1 表示完成或无冷却 @en Progress 0-1, 1 if done or no cooldown
|
|
196
|
+
*/
|
|
197
|
+
getCooldownProgress(id: string): number;
|
|
198
|
+
/**
|
|
199
|
+
* @zh 获取冷却信息
|
|
200
|
+
* @en Get cooldown information
|
|
201
|
+
*
|
|
202
|
+
* @param id - @zh 冷却标识 @en Cooldown identifier
|
|
203
|
+
* @returns @zh 冷却信息或 null @en Cooldown info or null
|
|
204
|
+
*/
|
|
205
|
+
getCooldownInfo(id: string): CooldownInfo | null;
|
|
206
|
+
/**
|
|
207
|
+
* @zh 重置冷却
|
|
208
|
+
* @en Reset a cooldown
|
|
209
|
+
*
|
|
210
|
+
* @param id - @zh 冷却标识 @en Cooldown identifier
|
|
211
|
+
*/
|
|
212
|
+
resetCooldown(id: string): void;
|
|
213
|
+
/**
|
|
214
|
+
* @zh 清除所有冷却
|
|
215
|
+
* @en Clear all cooldowns
|
|
216
|
+
*/
|
|
217
|
+
clearAllCooldowns(): void;
|
|
218
|
+
/**
|
|
219
|
+
* @zh 更新定时器服务
|
|
220
|
+
* @en Update timer service
|
|
221
|
+
*
|
|
222
|
+
* @param deltaTime - @zh 距上次更新的时间(毫秒)@en Time since last update in ms
|
|
223
|
+
*/
|
|
224
|
+
update(deltaTime: number): void;
|
|
225
|
+
/**
|
|
226
|
+
* @zh 清除所有定时器和冷却
|
|
227
|
+
* @en Clear all timers and cooldowns
|
|
228
|
+
*/
|
|
229
|
+
clear(): void;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @zh 定时器服务实现
|
|
234
|
+
* @en Timer Service Implementation
|
|
235
|
+
*
|
|
236
|
+
* @zh 提供定时器调度和冷却管理的默认实现
|
|
237
|
+
* @en Provides default implementation for timer scheduling and cooldown management
|
|
238
|
+
*/
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* @zh 定时器服务配置
|
|
242
|
+
* @en Timer service configuration
|
|
243
|
+
*/
|
|
244
|
+
interface TimerServiceConfig {
|
|
245
|
+
/**
|
|
246
|
+
* @zh 最大定时器数量(0 表示无限制)
|
|
247
|
+
* @en Maximum number of timers (0 for unlimited)
|
|
248
|
+
*/
|
|
249
|
+
maxTimers?: number;
|
|
250
|
+
/**
|
|
251
|
+
* @zh 最大冷却数量(0 表示无限制)
|
|
252
|
+
* @en Maximum number of cooldowns (0 for unlimited)
|
|
253
|
+
*/
|
|
254
|
+
maxCooldowns?: number;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* @zh 定时器服务实现
|
|
258
|
+
* @en Timer service implementation
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```typescript
|
|
262
|
+
* const timerService = new TimerService();
|
|
263
|
+
*
|
|
264
|
+
* // 一次性定时器 | One-time timer
|
|
265
|
+
* const handle = timerService.schedule('myTimer', 1000, () => {
|
|
266
|
+
* console.log('Timer fired!');
|
|
267
|
+
* });
|
|
268
|
+
*
|
|
269
|
+
* // 重复定时器 | Repeating timer
|
|
270
|
+
* timerService.scheduleRepeating('heartbeat', 100, () => {
|
|
271
|
+
* console.log('Tick');
|
|
272
|
+
* });
|
|
273
|
+
*
|
|
274
|
+
* // 冷却系统 | Cooldown system
|
|
275
|
+
* timerService.startCooldown('skill_fireball', 5000);
|
|
276
|
+
* if (timerService.isCooldownReady('skill_fireball')) {
|
|
277
|
+
* // 可以使用技能 | Can use skill
|
|
278
|
+
* }
|
|
279
|
+
*
|
|
280
|
+
* // 每帧更新 | Update each frame
|
|
281
|
+
* timerService.update(deltaTime);
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
declare class TimerService implements ITimerService {
|
|
285
|
+
private timers;
|
|
286
|
+
private cooldowns;
|
|
287
|
+
private config;
|
|
288
|
+
constructor(config?: TimerServiceConfig);
|
|
289
|
+
schedule(id: string, delay: number, callback: TimerCallback): TimerHandle;
|
|
290
|
+
scheduleRepeating(id: string, interval: number, callback: TimerCallback, immediate?: boolean): TimerHandle;
|
|
291
|
+
cancel(handle: TimerHandle): void;
|
|
292
|
+
cancelById(id: string): void;
|
|
293
|
+
hasTimer(id: string): boolean;
|
|
294
|
+
getTimerInfo(id: string): TimerInfo | null;
|
|
295
|
+
startCooldown(id: string, duration: number): void;
|
|
296
|
+
isOnCooldown(id: string): boolean;
|
|
297
|
+
isCooldownReady(id: string): boolean;
|
|
298
|
+
getCooldownRemaining(id: string): number;
|
|
299
|
+
getCooldownProgress(id: string): number;
|
|
300
|
+
getCooldownInfo(id: string): CooldownInfo | null;
|
|
301
|
+
resetCooldown(id: string): void;
|
|
302
|
+
clearAllCooldowns(): void;
|
|
303
|
+
update(deltaTime: number): void;
|
|
304
|
+
private updateTimers;
|
|
305
|
+
private updateCooldowns;
|
|
306
|
+
clear(): void;
|
|
307
|
+
/**
|
|
308
|
+
* @zh 获取活跃定时器数量
|
|
309
|
+
* @en Get active timer count
|
|
310
|
+
*/
|
|
311
|
+
get activeTimerCount(): number;
|
|
312
|
+
/**
|
|
313
|
+
* @zh 获取活跃冷却数量
|
|
314
|
+
* @en Get active cooldown count
|
|
315
|
+
*/
|
|
316
|
+
get activeCooldownCount(): number;
|
|
317
|
+
/**
|
|
318
|
+
* @zh 获取所有活跃定时器 ID
|
|
319
|
+
* @en Get all active timer IDs
|
|
320
|
+
*/
|
|
321
|
+
getActiveTimerIds(): string[];
|
|
322
|
+
/**
|
|
323
|
+
* @zh 获取所有活跃冷却 ID
|
|
324
|
+
* @en Get all active cooldown IDs
|
|
325
|
+
*/
|
|
326
|
+
getActiveCooldownIds(): string[];
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* @zh 创建定时器服务
|
|
330
|
+
* @en Create timer service
|
|
331
|
+
*
|
|
332
|
+
* @param config - @zh 配置选项 @en Configuration options
|
|
333
|
+
* @returns @zh 定时器服务实例 @en Timer service instance
|
|
334
|
+
*/
|
|
335
|
+
declare function createTimerService(config?: TimerServiceConfig): ITimerService;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* @zh 定时器服务令牌
|
|
339
|
+
* @en Timer service token
|
|
340
|
+
*
|
|
341
|
+
* @zh 用于注入定时器服务
|
|
342
|
+
* @en Used for injecting timer service
|
|
343
|
+
*/
|
|
344
|
+
declare const TimerServiceToken: _esengine_ecs_framework.ServiceToken<ITimerService>;
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* @zh 定时器蓝图节点
|
|
348
|
+
* @en Timer Blueprint Nodes
|
|
349
|
+
*
|
|
350
|
+
* @zh 提供定时器和冷却功能的蓝图节点
|
|
351
|
+
* @en Provides blueprint nodes for timer and cooldown functionality
|
|
352
|
+
*/
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* @zh StartCooldown 节点模板
|
|
356
|
+
* @en StartCooldown node template
|
|
357
|
+
*/
|
|
358
|
+
declare const StartCooldownTemplate: BlueprintNodeTemplate;
|
|
359
|
+
/**
|
|
360
|
+
* @zh StartCooldown 节点执行器
|
|
361
|
+
* @en StartCooldown node executor
|
|
362
|
+
*/
|
|
363
|
+
declare class StartCooldownExecutor implements INodeExecutor {
|
|
364
|
+
execute(node: BlueprintNode, context: unknown): ExecutionResult;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* @zh IsCooldownReady 节点模板
|
|
368
|
+
* @en IsCooldownReady node template
|
|
369
|
+
*/
|
|
370
|
+
declare const IsCooldownReadyTemplate: BlueprintNodeTemplate;
|
|
371
|
+
/**
|
|
372
|
+
* @zh IsCooldownReady 节点执行器
|
|
373
|
+
* @en IsCooldownReady node executor
|
|
374
|
+
*/
|
|
375
|
+
declare class IsCooldownReadyExecutor implements INodeExecutor {
|
|
376
|
+
execute(node: BlueprintNode, context: unknown): ExecutionResult;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* @zh GetCooldownProgress 节点模板
|
|
380
|
+
* @en GetCooldownProgress node template
|
|
381
|
+
*/
|
|
382
|
+
declare const GetCooldownProgressTemplate: BlueprintNodeTemplate;
|
|
383
|
+
/**
|
|
384
|
+
* @zh GetCooldownProgress 节点执行器
|
|
385
|
+
* @en GetCooldownProgress node executor
|
|
386
|
+
*/
|
|
387
|
+
declare class GetCooldownProgressExecutor implements INodeExecutor {
|
|
388
|
+
execute(node: BlueprintNode, context: unknown): ExecutionResult;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* @zh ResetCooldown 节点模板
|
|
392
|
+
* @en ResetCooldown node template
|
|
393
|
+
*/
|
|
394
|
+
declare const ResetCooldownTemplate: BlueprintNodeTemplate;
|
|
395
|
+
/**
|
|
396
|
+
* @zh ResetCooldown 节点执行器
|
|
397
|
+
* @en ResetCooldown node executor
|
|
398
|
+
*/
|
|
399
|
+
declare class ResetCooldownExecutor implements INodeExecutor {
|
|
400
|
+
execute(node: BlueprintNode, context: unknown): ExecutionResult;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* @zh GetCooldownInfo 节点模板
|
|
404
|
+
* @en GetCooldownInfo node template
|
|
405
|
+
*/
|
|
406
|
+
declare const GetCooldownInfoTemplate: BlueprintNodeTemplate;
|
|
407
|
+
/**
|
|
408
|
+
* @zh GetCooldownInfo 节点执行器
|
|
409
|
+
* @en GetCooldownInfo node executor
|
|
410
|
+
*/
|
|
411
|
+
declare class GetCooldownInfoExecutor implements INodeExecutor {
|
|
412
|
+
execute(node: BlueprintNode, context: unknown): ExecutionResult;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* @zh HasTimer 节点模板
|
|
416
|
+
* @en HasTimer node template
|
|
417
|
+
*/
|
|
418
|
+
declare const HasTimerTemplate: BlueprintNodeTemplate;
|
|
419
|
+
/**
|
|
420
|
+
* @zh HasTimer 节点执行器
|
|
421
|
+
* @en HasTimer node executor
|
|
422
|
+
*/
|
|
423
|
+
declare class HasTimerExecutor implements INodeExecutor {
|
|
424
|
+
execute(node: BlueprintNode, context: unknown): ExecutionResult;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* @zh CancelTimer 节点模板
|
|
428
|
+
* @en CancelTimer node template
|
|
429
|
+
*/
|
|
430
|
+
declare const CancelTimerTemplate: BlueprintNodeTemplate;
|
|
431
|
+
/**
|
|
432
|
+
* @zh CancelTimer 节点执行器
|
|
433
|
+
* @en CancelTimer node executor
|
|
434
|
+
*/
|
|
435
|
+
declare class CancelTimerExecutor implements INodeExecutor {
|
|
436
|
+
execute(node: BlueprintNode, context: unknown): ExecutionResult;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* @zh GetTimerRemaining 节点模板
|
|
440
|
+
* @en GetTimerRemaining node template
|
|
441
|
+
*/
|
|
442
|
+
declare const GetTimerRemainingTemplate: BlueprintNodeTemplate;
|
|
443
|
+
/**
|
|
444
|
+
* @zh GetTimerRemaining 节点执行器
|
|
445
|
+
* @en GetTimerRemaining node executor
|
|
446
|
+
*/
|
|
447
|
+
declare class GetTimerRemainingExecutor implements INodeExecutor {
|
|
448
|
+
execute(node: BlueprintNode, context: unknown): ExecutionResult;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* @zh 定时器节点定义
|
|
452
|
+
* @en Timer node definitions
|
|
453
|
+
*/
|
|
454
|
+
declare const TimerNodeDefinitions: {
|
|
455
|
+
template: BlueprintNodeTemplate;
|
|
456
|
+
executor: StartCooldownExecutor;
|
|
457
|
+
}[];
|
|
458
|
+
|
|
459
|
+
export { CancelTimerExecutor, CancelTimerTemplate, type CooldownInfo, GetCooldownInfoExecutor, GetCooldownInfoTemplate, GetCooldownProgressExecutor, GetCooldownProgressTemplate, GetTimerRemainingExecutor, GetTimerRemainingTemplate, HasTimerExecutor, HasTimerTemplate, type ITimerService, IsCooldownReadyExecutor, IsCooldownReadyTemplate, ResetCooldownExecutor, ResetCooldownTemplate, StartCooldownExecutor, StartCooldownTemplate, type TimerCallback, type TimerCallbackWithTime, type TimerHandle, type TimerInfo, TimerNodeDefinitions, TimerService, type TimerServiceConfig, TimerServiceToken, createTimerService };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,762 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
4
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
+
|
|
6
|
+
// src/TimerService.ts
|
|
7
|
+
var _a;
|
|
8
|
+
var TimerHandleImpl = (_a = class {
|
|
9
|
+
constructor(timer) {
|
|
10
|
+
__publicField(this, "timer");
|
|
11
|
+
this.timer = timer;
|
|
12
|
+
}
|
|
13
|
+
get id() {
|
|
14
|
+
return this.timer.id;
|
|
15
|
+
}
|
|
16
|
+
get isValid() {
|
|
17
|
+
return !this.timer.cancelled;
|
|
18
|
+
}
|
|
19
|
+
cancel() {
|
|
20
|
+
this.timer.cancelled = true;
|
|
21
|
+
}
|
|
22
|
+
}, __name(_a, "TimerHandleImpl"), _a);
|
|
23
|
+
var _TimerService = class _TimerService {
|
|
24
|
+
constructor(config = {}) {
|
|
25
|
+
__publicField(this, "timers", /* @__PURE__ */ new Map());
|
|
26
|
+
__publicField(this, "cooldowns", /* @__PURE__ */ new Map());
|
|
27
|
+
__publicField(this, "config");
|
|
28
|
+
this.config = {
|
|
29
|
+
maxTimers: config.maxTimers ?? 0,
|
|
30
|
+
maxCooldowns: config.maxCooldowns ?? 0
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// =========================================================================
|
|
34
|
+
// 定时器 API | Timer API
|
|
35
|
+
// =========================================================================
|
|
36
|
+
schedule(id, delay, callback) {
|
|
37
|
+
this.cancelById(id);
|
|
38
|
+
if (this.config.maxTimers > 0 && this.timers.size >= this.config.maxTimers) {
|
|
39
|
+
throw new Error(`Maximum timer limit reached: ${this.config.maxTimers}`);
|
|
40
|
+
}
|
|
41
|
+
const timer = {
|
|
42
|
+
id,
|
|
43
|
+
callback,
|
|
44
|
+
remaining: Math.max(0, delay),
|
|
45
|
+
repeating: false,
|
|
46
|
+
interval: 0,
|
|
47
|
+
cancelled: false
|
|
48
|
+
};
|
|
49
|
+
this.timers.set(id, timer);
|
|
50
|
+
return new TimerHandleImpl(timer);
|
|
51
|
+
}
|
|
52
|
+
scheduleRepeating(id, interval, callback, immediate = false) {
|
|
53
|
+
this.cancelById(id);
|
|
54
|
+
if (this.config.maxTimers > 0 && this.timers.size >= this.config.maxTimers) {
|
|
55
|
+
throw new Error(`Maximum timer limit reached: ${this.config.maxTimers}`);
|
|
56
|
+
}
|
|
57
|
+
const safeInterval = Math.max(1, interval);
|
|
58
|
+
const timer = {
|
|
59
|
+
id,
|
|
60
|
+
callback,
|
|
61
|
+
remaining: immediate ? 0 : safeInterval,
|
|
62
|
+
repeating: true,
|
|
63
|
+
interval: safeInterval,
|
|
64
|
+
cancelled: false
|
|
65
|
+
};
|
|
66
|
+
this.timers.set(id, timer);
|
|
67
|
+
return new TimerHandleImpl(timer);
|
|
68
|
+
}
|
|
69
|
+
cancel(handle) {
|
|
70
|
+
handle.cancel();
|
|
71
|
+
this.timers.delete(handle.id);
|
|
72
|
+
}
|
|
73
|
+
cancelById(id) {
|
|
74
|
+
const timer = this.timers.get(id);
|
|
75
|
+
if (timer) {
|
|
76
|
+
timer.cancelled = true;
|
|
77
|
+
this.timers.delete(id);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
hasTimer(id) {
|
|
81
|
+
const timer = this.timers.get(id);
|
|
82
|
+
return timer !== void 0 && !timer.cancelled;
|
|
83
|
+
}
|
|
84
|
+
getTimerInfo(id) {
|
|
85
|
+
const timer = this.timers.get(id);
|
|
86
|
+
if (!timer || timer.cancelled) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
id: timer.id,
|
|
91
|
+
remaining: timer.remaining,
|
|
92
|
+
repeating: timer.repeating,
|
|
93
|
+
interval: timer.repeating ? timer.interval : void 0
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// =========================================================================
|
|
97
|
+
// 冷却 API | Cooldown API
|
|
98
|
+
// =========================================================================
|
|
99
|
+
startCooldown(id, duration) {
|
|
100
|
+
if (this.config.maxCooldowns > 0 && !this.cooldowns.has(id)) {
|
|
101
|
+
if (this.cooldowns.size >= this.config.maxCooldowns) {
|
|
102
|
+
throw new Error(`Maximum cooldown limit reached: ${this.config.maxCooldowns}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const safeDuration = Math.max(0, duration);
|
|
106
|
+
this.cooldowns.set(id, {
|
|
107
|
+
id,
|
|
108
|
+
duration: safeDuration,
|
|
109
|
+
remaining: safeDuration
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
isOnCooldown(id) {
|
|
113
|
+
const cooldown = this.cooldowns.get(id);
|
|
114
|
+
return cooldown !== void 0 && cooldown.remaining > 0;
|
|
115
|
+
}
|
|
116
|
+
isCooldownReady(id) {
|
|
117
|
+
return !this.isOnCooldown(id);
|
|
118
|
+
}
|
|
119
|
+
getCooldownRemaining(id) {
|
|
120
|
+
const cooldown = this.cooldowns.get(id);
|
|
121
|
+
return cooldown ? Math.max(0, cooldown.remaining) : 0;
|
|
122
|
+
}
|
|
123
|
+
getCooldownProgress(id) {
|
|
124
|
+
const cooldown = this.cooldowns.get(id);
|
|
125
|
+
if (!cooldown || cooldown.duration <= 0) {
|
|
126
|
+
return 1;
|
|
127
|
+
}
|
|
128
|
+
const elapsed = cooldown.duration - cooldown.remaining;
|
|
129
|
+
return Math.min(1, Math.max(0, elapsed / cooldown.duration));
|
|
130
|
+
}
|
|
131
|
+
getCooldownInfo(id) {
|
|
132
|
+
const cooldown = this.cooldowns.get(id);
|
|
133
|
+
if (!cooldown) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const remaining = Math.max(0, cooldown.remaining);
|
|
137
|
+
const progress = cooldown.duration > 0 ? Math.min(1, (cooldown.duration - remaining) / cooldown.duration) : 1;
|
|
138
|
+
return {
|
|
139
|
+
id: cooldown.id,
|
|
140
|
+
duration: cooldown.duration,
|
|
141
|
+
remaining,
|
|
142
|
+
progress,
|
|
143
|
+
isReady: remaining <= 0
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
resetCooldown(id) {
|
|
147
|
+
this.cooldowns.delete(id);
|
|
148
|
+
}
|
|
149
|
+
clearAllCooldowns() {
|
|
150
|
+
this.cooldowns.clear();
|
|
151
|
+
}
|
|
152
|
+
// =========================================================================
|
|
153
|
+
// 更新 | Update
|
|
154
|
+
// =========================================================================
|
|
155
|
+
update(deltaTime) {
|
|
156
|
+
if (deltaTime <= 0) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
this.updateTimers(deltaTime);
|
|
160
|
+
this.updateCooldowns(deltaTime);
|
|
161
|
+
}
|
|
162
|
+
updateTimers(deltaTime) {
|
|
163
|
+
const toRemove = [];
|
|
164
|
+
for (const [id, timer] of this.timers) {
|
|
165
|
+
if (timer.cancelled) {
|
|
166
|
+
toRemove.push(id);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
timer.remaining -= deltaTime;
|
|
170
|
+
if (timer.remaining <= 0) {
|
|
171
|
+
try {
|
|
172
|
+
timer.callback();
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error(`Timer callback error [${id}]:`, error);
|
|
175
|
+
}
|
|
176
|
+
if (timer.repeating && !timer.cancelled) {
|
|
177
|
+
timer.remaining += timer.interval;
|
|
178
|
+
if (timer.remaining < 0) {
|
|
179
|
+
timer.remaining = timer.interval;
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
timer.cancelled = true;
|
|
183
|
+
toRemove.push(id);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
for (const id of toRemove) {
|
|
188
|
+
this.timers.delete(id);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
updateCooldowns(deltaTime) {
|
|
192
|
+
const toRemove = [];
|
|
193
|
+
for (const [id, cooldown] of this.cooldowns) {
|
|
194
|
+
cooldown.remaining -= deltaTime;
|
|
195
|
+
if (cooldown.remaining <= 0) {
|
|
196
|
+
toRemove.push(id);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
for (const id of toRemove) {
|
|
200
|
+
this.cooldowns.delete(id);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
clear() {
|
|
204
|
+
for (const timer of this.timers.values()) {
|
|
205
|
+
timer.cancelled = true;
|
|
206
|
+
}
|
|
207
|
+
this.timers.clear();
|
|
208
|
+
this.cooldowns.clear();
|
|
209
|
+
}
|
|
210
|
+
// =========================================================================
|
|
211
|
+
// 调试 | Debug
|
|
212
|
+
// =========================================================================
|
|
213
|
+
/**
|
|
214
|
+
* @zh 获取活跃定时器数量
|
|
215
|
+
* @en Get active timer count
|
|
216
|
+
*/
|
|
217
|
+
get activeTimerCount() {
|
|
218
|
+
return this.timers.size;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* @zh 获取活跃冷却数量
|
|
222
|
+
* @en Get active cooldown count
|
|
223
|
+
*/
|
|
224
|
+
get activeCooldownCount() {
|
|
225
|
+
return this.cooldowns.size;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* @zh 获取所有活跃定时器 ID
|
|
229
|
+
* @en Get all active timer IDs
|
|
230
|
+
*/
|
|
231
|
+
getActiveTimerIds() {
|
|
232
|
+
return Array.from(this.timers.keys());
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* @zh 获取所有活跃冷却 ID
|
|
236
|
+
* @en Get all active cooldown IDs
|
|
237
|
+
*/
|
|
238
|
+
getActiveCooldownIds() {
|
|
239
|
+
return Array.from(this.cooldowns.keys());
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
__name(_TimerService, "TimerService");
|
|
243
|
+
var TimerService = _TimerService;
|
|
244
|
+
function createTimerService(config) {
|
|
245
|
+
return new TimerService(config);
|
|
246
|
+
}
|
|
247
|
+
__name(createTimerService, "createTimerService");
|
|
248
|
+
|
|
249
|
+
// src/tokens.ts
|
|
250
|
+
import { createServiceToken } from "@esengine/ecs-framework";
|
|
251
|
+
var TimerServiceToken = createServiceToken("timerService");
|
|
252
|
+
|
|
253
|
+
// src/nodes/TimerNodes.ts
|
|
254
|
+
var StartCooldownTemplate = {
|
|
255
|
+
type: "StartCooldown",
|
|
256
|
+
title: "Start Cooldown",
|
|
257
|
+
category: "time",
|
|
258
|
+
description: "Start a cooldown timer / \u5F00\u59CB\u51B7\u5374\u8BA1\u65F6",
|
|
259
|
+
keywords: [
|
|
260
|
+
"timer",
|
|
261
|
+
"cooldown",
|
|
262
|
+
"start",
|
|
263
|
+
"delay"
|
|
264
|
+
],
|
|
265
|
+
menuPath: [
|
|
266
|
+
"Timer",
|
|
267
|
+
"Start Cooldown"
|
|
268
|
+
],
|
|
269
|
+
isPure: false,
|
|
270
|
+
inputs: [
|
|
271
|
+
{
|
|
272
|
+
name: "exec",
|
|
273
|
+
displayName: "",
|
|
274
|
+
type: "exec"
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: "id",
|
|
278
|
+
displayName: "Cooldown ID",
|
|
279
|
+
type: "string",
|
|
280
|
+
defaultValue: ""
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
name: "duration",
|
|
284
|
+
displayName: "Duration (ms)",
|
|
285
|
+
type: "float",
|
|
286
|
+
defaultValue: 1e3
|
|
287
|
+
}
|
|
288
|
+
],
|
|
289
|
+
outputs: [
|
|
290
|
+
{
|
|
291
|
+
name: "exec",
|
|
292
|
+
displayName: "",
|
|
293
|
+
type: "exec"
|
|
294
|
+
}
|
|
295
|
+
],
|
|
296
|
+
color: "#00bcd4"
|
|
297
|
+
};
|
|
298
|
+
var _StartCooldownExecutor = class _StartCooldownExecutor {
|
|
299
|
+
execute(node, context) {
|
|
300
|
+
const ctx = context;
|
|
301
|
+
const id = ctx.evaluateInput(node.id, "id", "");
|
|
302
|
+
const duration = ctx.evaluateInput(node.id, "duration", 1e3);
|
|
303
|
+
if (id && ctx.timerService) {
|
|
304
|
+
ctx.timerService.startCooldown(id, duration);
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
outputs: {},
|
|
308
|
+
nextExec: "exec"
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
__name(_StartCooldownExecutor, "StartCooldownExecutor");
|
|
313
|
+
var StartCooldownExecutor = _StartCooldownExecutor;
|
|
314
|
+
var IsCooldownReadyTemplate = {
|
|
315
|
+
type: "IsCooldownReady",
|
|
316
|
+
title: "Is Cooldown Ready",
|
|
317
|
+
category: "time",
|
|
318
|
+
description: "Check if cooldown is ready / \u68C0\u67E5\u51B7\u5374\u662F\u5426\u5C31\u7EEA",
|
|
319
|
+
keywords: [
|
|
320
|
+
"timer",
|
|
321
|
+
"cooldown",
|
|
322
|
+
"ready",
|
|
323
|
+
"check"
|
|
324
|
+
],
|
|
325
|
+
menuPath: [
|
|
326
|
+
"Timer",
|
|
327
|
+
"Is Cooldown Ready"
|
|
328
|
+
],
|
|
329
|
+
isPure: true,
|
|
330
|
+
inputs: [
|
|
331
|
+
{
|
|
332
|
+
name: "id",
|
|
333
|
+
displayName: "Cooldown ID",
|
|
334
|
+
type: "string",
|
|
335
|
+
defaultValue: ""
|
|
336
|
+
}
|
|
337
|
+
],
|
|
338
|
+
outputs: [
|
|
339
|
+
{
|
|
340
|
+
name: "isReady",
|
|
341
|
+
displayName: "Is Ready",
|
|
342
|
+
type: "bool"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
name: "isOnCooldown",
|
|
346
|
+
displayName: "Is On Cooldown",
|
|
347
|
+
type: "bool"
|
|
348
|
+
}
|
|
349
|
+
],
|
|
350
|
+
color: "#00bcd4"
|
|
351
|
+
};
|
|
352
|
+
var _IsCooldownReadyExecutor = class _IsCooldownReadyExecutor {
|
|
353
|
+
execute(node, context) {
|
|
354
|
+
const ctx = context;
|
|
355
|
+
const id = ctx.evaluateInput(node.id, "id", "");
|
|
356
|
+
const isReady = id ? ctx.timerService?.isCooldownReady(id) ?? true : true;
|
|
357
|
+
const isOnCooldown = !isReady;
|
|
358
|
+
return {
|
|
359
|
+
outputs: {
|
|
360
|
+
isReady,
|
|
361
|
+
isOnCooldown
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
__name(_IsCooldownReadyExecutor, "IsCooldownReadyExecutor");
|
|
367
|
+
var IsCooldownReadyExecutor = _IsCooldownReadyExecutor;
|
|
368
|
+
var GetCooldownProgressTemplate = {
|
|
369
|
+
type: "GetCooldownProgress",
|
|
370
|
+
title: "Get Cooldown Progress",
|
|
371
|
+
category: "time",
|
|
372
|
+
description: "Get cooldown progress (0-1) / \u83B7\u53D6\u51B7\u5374\u8FDB\u5EA6 (0-1)",
|
|
373
|
+
keywords: [
|
|
374
|
+
"timer",
|
|
375
|
+
"cooldown",
|
|
376
|
+
"progress",
|
|
377
|
+
"remaining"
|
|
378
|
+
],
|
|
379
|
+
menuPath: [
|
|
380
|
+
"Timer",
|
|
381
|
+
"Get Cooldown Progress"
|
|
382
|
+
],
|
|
383
|
+
isPure: true,
|
|
384
|
+
inputs: [
|
|
385
|
+
{
|
|
386
|
+
name: "id",
|
|
387
|
+
displayName: "Cooldown ID",
|
|
388
|
+
type: "string",
|
|
389
|
+
defaultValue: ""
|
|
390
|
+
}
|
|
391
|
+
],
|
|
392
|
+
outputs: [
|
|
393
|
+
{
|
|
394
|
+
name: "progress",
|
|
395
|
+
displayName: "Progress",
|
|
396
|
+
type: "float"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
name: "remaining",
|
|
400
|
+
displayName: "Remaining (ms)",
|
|
401
|
+
type: "float"
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
name: "isReady",
|
|
405
|
+
displayName: "Is Ready",
|
|
406
|
+
type: "bool"
|
|
407
|
+
}
|
|
408
|
+
],
|
|
409
|
+
color: "#00bcd4"
|
|
410
|
+
};
|
|
411
|
+
var _GetCooldownProgressExecutor = class _GetCooldownProgressExecutor {
|
|
412
|
+
execute(node, context) {
|
|
413
|
+
const ctx = context;
|
|
414
|
+
const id = ctx.evaluateInput(node.id, "id", "");
|
|
415
|
+
const progress = id ? ctx.timerService?.getCooldownProgress(id) ?? 1 : 1;
|
|
416
|
+
const remaining = id ? ctx.timerService?.getCooldownRemaining(id) ?? 0 : 0;
|
|
417
|
+
const isReady = remaining <= 0;
|
|
418
|
+
return {
|
|
419
|
+
outputs: {
|
|
420
|
+
progress,
|
|
421
|
+
remaining,
|
|
422
|
+
isReady
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
__name(_GetCooldownProgressExecutor, "GetCooldownProgressExecutor");
|
|
428
|
+
var GetCooldownProgressExecutor = _GetCooldownProgressExecutor;
|
|
429
|
+
var ResetCooldownTemplate = {
|
|
430
|
+
type: "ResetCooldown",
|
|
431
|
+
title: "Reset Cooldown",
|
|
432
|
+
category: "time",
|
|
433
|
+
description: "Reset a cooldown (make it ready) / \u91CD\u7F6E\u51B7\u5374\uFF08\u4F7F\u5176\u5C31\u7EEA\uFF09",
|
|
434
|
+
keywords: [
|
|
435
|
+
"timer",
|
|
436
|
+
"cooldown",
|
|
437
|
+
"reset",
|
|
438
|
+
"clear"
|
|
439
|
+
],
|
|
440
|
+
menuPath: [
|
|
441
|
+
"Timer",
|
|
442
|
+
"Reset Cooldown"
|
|
443
|
+
],
|
|
444
|
+
isPure: false,
|
|
445
|
+
inputs: [
|
|
446
|
+
{
|
|
447
|
+
name: "exec",
|
|
448
|
+
displayName: "",
|
|
449
|
+
type: "exec"
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
name: "id",
|
|
453
|
+
displayName: "Cooldown ID",
|
|
454
|
+
type: "string",
|
|
455
|
+
defaultValue: ""
|
|
456
|
+
}
|
|
457
|
+
],
|
|
458
|
+
outputs: [
|
|
459
|
+
{
|
|
460
|
+
name: "exec",
|
|
461
|
+
displayName: "",
|
|
462
|
+
type: "exec"
|
|
463
|
+
}
|
|
464
|
+
],
|
|
465
|
+
color: "#00bcd4"
|
|
466
|
+
};
|
|
467
|
+
var _ResetCooldownExecutor = class _ResetCooldownExecutor {
|
|
468
|
+
execute(node, context) {
|
|
469
|
+
const ctx = context;
|
|
470
|
+
const id = ctx.evaluateInput(node.id, "id", "");
|
|
471
|
+
if (id && ctx.timerService) {
|
|
472
|
+
ctx.timerService.resetCooldown(id);
|
|
473
|
+
}
|
|
474
|
+
return {
|
|
475
|
+
outputs: {},
|
|
476
|
+
nextExec: "exec"
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
__name(_ResetCooldownExecutor, "ResetCooldownExecutor");
|
|
481
|
+
var ResetCooldownExecutor = _ResetCooldownExecutor;
|
|
482
|
+
var GetCooldownInfoTemplate = {
|
|
483
|
+
type: "GetCooldownInfo",
|
|
484
|
+
title: "Get Cooldown Info",
|
|
485
|
+
category: "time",
|
|
486
|
+
description: "Get detailed cooldown information / \u83B7\u53D6\u8BE6\u7EC6\u51B7\u5374\u4FE1\u606F",
|
|
487
|
+
keywords: [
|
|
488
|
+
"timer",
|
|
489
|
+
"cooldown",
|
|
490
|
+
"info",
|
|
491
|
+
"details"
|
|
492
|
+
],
|
|
493
|
+
menuPath: [
|
|
494
|
+
"Timer",
|
|
495
|
+
"Get Cooldown Info"
|
|
496
|
+
],
|
|
497
|
+
isPure: true,
|
|
498
|
+
inputs: [
|
|
499
|
+
{
|
|
500
|
+
name: "id",
|
|
501
|
+
displayName: "Cooldown ID",
|
|
502
|
+
type: "string",
|
|
503
|
+
defaultValue: ""
|
|
504
|
+
}
|
|
505
|
+
],
|
|
506
|
+
outputs: [
|
|
507
|
+
{
|
|
508
|
+
name: "exists",
|
|
509
|
+
displayName: "Exists",
|
|
510
|
+
type: "bool"
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
name: "duration",
|
|
514
|
+
displayName: "Duration (ms)",
|
|
515
|
+
type: "float"
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
name: "remaining",
|
|
519
|
+
displayName: "Remaining (ms)",
|
|
520
|
+
type: "float"
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
name: "progress",
|
|
524
|
+
displayName: "Progress",
|
|
525
|
+
type: "float"
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
name: "isReady",
|
|
529
|
+
displayName: "Is Ready",
|
|
530
|
+
type: "bool"
|
|
531
|
+
}
|
|
532
|
+
],
|
|
533
|
+
color: "#00bcd4"
|
|
534
|
+
};
|
|
535
|
+
var _GetCooldownInfoExecutor = class _GetCooldownInfoExecutor {
|
|
536
|
+
execute(node, context) {
|
|
537
|
+
const ctx = context;
|
|
538
|
+
const id = ctx.evaluateInput(node.id, "id", "");
|
|
539
|
+
const info = id ? ctx.timerService?.getCooldownInfo(id) : null;
|
|
540
|
+
return {
|
|
541
|
+
outputs: {
|
|
542
|
+
exists: info !== null,
|
|
543
|
+
duration: info?.duration ?? 0,
|
|
544
|
+
remaining: info?.remaining ?? 0,
|
|
545
|
+
progress: info?.progress ?? 1,
|
|
546
|
+
isReady: info?.isReady ?? true
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
__name(_GetCooldownInfoExecutor, "GetCooldownInfoExecutor");
|
|
552
|
+
var GetCooldownInfoExecutor = _GetCooldownInfoExecutor;
|
|
553
|
+
var HasTimerTemplate = {
|
|
554
|
+
type: "HasTimer",
|
|
555
|
+
title: "Has Timer",
|
|
556
|
+
category: "time",
|
|
557
|
+
description: "Check if a timer exists / \u68C0\u67E5\u5B9A\u65F6\u5668\u662F\u5426\u5B58\u5728",
|
|
558
|
+
keywords: [
|
|
559
|
+
"timer",
|
|
560
|
+
"exists",
|
|
561
|
+
"check",
|
|
562
|
+
"has"
|
|
563
|
+
],
|
|
564
|
+
menuPath: [
|
|
565
|
+
"Timer",
|
|
566
|
+
"Has Timer"
|
|
567
|
+
],
|
|
568
|
+
isPure: true,
|
|
569
|
+
inputs: [
|
|
570
|
+
{
|
|
571
|
+
name: "id",
|
|
572
|
+
displayName: "Timer ID",
|
|
573
|
+
type: "string",
|
|
574
|
+
defaultValue: ""
|
|
575
|
+
}
|
|
576
|
+
],
|
|
577
|
+
outputs: [
|
|
578
|
+
{
|
|
579
|
+
name: "exists",
|
|
580
|
+
displayName: "Exists",
|
|
581
|
+
type: "bool"
|
|
582
|
+
}
|
|
583
|
+
],
|
|
584
|
+
color: "#00bcd4"
|
|
585
|
+
};
|
|
586
|
+
var _HasTimerExecutor = class _HasTimerExecutor {
|
|
587
|
+
execute(node, context) {
|
|
588
|
+
const ctx = context;
|
|
589
|
+
const id = ctx.evaluateInput(node.id, "id", "");
|
|
590
|
+
const exists = id ? ctx.timerService?.hasTimer(id) ?? false : false;
|
|
591
|
+
return {
|
|
592
|
+
outputs: {
|
|
593
|
+
exists
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
__name(_HasTimerExecutor, "HasTimerExecutor");
|
|
599
|
+
var HasTimerExecutor = _HasTimerExecutor;
|
|
600
|
+
var CancelTimerTemplate = {
|
|
601
|
+
type: "CancelTimer",
|
|
602
|
+
title: "Cancel Timer",
|
|
603
|
+
category: "time",
|
|
604
|
+
description: "Cancel a timer by ID / \u901A\u8FC7 ID \u53D6\u6D88\u5B9A\u65F6\u5668",
|
|
605
|
+
keywords: [
|
|
606
|
+
"timer",
|
|
607
|
+
"cancel",
|
|
608
|
+
"stop",
|
|
609
|
+
"clear"
|
|
610
|
+
],
|
|
611
|
+
menuPath: [
|
|
612
|
+
"Timer",
|
|
613
|
+
"Cancel Timer"
|
|
614
|
+
],
|
|
615
|
+
isPure: false,
|
|
616
|
+
inputs: [
|
|
617
|
+
{
|
|
618
|
+
name: "exec",
|
|
619
|
+
displayName: "",
|
|
620
|
+
type: "exec"
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
name: "id",
|
|
624
|
+
displayName: "Timer ID",
|
|
625
|
+
type: "string",
|
|
626
|
+
defaultValue: ""
|
|
627
|
+
}
|
|
628
|
+
],
|
|
629
|
+
outputs: [
|
|
630
|
+
{
|
|
631
|
+
name: "exec",
|
|
632
|
+
displayName: "",
|
|
633
|
+
type: "exec"
|
|
634
|
+
}
|
|
635
|
+
],
|
|
636
|
+
color: "#00bcd4"
|
|
637
|
+
};
|
|
638
|
+
var _CancelTimerExecutor = class _CancelTimerExecutor {
|
|
639
|
+
execute(node, context) {
|
|
640
|
+
const ctx = context;
|
|
641
|
+
const id = ctx.evaluateInput(node.id, "id", "");
|
|
642
|
+
if (id && ctx.timerService) {
|
|
643
|
+
ctx.timerService.cancelById(id);
|
|
644
|
+
}
|
|
645
|
+
return {
|
|
646
|
+
outputs: {},
|
|
647
|
+
nextExec: "exec"
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
__name(_CancelTimerExecutor, "CancelTimerExecutor");
|
|
652
|
+
var CancelTimerExecutor = _CancelTimerExecutor;
|
|
653
|
+
var GetTimerRemainingTemplate = {
|
|
654
|
+
type: "GetTimerRemaining",
|
|
655
|
+
title: "Get Timer Remaining",
|
|
656
|
+
category: "time",
|
|
657
|
+
description: "Get remaining time for a timer / \u83B7\u53D6\u5B9A\u65F6\u5668\u5269\u4F59\u65F6\u95F4",
|
|
658
|
+
keywords: [
|
|
659
|
+
"timer",
|
|
660
|
+
"remaining",
|
|
661
|
+
"time",
|
|
662
|
+
"left"
|
|
663
|
+
],
|
|
664
|
+
menuPath: [
|
|
665
|
+
"Timer",
|
|
666
|
+
"Get Timer Remaining"
|
|
667
|
+
],
|
|
668
|
+
isPure: true,
|
|
669
|
+
inputs: [
|
|
670
|
+
{
|
|
671
|
+
name: "id",
|
|
672
|
+
displayName: "Timer ID",
|
|
673
|
+
type: "string",
|
|
674
|
+
defaultValue: ""
|
|
675
|
+
}
|
|
676
|
+
],
|
|
677
|
+
outputs: [
|
|
678
|
+
{
|
|
679
|
+
name: "remaining",
|
|
680
|
+
displayName: "Remaining (ms)",
|
|
681
|
+
type: "float"
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
name: "exists",
|
|
685
|
+
displayName: "Exists",
|
|
686
|
+
type: "bool"
|
|
687
|
+
}
|
|
688
|
+
],
|
|
689
|
+
color: "#00bcd4"
|
|
690
|
+
};
|
|
691
|
+
var _GetTimerRemainingExecutor = class _GetTimerRemainingExecutor {
|
|
692
|
+
execute(node, context) {
|
|
693
|
+
const ctx = context;
|
|
694
|
+
const id = ctx.evaluateInput(node.id, "id", "");
|
|
695
|
+
const info = id ? ctx.timerService?.getTimerInfo(id) : null;
|
|
696
|
+
return {
|
|
697
|
+
outputs: {
|
|
698
|
+
remaining: info?.remaining ?? 0,
|
|
699
|
+
exists: info !== null
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
__name(_GetTimerRemainingExecutor, "GetTimerRemainingExecutor");
|
|
705
|
+
var GetTimerRemainingExecutor = _GetTimerRemainingExecutor;
|
|
706
|
+
var TimerNodeDefinitions = [
|
|
707
|
+
{
|
|
708
|
+
template: StartCooldownTemplate,
|
|
709
|
+
executor: new StartCooldownExecutor()
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
template: IsCooldownReadyTemplate,
|
|
713
|
+
executor: new IsCooldownReadyExecutor()
|
|
714
|
+
},
|
|
715
|
+
{
|
|
716
|
+
template: GetCooldownProgressTemplate,
|
|
717
|
+
executor: new GetCooldownProgressExecutor()
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
template: ResetCooldownTemplate,
|
|
721
|
+
executor: new ResetCooldownExecutor()
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
template: GetCooldownInfoTemplate,
|
|
725
|
+
executor: new GetCooldownInfoExecutor()
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
template: HasTimerTemplate,
|
|
729
|
+
executor: new HasTimerExecutor()
|
|
730
|
+
},
|
|
731
|
+
{
|
|
732
|
+
template: CancelTimerTemplate,
|
|
733
|
+
executor: new CancelTimerExecutor()
|
|
734
|
+
},
|
|
735
|
+
{
|
|
736
|
+
template: GetTimerRemainingTemplate,
|
|
737
|
+
executor: new GetTimerRemainingExecutor()
|
|
738
|
+
}
|
|
739
|
+
];
|
|
740
|
+
export {
|
|
741
|
+
CancelTimerExecutor,
|
|
742
|
+
CancelTimerTemplate,
|
|
743
|
+
GetCooldownInfoExecutor,
|
|
744
|
+
GetCooldownInfoTemplate,
|
|
745
|
+
GetCooldownProgressExecutor,
|
|
746
|
+
GetCooldownProgressTemplate,
|
|
747
|
+
GetTimerRemainingExecutor,
|
|
748
|
+
GetTimerRemainingTemplate,
|
|
749
|
+
HasTimerExecutor,
|
|
750
|
+
HasTimerTemplate,
|
|
751
|
+
IsCooldownReadyExecutor,
|
|
752
|
+
IsCooldownReadyTemplate,
|
|
753
|
+
ResetCooldownExecutor,
|
|
754
|
+
ResetCooldownTemplate,
|
|
755
|
+
StartCooldownExecutor,
|
|
756
|
+
StartCooldownTemplate,
|
|
757
|
+
TimerNodeDefinitions,
|
|
758
|
+
TimerService,
|
|
759
|
+
TimerServiceToken,
|
|
760
|
+
createTimerService
|
|
761
|
+
};
|
|
762
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/TimerService.ts","../src/tokens.ts","../src/nodes/TimerNodes.ts"],"sourcesContent":["/**\n * @zh 定时器服务实现\n * @en Timer Service Implementation\n *\n * @zh 提供定时器调度和冷却管理的默认实现\n * @en Provides default implementation for timer scheduling and cooldown management\n */\n\nimport type {\n ITimerService,\n TimerHandle,\n TimerInfo,\n TimerCallback,\n CooldownInfo\n} from './ITimerService';\n\n// =============================================================================\n// 内部类型 | Internal Types\n// =============================================================================\n\n/**\n * @zh 内部定时器数据\n * @en Internal timer data\n */\ninterface InternalTimer {\n id: string;\n callback: TimerCallback;\n remaining: number;\n repeating: boolean;\n interval: number;\n cancelled: boolean;\n}\n\n/**\n * @zh 内部冷却数据\n * @en Internal cooldown data\n */\ninterface InternalCooldown {\n id: string;\n duration: number;\n remaining: number;\n}\n\n// =============================================================================\n// 定时器句柄实现 | Timer Handle Implementation\n// =============================================================================\n\n/**\n * @zh 定时器句柄实现\n * @en Timer handle implementation\n */\nclass TimerHandleImpl implements TimerHandle {\n private timer: InternalTimer;\n\n constructor(timer: InternalTimer) {\n this.timer = timer;\n }\n\n get id(): string {\n return this.timer.id;\n }\n\n get isValid(): boolean {\n return !this.timer.cancelled;\n }\n\n cancel(): void {\n this.timer.cancelled = true;\n }\n}\n\n// =============================================================================\n// 定时器服务实现 | Timer Service Implementation\n// =============================================================================\n\n/**\n * @zh 定时器服务配置\n * @en Timer service configuration\n */\nexport interface TimerServiceConfig {\n /**\n * @zh 最大定时器数量(0 表示无限制)\n * @en Maximum number of timers (0 for unlimited)\n */\n maxTimers?: number;\n\n /**\n * @zh 最大冷却数量(0 表示无限制)\n * @en Maximum number of cooldowns (0 for unlimited)\n */\n maxCooldowns?: number;\n}\n\n/**\n * @zh 定时器服务实现\n * @en Timer service implementation\n *\n * @example\n * ```typescript\n * const timerService = new TimerService();\n *\n * // 一次性定时器 | One-time timer\n * const handle = timerService.schedule('myTimer', 1000, () => {\n * console.log('Timer fired!');\n * });\n *\n * // 重复定时器 | Repeating timer\n * timerService.scheduleRepeating('heartbeat', 100, () => {\n * console.log('Tick');\n * });\n *\n * // 冷却系统 | Cooldown system\n * timerService.startCooldown('skill_fireball', 5000);\n * if (timerService.isCooldownReady('skill_fireball')) {\n * // 可以使用技能 | Can use skill\n * }\n *\n * // 每帧更新 | Update each frame\n * timerService.update(deltaTime);\n * ```\n */\nexport class TimerService implements ITimerService {\n private timers: Map<string, InternalTimer> = new Map();\n private cooldowns: Map<string, InternalCooldown> = new Map();\n private config: Required<TimerServiceConfig>;\n\n constructor(config: TimerServiceConfig = {}) {\n this.config = {\n maxTimers: config.maxTimers ?? 0,\n maxCooldowns: config.maxCooldowns ?? 0\n };\n }\n\n // =========================================================================\n // 定时器 API | Timer API\n // =========================================================================\n\n schedule(id: string, delay: number, callback: TimerCallback): TimerHandle {\n this.cancelById(id);\n\n if (this.config.maxTimers > 0 && this.timers.size >= this.config.maxTimers) {\n throw new Error(`Maximum timer limit reached: ${this.config.maxTimers}`);\n }\n\n const timer: InternalTimer = {\n id,\n callback,\n remaining: Math.max(0, delay),\n repeating: false,\n interval: 0,\n cancelled: false\n };\n\n this.timers.set(id, timer);\n return new TimerHandleImpl(timer);\n }\n\n scheduleRepeating(\n id: string,\n interval: number,\n callback: TimerCallback,\n immediate = false\n ): TimerHandle {\n this.cancelById(id);\n\n if (this.config.maxTimers > 0 && this.timers.size >= this.config.maxTimers) {\n throw new Error(`Maximum timer limit reached: ${this.config.maxTimers}`);\n }\n\n const safeInterval = Math.max(1, interval);\n\n const timer: InternalTimer = {\n id,\n callback,\n remaining: immediate ? 0 : safeInterval,\n repeating: true,\n interval: safeInterval,\n cancelled: false\n };\n\n this.timers.set(id, timer);\n return new TimerHandleImpl(timer);\n }\n\n cancel(handle: TimerHandle): void {\n handle.cancel();\n this.timers.delete(handle.id);\n }\n\n cancelById(id: string): void {\n const timer = this.timers.get(id);\n if (timer) {\n timer.cancelled = true;\n this.timers.delete(id);\n }\n }\n\n hasTimer(id: string): boolean {\n const timer = this.timers.get(id);\n return timer !== undefined && !timer.cancelled;\n }\n\n getTimerInfo(id: string): TimerInfo | null {\n const timer = this.timers.get(id);\n if (!timer || timer.cancelled) {\n return null;\n }\n\n return {\n id: timer.id,\n remaining: timer.remaining,\n repeating: timer.repeating,\n interval: timer.repeating ? timer.interval : undefined\n };\n }\n\n // =========================================================================\n // 冷却 API | Cooldown API\n // =========================================================================\n\n startCooldown(id: string, duration: number): void {\n if (this.config.maxCooldowns > 0 && !this.cooldowns.has(id)) {\n if (this.cooldowns.size >= this.config.maxCooldowns) {\n throw new Error(`Maximum cooldown limit reached: ${this.config.maxCooldowns}`);\n }\n }\n\n const safeDuration = Math.max(0, duration);\n\n this.cooldowns.set(id, {\n id,\n duration: safeDuration,\n remaining: safeDuration\n });\n }\n\n isOnCooldown(id: string): boolean {\n const cooldown = this.cooldowns.get(id);\n return cooldown !== undefined && cooldown.remaining > 0;\n }\n\n isCooldownReady(id: string): boolean {\n return !this.isOnCooldown(id);\n }\n\n getCooldownRemaining(id: string): number {\n const cooldown = this.cooldowns.get(id);\n return cooldown ? Math.max(0, cooldown.remaining) : 0;\n }\n\n getCooldownProgress(id: string): number {\n const cooldown = this.cooldowns.get(id);\n if (!cooldown || cooldown.duration <= 0) {\n return 1;\n }\n\n const elapsed = cooldown.duration - cooldown.remaining;\n return Math.min(1, Math.max(0, elapsed / cooldown.duration));\n }\n\n getCooldownInfo(id: string): CooldownInfo | null {\n const cooldown = this.cooldowns.get(id);\n if (!cooldown) {\n return null;\n }\n\n const remaining = Math.max(0, cooldown.remaining);\n const progress = cooldown.duration > 0\n ? Math.min(1, (cooldown.duration - remaining) / cooldown.duration)\n : 1;\n\n return {\n id: cooldown.id,\n duration: cooldown.duration,\n remaining,\n progress,\n isReady: remaining <= 0\n };\n }\n\n resetCooldown(id: string): void {\n this.cooldowns.delete(id);\n }\n\n clearAllCooldowns(): void {\n this.cooldowns.clear();\n }\n\n // =========================================================================\n // 更新 | Update\n // =========================================================================\n\n update(deltaTime: number): void {\n if (deltaTime <= 0) {\n return;\n }\n\n this.updateTimers(deltaTime);\n this.updateCooldowns(deltaTime);\n }\n\n private updateTimers(deltaTime: number): void {\n const toRemove: string[] = [];\n\n for (const [id, timer] of this.timers) {\n if (timer.cancelled) {\n toRemove.push(id);\n continue;\n }\n\n timer.remaining -= deltaTime;\n\n if (timer.remaining <= 0) {\n try {\n timer.callback();\n } catch (error) {\n console.error(`Timer callback error [${id}]:`, error);\n }\n\n if (timer.repeating && !timer.cancelled) {\n timer.remaining += timer.interval;\n if (timer.remaining < 0) {\n timer.remaining = timer.interval;\n }\n } else {\n timer.cancelled = true;\n toRemove.push(id);\n }\n }\n }\n\n for (const id of toRemove) {\n this.timers.delete(id);\n }\n }\n\n private updateCooldowns(deltaTime: number): void {\n const toRemove: string[] = [];\n\n for (const [id, cooldown] of this.cooldowns) {\n cooldown.remaining -= deltaTime;\n\n if (cooldown.remaining <= 0) {\n toRemove.push(id);\n }\n }\n\n for (const id of toRemove) {\n this.cooldowns.delete(id);\n }\n }\n\n clear(): void {\n for (const timer of this.timers.values()) {\n timer.cancelled = true;\n }\n this.timers.clear();\n this.cooldowns.clear();\n }\n\n // =========================================================================\n // 调试 | Debug\n // =========================================================================\n\n /**\n * @zh 获取活跃定时器数量\n * @en Get active timer count\n */\n get activeTimerCount(): number {\n return this.timers.size;\n }\n\n /**\n * @zh 获取活跃冷却数量\n * @en Get active cooldown count\n */\n get activeCooldownCount(): number {\n return this.cooldowns.size;\n }\n\n /**\n * @zh 获取所有活跃定时器 ID\n * @en Get all active timer IDs\n */\n getActiveTimerIds(): string[] {\n return Array.from(this.timers.keys());\n }\n\n /**\n * @zh 获取所有活跃冷却 ID\n * @en Get all active cooldown IDs\n */\n getActiveCooldownIds(): string[] {\n return Array.from(this.cooldowns.keys());\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Functions\n// =============================================================================\n\n/**\n * @zh 创建定时器服务\n * @en Create timer service\n *\n * @param config - @zh 配置选项 @en Configuration options\n * @returns @zh 定时器服务实例 @en Timer service instance\n */\nexport function createTimerService(config?: TimerServiceConfig): ITimerService {\n return new TimerService(config);\n}\n","/**\n * @zh 定时器服务令牌\n * @en Timer Service Tokens\n */\n\nimport { createServiceToken } from '@esengine/ecs-framework';\nimport type { ITimerService } from './ITimerService';\n\n/**\n * @zh 定时器服务令牌\n * @en Timer service token\n *\n * @zh 用于注入定时器服务\n * @en Used for injecting timer service\n */\nexport const TimerServiceToken = createServiceToken<ITimerService>('timerService');\n","/**\n * @zh 定时器蓝图节点\n * @en Timer Blueprint Nodes\n *\n * @zh 提供定时器和冷却功能的蓝图节点\n * @en Provides blueprint nodes for timer and cooldown functionality\n */\n\nimport type { BlueprintNodeTemplate, BlueprintNode, INodeExecutor, ExecutionResult } from '@esengine/blueprint';\nimport type { ITimerService } from '../ITimerService';\n\n// =============================================================================\n// 执行上下文接口 | Execution Context Interface\n// =============================================================================\n\n/**\n * @zh 定时器上下文\n * @en Timer context\n */\ninterface TimerContext {\n timerService: ITimerService;\n evaluateInput(nodeId: string, pinName: string, defaultValue?: unknown): unknown;\n setOutputs(nodeId: string, outputs: Record<string, unknown>): void;\n}\n\n// =============================================================================\n// StartCooldown 节点 | StartCooldown Node\n// =============================================================================\n\n/**\n * @zh StartCooldown 节点模板\n * @en StartCooldown node template\n */\nexport const StartCooldownTemplate: BlueprintNodeTemplate = {\n type: 'StartCooldown',\n title: 'Start Cooldown',\n category: 'time',\n description: 'Start a cooldown timer / 开始冷却计时',\n keywords: ['timer', 'cooldown', 'start', 'delay'],\n menuPath: ['Timer', 'Start Cooldown'],\n isPure: false,\n inputs: [\n {\n name: 'exec',\n displayName: '',\n type: 'exec'\n },\n {\n name: 'id',\n displayName: 'Cooldown ID',\n type: 'string',\n defaultValue: ''\n },\n {\n name: 'duration',\n displayName: 'Duration (ms)',\n type: 'float',\n defaultValue: 1000\n }\n ],\n outputs: [\n {\n name: 'exec',\n displayName: '',\n type: 'exec'\n }\n ],\n color: '#00bcd4'\n};\n\n/**\n * @zh StartCooldown 节点执行器\n * @en StartCooldown node executor\n */\nexport class StartCooldownExecutor implements INodeExecutor {\n execute(node: BlueprintNode, context: unknown): ExecutionResult {\n const ctx = context as TimerContext;\n const id = ctx.evaluateInput(node.id, 'id', '') as string;\n const duration = ctx.evaluateInput(node.id, 'duration', 1000) as number;\n\n if (id && ctx.timerService) {\n ctx.timerService.startCooldown(id, duration);\n }\n\n return {\n outputs: {},\n nextExec: 'exec'\n };\n }\n}\n\n// =============================================================================\n// IsCooldownReady 节点 | IsCooldownReady Node\n// =============================================================================\n\n/**\n * @zh IsCooldownReady 节点模板\n * @en IsCooldownReady node template\n */\nexport const IsCooldownReadyTemplate: BlueprintNodeTemplate = {\n type: 'IsCooldownReady',\n title: 'Is Cooldown Ready',\n category: 'time',\n description: 'Check if cooldown is ready / 检查冷却是否就绪',\n keywords: ['timer', 'cooldown', 'ready', 'check'],\n menuPath: ['Timer', 'Is Cooldown Ready'],\n isPure: true,\n inputs: [\n {\n name: 'id',\n displayName: 'Cooldown ID',\n type: 'string',\n defaultValue: ''\n }\n ],\n outputs: [\n {\n name: 'isReady',\n displayName: 'Is Ready',\n type: 'bool'\n },\n {\n name: 'isOnCooldown',\n displayName: 'Is On Cooldown',\n type: 'bool'\n }\n ],\n color: '#00bcd4'\n};\n\n/**\n * @zh IsCooldownReady 节点执行器\n * @en IsCooldownReady node executor\n */\nexport class IsCooldownReadyExecutor implements INodeExecutor {\n execute(node: BlueprintNode, context: unknown): ExecutionResult {\n const ctx = context as TimerContext;\n const id = ctx.evaluateInput(node.id, 'id', '') as string;\n\n const isReady = id ? ctx.timerService?.isCooldownReady(id) ?? true : true;\n const isOnCooldown = !isReady;\n\n return {\n outputs: {\n isReady,\n isOnCooldown\n }\n };\n }\n}\n\n// =============================================================================\n// GetCooldownProgress 节点 | GetCooldownProgress Node\n// =============================================================================\n\n/**\n * @zh GetCooldownProgress 节点模板\n * @en GetCooldownProgress node template\n */\nexport const GetCooldownProgressTemplate: BlueprintNodeTemplate = {\n type: 'GetCooldownProgress',\n title: 'Get Cooldown Progress',\n category: 'time',\n description: 'Get cooldown progress (0-1) / 获取冷却进度 (0-1)',\n keywords: ['timer', 'cooldown', 'progress', 'remaining'],\n menuPath: ['Timer', 'Get Cooldown Progress'],\n isPure: true,\n inputs: [\n {\n name: 'id',\n displayName: 'Cooldown ID',\n type: 'string',\n defaultValue: ''\n }\n ],\n outputs: [\n {\n name: 'progress',\n displayName: 'Progress',\n type: 'float'\n },\n {\n name: 'remaining',\n displayName: 'Remaining (ms)',\n type: 'float'\n },\n {\n name: 'isReady',\n displayName: 'Is Ready',\n type: 'bool'\n }\n ],\n color: '#00bcd4'\n};\n\n/**\n * @zh GetCooldownProgress 节点执行器\n * @en GetCooldownProgress node executor\n */\nexport class GetCooldownProgressExecutor implements INodeExecutor {\n execute(node: BlueprintNode, context: unknown): ExecutionResult {\n const ctx = context as TimerContext;\n const id = ctx.evaluateInput(node.id, 'id', '') as string;\n\n const progress = id ? ctx.timerService?.getCooldownProgress(id) ?? 1 : 1;\n const remaining = id ? ctx.timerService?.getCooldownRemaining(id) ?? 0 : 0;\n const isReady = remaining <= 0;\n\n return {\n outputs: {\n progress,\n remaining,\n isReady\n }\n };\n }\n}\n\n// =============================================================================\n// ResetCooldown 节点 | ResetCooldown Node\n// =============================================================================\n\n/**\n * @zh ResetCooldown 节点模板\n * @en ResetCooldown node template\n */\nexport const ResetCooldownTemplate: BlueprintNodeTemplate = {\n type: 'ResetCooldown',\n title: 'Reset Cooldown',\n category: 'time',\n description: 'Reset a cooldown (make it ready) / 重置冷却(使其就绪)',\n keywords: ['timer', 'cooldown', 'reset', 'clear'],\n menuPath: ['Timer', 'Reset Cooldown'],\n isPure: false,\n inputs: [\n {\n name: 'exec',\n displayName: '',\n type: 'exec'\n },\n {\n name: 'id',\n displayName: 'Cooldown ID',\n type: 'string',\n defaultValue: ''\n }\n ],\n outputs: [\n {\n name: 'exec',\n displayName: '',\n type: 'exec'\n }\n ],\n color: '#00bcd4'\n};\n\n/**\n * @zh ResetCooldown 节点执行器\n * @en ResetCooldown node executor\n */\nexport class ResetCooldownExecutor implements INodeExecutor {\n execute(node: BlueprintNode, context: unknown): ExecutionResult {\n const ctx = context as TimerContext;\n const id = ctx.evaluateInput(node.id, 'id', '') as string;\n\n if (id && ctx.timerService) {\n ctx.timerService.resetCooldown(id);\n }\n\n return {\n outputs: {},\n nextExec: 'exec'\n };\n }\n}\n\n// =============================================================================\n// GetCooldownInfo 节点 | GetCooldownInfo Node\n// =============================================================================\n\n/**\n * @zh GetCooldownInfo 节点模板\n * @en GetCooldownInfo node template\n */\nexport const GetCooldownInfoTemplate: BlueprintNodeTemplate = {\n type: 'GetCooldownInfo',\n title: 'Get Cooldown Info',\n category: 'time',\n description: 'Get detailed cooldown information / 获取详细冷却信息',\n keywords: ['timer', 'cooldown', 'info', 'details'],\n menuPath: ['Timer', 'Get Cooldown Info'],\n isPure: true,\n inputs: [\n {\n name: 'id',\n displayName: 'Cooldown ID',\n type: 'string',\n defaultValue: ''\n }\n ],\n outputs: [\n {\n name: 'exists',\n displayName: 'Exists',\n type: 'bool'\n },\n {\n name: 'duration',\n displayName: 'Duration (ms)',\n type: 'float'\n },\n {\n name: 'remaining',\n displayName: 'Remaining (ms)',\n type: 'float'\n },\n {\n name: 'progress',\n displayName: 'Progress',\n type: 'float'\n },\n {\n name: 'isReady',\n displayName: 'Is Ready',\n type: 'bool'\n }\n ],\n color: '#00bcd4'\n};\n\n/**\n * @zh GetCooldownInfo 节点执行器\n * @en GetCooldownInfo node executor\n */\nexport class GetCooldownInfoExecutor implements INodeExecutor {\n execute(node: BlueprintNode, context: unknown): ExecutionResult {\n const ctx = context as TimerContext;\n const id = ctx.evaluateInput(node.id, 'id', '') as string;\n\n const info = id ? ctx.timerService?.getCooldownInfo(id) : null;\n\n return {\n outputs: {\n exists: info !== null,\n duration: info?.duration ?? 0,\n remaining: info?.remaining ?? 0,\n progress: info?.progress ?? 1,\n isReady: info?.isReady ?? true\n }\n };\n }\n}\n\n// =============================================================================\n// HasTimer 节点 | HasTimer Node\n// =============================================================================\n\n/**\n * @zh HasTimer 节点模板\n * @en HasTimer node template\n */\nexport const HasTimerTemplate: BlueprintNodeTemplate = {\n type: 'HasTimer',\n title: 'Has Timer',\n category: 'time',\n description: 'Check if a timer exists / 检查定时器是否存在',\n keywords: ['timer', 'exists', 'check', 'has'],\n menuPath: ['Timer', 'Has Timer'],\n isPure: true,\n inputs: [\n {\n name: 'id',\n displayName: 'Timer ID',\n type: 'string',\n defaultValue: ''\n }\n ],\n outputs: [\n {\n name: 'exists',\n displayName: 'Exists',\n type: 'bool'\n }\n ],\n color: '#00bcd4'\n};\n\n/**\n * @zh HasTimer 节点执行器\n * @en HasTimer node executor\n */\nexport class HasTimerExecutor implements INodeExecutor {\n execute(node: BlueprintNode, context: unknown): ExecutionResult {\n const ctx = context as TimerContext;\n const id = ctx.evaluateInput(node.id, 'id', '') as string;\n\n const exists = id ? ctx.timerService?.hasTimer(id) ?? false : false;\n\n return {\n outputs: {\n exists\n }\n };\n }\n}\n\n// =============================================================================\n// CancelTimer 节点 | CancelTimer Node\n// =============================================================================\n\n/**\n * @zh CancelTimer 节点模板\n * @en CancelTimer node template\n */\nexport const CancelTimerTemplate: BlueprintNodeTemplate = {\n type: 'CancelTimer',\n title: 'Cancel Timer',\n category: 'time',\n description: 'Cancel a timer by ID / 通过 ID 取消定时器',\n keywords: ['timer', 'cancel', 'stop', 'clear'],\n menuPath: ['Timer', 'Cancel Timer'],\n isPure: false,\n inputs: [\n {\n name: 'exec',\n displayName: '',\n type: 'exec'\n },\n {\n name: 'id',\n displayName: 'Timer ID',\n type: 'string',\n defaultValue: ''\n }\n ],\n outputs: [\n {\n name: 'exec',\n displayName: '',\n type: 'exec'\n }\n ],\n color: '#00bcd4'\n};\n\n/**\n * @zh CancelTimer 节点执行器\n * @en CancelTimer node executor\n */\nexport class CancelTimerExecutor implements INodeExecutor {\n execute(node: BlueprintNode, context: unknown): ExecutionResult {\n const ctx = context as TimerContext;\n const id = ctx.evaluateInput(node.id, 'id', '') as string;\n\n if (id && ctx.timerService) {\n ctx.timerService.cancelById(id);\n }\n\n return {\n outputs: {},\n nextExec: 'exec'\n };\n }\n}\n\n// =============================================================================\n// GetTimerRemaining 节点 | GetTimerRemaining Node\n// =============================================================================\n\n/**\n * @zh GetTimerRemaining 节点模板\n * @en GetTimerRemaining node template\n */\nexport const GetTimerRemainingTemplate: BlueprintNodeTemplate = {\n type: 'GetTimerRemaining',\n title: 'Get Timer Remaining',\n category: 'time',\n description: 'Get remaining time for a timer / 获取定时器剩余时间',\n keywords: ['timer', 'remaining', 'time', 'left'],\n menuPath: ['Timer', 'Get Timer Remaining'],\n isPure: true,\n inputs: [\n {\n name: 'id',\n displayName: 'Timer ID',\n type: 'string',\n defaultValue: ''\n }\n ],\n outputs: [\n {\n name: 'remaining',\n displayName: 'Remaining (ms)',\n type: 'float'\n },\n {\n name: 'exists',\n displayName: 'Exists',\n type: 'bool'\n }\n ],\n color: '#00bcd4'\n};\n\n/**\n * @zh GetTimerRemaining 节点执行器\n * @en GetTimerRemaining node executor\n */\nexport class GetTimerRemainingExecutor implements INodeExecutor {\n execute(node: BlueprintNode, context: unknown): ExecutionResult {\n const ctx = context as TimerContext;\n const id = ctx.evaluateInput(node.id, 'id', '') as string;\n\n const info = id ? ctx.timerService?.getTimerInfo(id) : null;\n\n return {\n outputs: {\n remaining: info?.remaining ?? 0,\n exists: info !== null\n }\n };\n }\n}\n\n// =============================================================================\n// 节点定义集合 | Node Definition Collection\n// =============================================================================\n\n/**\n * @zh 定时器节点定义\n * @en Timer node definitions\n */\nexport const TimerNodeDefinitions = [\n { template: StartCooldownTemplate, executor: new StartCooldownExecutor() },\n { template: IsCooldownReadyTemplate, executor: new IsCooldownReadyExecutor() },\n { template: GetCooldownProgressTemplate, executor: new GetCooldownProgressExecutor() },\n { template: ResetCooldownTemplate, executor: new ResetCooldownExecutor() },\n { template: GetCooldownInfoTemplate, executor: new GetCooldownInfoExecutor() },\n { template: HasTimerTemplate, executor: new HasTimerExecutor() },\n { template: CancelTimerTemplate, executor: new CancelTimerExecutor() },\n { template: GetTimerRemainingTemplate, executor: new GetTimerRemainingExecutor() }\n];\n"],"mappings":"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","names":["TimerHandleImpl","timer","id","isValid","cancelled","cancel","TimerService","config","timers","Map","cooldowns","maxTimers","maxCooldowns","schedule","delay","callback","cancelById","size","Error","remaining","Math","max","repeating","interval","set","scheduleRepeating","immediate","safeInterval","handle","delete","get","hasTimer","undefined","getTimerInfo","startCooldown","duration","has","safeDuration","isOnCooldown","cooldown","isCooldownReady","getCooldownRemaining","getCooldownProgress","elapsed","min","getCooldownInfo","progress","isReady","resetCooldown","clearAllCooldowns","clear","update","deltaTime","updateTimers","updateCooldowns","toRemove","push","error","console","values","activeTimerCount","activeCooldownCount","getActiveTimerIds","Array","from","keys","getActiveCooldownIds","createTimerService","createServiceToken","TimerServiceToken","StartCooldownTemplate","type","title","category","description","keywords","menuPath","isPure","inputs","name","displayName","defaultValue","outputs","color","StartCooldownExecutor","execute","node","context","ctx","id","evaluateInput","duration","timerService","startCooldown","nextExec","IsCooldownReadyTemplate","IsCooldownReadyExecutor","isReady","isCooldownReady","isOnCooldown","GetCooldownProgressTemplate","GetCooldownProgressExecutor","progress","getCooldownProgress","remaining","getCooldownRemaining","ResetCooldownTemplate","ResetCooldownExecutor","resetCooldown","GetCooldownInfoTemplate","GetCooldownInfoExecutor","info","getCooldownInfo","exists","HasTimerTemplate","HasTimerExecutor","hasTimer","CancelTimerTemplate","CancelTimerExecutor","cancelById","GetTimerRemainingTemplate","GetTimerRemainingExecutor","getTimerInfo","TimerNodeDefinitions","template","executor"]}
|
package/module.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "timer",
|
|
3
|
+
"name": "@esengine/timer",
|
|
4
|
+
"globalKey": "timer",
|
|
5
|
+
"displayName": "Timer & Cooldown",
|
|
6
|
+
"description": "定时器和冷却系统 | Timer and cooldown system",
|
|
7
|
+
"version": "1.0.0",
|
|
8
|
+
"category": "Other",
|
|
9
|
+
"icon": "Timer",
|
|
10
|
+
"tags": ["timer", "cooldown", "delay", "schedule"],
|
|
11
|
+
"isCore": false,
|
|
12
|
+
"defaultEnabled": true,
|
|
13
|
+
"isEngineModule": true,
|
|
14
|
+
"canContainContent": false,
|
|
15
|
+
"platforms": ["web", "desktop"],
|
|
16
|
+
"dependencies": ["core"],
|
|
17
|
+
"exports": {
|
|
18
|
+
"components": [],
|
|
19
|
+
"systems": []
|
|
20
|
+
},
|
|
21
|
+
"outputPath": "dist/index.js",
|
|
22
|
+
"pluginExport": "TimerPlugin"
|
|
23
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@esengine/timer",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Timer and cooldown system for ECS Framework / ECS 框架的定时器和冷却系统",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"module.json"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"tslib": "^2.8.1"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^20.19.17",
|
|
24
|
+
"rimraf": "^5.0.0",
|
|
25
|
+
"tsup": "^8.0.0",
|
|
26
|
+
"typescript": "^5.8.3",
|
|
27
|
+
"@esengine/ecs-framework": "2.4.2",
|
|
28
|
+
"@esengine/blueprint": "1.0.0",
|
|
29
|
+
"@esengine/build-config": "1.0.0"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup",
|
|
36
|
+
"build:watch": "tsup --watch",
|
|
37
|
+
"type-check": "tsc --noEmit",
|
|
38
|
+
"clean": "rimraf dist"
|
|
39
|
+
}
|
|
40
|
+
}
|