@mclawnet/agent 0.6.19 → 0.6.21

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 (66) hide show
  1. package/dist/{chunk-RO47ET27.js → chunk-M2CDVPQF.js} +2 -2
  2. package/dist/{chunk-CBZIH6FY.js → chunk-PJ5M6Q36.js} +2 -2
  3. package/dist/chunk-PJ5M6Q36.js.map +1 -0
  4. package/dist/{chunk-MSDIRBXF.js → chunk-RIK7IXSW.js} +2 -2
  5. package/dist/index.js +2 -2
  6. package/dist/{linux-6AR7SXHW.js → linux-IHA4O633.js} +3 -3
  7. package/dist/{macos-BTP5JW3U.js → macos-G4VK2253.js} +8 -3
  8. package/dist/macos-G4VK2253.js.map +1 -0
  9. package/dist/service/index.js +5 -5
  10. package/dist/service/macos.d.ts.map +1 -1
  11. package/dist/start.js +2 -2
  12. package/dist/{windows-IQNSUMN6.js → windows-P6U3JLUZ.js} +3 -3
  13. package/package.json +4 -4
  14. package/skills/cocos-creator-3x-cn/SKILL.md +475 -0
  15. package/skills/cocos-creator-3x-cn/references/framework/asset-management.md +322 -0
  16. package/skills/cocos-creator-3x-cn/references/framework/component-system.md +348 -0
  17. package/skills/cocos-creator-3x-cn/references/framework/event-patterns.md +410 -0
  18. package/skills/cocos-creator-3x-cn/references/framework/playable-optimization.md +257 -0
  19. package/skills/cocos-creator-3x-cn/references/language/performance.md +363 -0
  20. package/skills/cocos-creator-3x-cn/references/language/quality-hygiene.md +307 -0
  21. package/skills/cocos-creator-3x-cn/references/review/architecture-review.md +183 -0
  22. package/skills/cocos-creator-3x-cn/references/review/quality-review.md +251 -0
  23. package/skills/cocos-performance-optimizer/SKILL.md +214 -0
  24. package/skills/game-development/2d-games/SKILL.md +129 -0
  25. package/skills/game-development/3d-games/SKILL.md +145 -0
  26. package/skills/game-development/SKILL.md +175 -0
  27. package/skills/game-development/game-art/SKILL.md +195 -0
  28. package/skills/game-development/game-audio/SKILL.md +200 -0
  29. package/skills/game-development/game-design/SKILL.md +139 -0
  30. package/skills/game-development/mobile-games/SKILL.md +118 -0
  31. package/skills/game-development/multiplayer/SKILL.md +142 -0
  32. package/skills/game-development/pc-games/SKILL.md +154 -0
  33. package/skills/game-development/vr-ar/SKILL.md +133 -0
  34. package/skills/game-development/web-games/SKILL.md +160 -0
  35. package/skills/game-engine/SKILL.md +140 -0
  36. package/skills/game-engine/assets/2d-maze-game.md +528 -0
  37. package/skills/game-engine/assets/2d-platform-game.md +1855 -0
  38. package/skills/game-engine/assets/gameBase-template-repo.md +310 -0
  39. package/skills/game-engine/assets/paddle-game-template.md +1528 -0
  40. package/skills/game-engine/assets/simple-2d-engine.md +507 -0
  41. package/skills/game-engine/references/3d-web-games.md +754 -0
  42. package/skills/game-engine/references/algorithms.md +843 -0
  43. package/skills/game-engine/references/basics.md +343 -0
  44. package/skills/game-engine/references/game-control-mechanisms.md +617 -0
  45. package/skills/game-engine/references/game-engine-core-principles.md +695 -0
  46. package/skills/game-engine/references/game-publishing.md +352 -0
  47. package/skills/game-engine/references/techniques.md +894 -0
  48. package/skills/game-engine/references/terminology.md +354 -0
  49. package/skills/game-engine/references/web-apis.md +1394 -0
  50. package/skills/theone-cocos-standards/SKILL.md +557 -0
  51. package/skills/theone-cocos-standards/references/framework/component-system.md +645 -0
  52. package/skills/theone-cocos-standards/references/framework/event-patterns.md +433 -0
  53. package/skills/theone-cocos-standards/references/framework/playable-optimization.md +429 -0
  54. package/skills/theone-cocos-standards/references/framework/size-optimization.md +308 -0
  55. package/skills/theone-cocos-standards/references/language/modern-typescript.md +658 -0
  56. package/skills/theone-cocos-standards/references/language/performance.md +580 -0
  57. package/skills/theone-cocos-standards/references/language/quality-hygiene.md +582 -0
  58. package/skills/theone-cocos-standards/references/review/architecture-review.md +250 -0
  59. package/skills/theone-cocos-standards/references/review/performance-review.md +288 -0
  60. package/skills/theone-cocos-standards/references/review/quality-review.md +239 -0
  61. package/dist/chunk-CBZIH6FY.js.map +0 -1
  62. package/dist/macos-BTP5JW3U.js.map +0 -1
  63. /package/dist/{chunk-RO47ET27.js.map → chunk-M2CDVPQF.js.map} +0 -0
  64. /package/dist/{chunk-MSDIRBXF.js.map → chunk-RIK7IXSW.js.map} +0 -0
  65. /package/dist/{linux-6AR7SXHW.js.map → linux-IHA4O633.js.map} +0 -0
  66. /package/dist/{windows-IQNSUMN6.js.map → windows-P6U3JLUZ.js.map} +0 -0
@@ -0,0 +1,433 @@
1
+ # Cocos Creator Event Patterns
2
+
3
+ ## EventDispatcher Pattern (Custom Events)
4
+
5
+ ```typescript
6
+ import { _decorator, Component, EventTarget } from 'cc';
7
+ const { ccclass } = _decorator;
8
+
9
+ // ✅ EXCELLENT: Centralized event system
10
+ export enum GameEvent {
11
+ SCORE_CHANGED = 'score_changed',
12
+ LEVEL_COMPLETE = 'level_complete',
13
+ PLAYER_DIED = 'player_died',
14
+ ENEMY_SPAWNED = 'enemy_spawned',
15
+ }
16
+
17
+ export interface ScoreChangedEvent {
18
+ oldScore: number;
19
+ newScore: number;
20
+ combo: number;
21
+ }
22
+
23
+ export interface LevelCompleteEvent {
24
+ level: number;
25
+ stars: number;
26
+ time: number;
27
+ }
28
+
29
+ @ccclass('EventManager')
30
+ export class EventManager extends Component {
31
+ private static instance: EventManager | null = null;
32
+ private readonly eventTarget: EventTarget = new EventTarget();
33
+
34
+ protected onLoad(): void {
35
+ if (EventManager.instance) {
36
+ throw new Error('EventManager: instance already exists');
37
+ }
38
+ EventManager.instance = this;
39
+ }
40
+
41
+ protected onDestroy(): void {
42
+ this.eventTarget.clear();
43
+ EventManager.instance = null;
44
+ }
45
+
46
+ // ✅ EXCELLENT: Type-safe emit
47
+ public static emit<T>(event: GameEvent, data?: T): void {
48
+ if (!EventManager.instance) {
49
+ throw new Error('EventManager: instance not initialized');
50
+ }
51
+ EventManager.instance.eventTarget.emit(event, data);
52
+ }
53
+
54
+ // ✅ EXCELLENT: Type-safe subscribe
55
+ public static on<T>(event: GameEvent, callback: (data: T) => void, target?: any): void {
56
+ if (!EventManager.instance) {
57
+ throw new Error('EventManager: instance not initialized');
58
+ }
59
+ EventManager.instance.eventTarget.on(event, callback, target);
60
+ }
61
+
62
+ // ✅ EXCELLENT: Type-safe unsubscribe
63
+ public static off<T>(event: GameEvent, callback: (data: T) => void, target?: any): void {
64
+ if (!EventManager.instance) {
65
+ throw new Error('EventManager: instance not initialized');
66
+ }
67
+ EventManager.instance.eventTarget.off(event, callback, target);
68
+ }
69
+
70
+ // ✅ EXCELLENT: Once (auto-unsubscribe after first call)
71
+ public static once<T>(event: GameEvent, callback: (data: T) => void, target?: any): void {
72
+ if (!EventManager.instance) {
73
+ throw new Error('EventManager: instance not initialized');
74
+ }
75
+ EventManager.instance.eventTarget.once(event, callback, target);
76
+ }
77
+ }
78
+
79
+ // Usage in component
80
+ @ccclass('ScoreManager')
81
+ export class ScoreManager extends Component {
82
+ private currentScore: number = 0;
83
+
84
+ public addScore(points: number): void {
85
+ const oldScore = this.currentScore;
86
+ this.currentScore += points;
87
+
88
+ // ✅ EXCELLENT: Emit typed event
89
+ EventManager.emit<ScoreChangedEvent>(GameEvent.SCORE_CHANGED, {
90
+ oldScore,
91
+ newScore: this.currentScore,
92
+ combo: 1,
93
+ });
94
+ }
95
+ }
96
+
97
+ // Subscriber component
98
+ @ccclass('ScoreDisplay')
99
+ export class ScoreDisplay extends Component {
100
+ protected onEnable(): void {
101
+ // ✅ EXCELLENT: Subscribe in onEnable
102
+ EventManager.on<ScoreChangedEvent>(GameEvent.SCORE_CHANGED, this.onScoreChanged, this);
103
+ }
104
+
105
+ protected onDisable(): void {
106
+ // ✅ CRITICAL: Always unsubscribe in onDisable
107
+ EventManager.off<ScoreChangedEvent>(GameEvent.SCORE_CHANGED, this.onScoreChanged, this);
108
+ }
109
+
110
+ private onScoreChanged(data: ScoreChangedEvent): void {
111
+ console.log(`Score: ${data.oldScore} → ${data.newScore}`);
112
+ this.updateDisplay(data.newScore);
113
+ }
114
+
115
+ private updateDisplay(score: number): void {
116
+ // Update UI
117
+ }
118
+ }
119
+
120
+ // ❌ WRONG: No unsubscription (memory leak)
121
+ protected onEnable(): void {
122
+ EventManager.on<ScoreChangedEvent>(GameEvent.SCORE_CHANGED, this.onScoreChanged, this);
123
+ }
124
+
125
+ // Missing onDisable - memory leak!
126
+
127
+ // ❌ WRONG: String-based events (not type-safe)
128
+ EventManager.emit('score_changed', { score: 100 }); // Typo-prone
129
+ ```
130
+
131
+ ## Node Event System (Built-in Events)
132
+
133
+ ```typescript
134
+ import { _decorator, Component, Node, EventTouch, EventKeyboard } from 'cc';
135
+ const { ccclass, property } = _decorator;
136
+
137
+ @ccclass('TouchHandler')
138
+ export class TouchHandler extends Component {
139
+ @property(Node)
140
+ private readonly buttonNode: Node | null = null;
141
+
142
+ // ✅ EXCELLENT: Touch event handling
143
+ protected onEnable(): void {
144
+ if (!this.buttonNode) return;
145
+
146
+ this.buttonNode.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
147
+ this.buttonNode.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
148
+ this.buttonNode.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
149
+ this.buttonNode.on(Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
150
+ }
151
+
152
+ protected onDisable(): void {
153
+ if (!this.buttonNode) return;
154
+
155
+ this.buttonNode.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
156
+ this.buttonNode.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
157
+ this.buttonNode.off(Node.EventType.TOUCH_END, this.onTouchEnd, this);
158
+ this.buttonNode.off(Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
159
+ }
160
+
161
+ private onTouchStart(event: EventTouch): void {
162
+ const location = event.getUILocation();
163
+ console.log(`Touch start at: ${location.x}, ${location.y}`);
164
+ }
165
+
166
+ private onTouchMove(event: EventTouch): void {
167
+ const delta = event.getUIDelta();
168
+ console.log(`Touch delta: ${delta.x}, ${delta.y}`);
169
+ }
170
+
171
+ private onTouchEnd(event: EventTouch): void {
172
+ console.log('Touch ended');
173
+ }
174
+
175
+ private onTouchCancel(event: EventTouch): void {
176
+ console.log('Touch cancelled');
177
+ }
178
+ }
179
+
180
+ // ✅ EXCELLENT: Keyboard event handling
181
+ @ccclass('KeyboardHandler')
182
+ export class KeyboardHandler extends Component {
183
+ protected onEnable(): void {
184
+ this.node.on(Node.EventType.KEY_DOWN, this.onKeyDown, this);
185
+ this.node.on(Node.EventType.KEY_UP, this.onKeyUp, this);
186
+ }
187
+
188
+ protected onDisable(): void {
189
+ this.node.off(Node.EventType.KEY_DOWN, this.onKeyDown, this);
190
+ this.node.off(Node.EventType.KEY_UP, this.onKeyUp, this);
191
+ }
192
+
193
+ private onKeyDown(event: EventKeyboard): void {
194
+ switch (event.keyCode) {
195
+ case macro.KEY.w:
196
+ case macro.KEY.up:
197
+ this.moveUp();
198
+ break;
199
+ case macro.KEY.s:
200
+ case macro.KEY.down:
201
+ this.moveDown();
202
+ break;
203
+ }
204
+ }
205
+
206
+ private onKeyUp(event: EventKeyboard): void {
207
+ this.stopMovement();
208
+ }
209
+ }
210
+ ```
211
+
212
+ ## Event Cleanup Patterns
213
+
214
+ ```typescript
215
+ import { _decorator, Component, Node } from 'cc';
216
+ const { ccclass, property } = _decorator;
217
+
218
+ // ✅ EXCELLENT: Comprehensive cleanup pattern
219
+ @ccclass('CompleteEventCleanup')
220
+ export class CompleteEventCleanup extends Component {
221
+ @property(Node)
222
+ private readonly targetNode: Node | null = null;
223
+
224
+ // Track registered listeners for complete cleanup
225
+ private readonly registeredListeners: Array<{
226
+ node: Node;
227
+ eventType: string;
228
+ callback: Function;
229
+ }> = [];
230
+
231
+ protected onEnable(): void {
232
+ if (!this.targetNode) return;
233
+
234
+ // Register and track listeners
235
+ this.registerListener(
236
+ this.targetNode,
237
+ Node.EventType.TOUCH_START,
238
+ this.onTouchStart
239
+ );
240
+ this.registerListener(
241
+ this.node,
242
+ Node.EventType.CHILD_ADDED,
243
+ this.onChildAdded
244
+ );
245
+
246
+ // Subscribe to global events
247
+ EventManager.on(GameEvent.LEVEL_COMPLETE, this.onLevelComplete, this);
248
+ }
249
+
250
+ protected onDisable(): void {
251
+ // Unregister all tracked listeners
252
+ for (const { node, eventType, callback } of this.registeredListeners) {
253
+ node.off(eventType, callback, this);
254
+ }
255
+ this.registeredListeners.length = 0;
256
+
257
+ // Unsubscribe from global events
258
+ EventManager.off(GameEvent.LEVEL_COMPLETE, this.onLevelComplete, this);
259
+ }
260
+
261
+ private registerListener(node: Node, eventType: string, callback: Function): void {
262
+ node.on(eventType, callback, this);
263
+ this.registeredListeners.push({ node, eventType, callback });
264
+ }
265
+
266
+ private onTouchStart(event: EventTouch): void {
267
+ // Handle touch
268
+ }
269
+
270
+ private onChildAdded(child: Node): void {
271
+ // Handle child added
272
+ }
273
+
274
+ private onLevelComplete(): void {
275
+ // Handle level complete
276
+ }
277
+ }
278
+
279
+ // ✅ EXCELLENT: Automatic cleanup with disposable pattern
280
+ interface IDisposable {
281
+ dispose(): void;
282
+ }
283
+
284
+ class EventSubscription implements IDisposable {
285
+ constructor(
286
+ private readonly eventManager: EventManager,
287
+ private readonly event: GameEvent,
288
+ private readonly callback: Function,
289
+ private readonly target: any
290
+ ) {}
291
+
292
+ public dispose(): void {
293
+ EventManager.off(this.event, this.callback as any, this.target);
294
+ }
295
+ }
296
+
297
+ @ccclass('DisposablePattern')
298
+ export class DisposablePattern extends Component {
299
+ private readonly subscriptions: IDisposable[] = [];
300
+
301
+ protected onEnable(): void {
302
+ // ✅ EXCELLENT: Track subscriptions for auto-cleanup
303
+ this.subscriptions.push(
304
+ new EventSubscription(
305
+ EventManager.instance!,
306
+ GameEvent.SCORE_CHANGED,
307
+ this.onScoreChanged,
308
+ this
309
+ )
310
+ );
311
+ }
312
+
313
+ protected onDisable(): void {
314
+ // ✅ EXCELLENT: Dispose all subscriptions
315
+ for (const subscription of this.subscriptions) {
316
+ subscription.dispose();
317
+ }
318
+ this.subscriptions.length = 0;
319
+ }
320
+
321
+ private onScoreChanged(data: ScoreChangedEvent): void {
322
+ // Handle score change
323
+ }
324
+ }
325
+ ```
326
+
327
+ ## Event Performance Best Practices
328
+
329
+ ```typescript
330
+ import { _decorator, Component } from 'cc';
331
+ const { ccclass } = _decorator;
332
+
333
+ @ccclass('PerformanceOptimizedEvents')
334
+ export class PerformanceOptimizedEvents extends Component {
335
+ // ✅ EXCELLENT: Throttle frequent events
336
+ private lastEmitTime: number = 0;
337
+ private static readonly EMIT_THROTTLE_MS: number = 100; // Max 10 events/second
338
+
339
+ public emitThrottled(event: GameEvent, data: any): void {
340
+ const now = Date.now();
341
+ if (now - this.lastEmitTime >= PerformanceOptimizedEvents.EMIT_THROTTLE_MS) {
342
+ EventManager.emit(event, data);
343
+ this.lastEmitTime = now;
344
+ }
345
+ }
346
+
347
+ // ✅ EXCELLENT: Batch events to reduce overhead
348
+ private readonly pendingEvents: Array<{ event: GameEvent; data: any }> = [];
349
+ private batchEmitScheduled: boolean = false;
350
+
351
+ public emitBatched(event: GameEvent, data: any): void {
352
+ this.pendingEvents.push({ event, data });
353
+
354
+ if (!this.batchEmitScheduled) {
355
+ this.batchEmitScheduled = true;
356
+ this.scheduleOnce(() => {
357
+ this.flushBatchedEvents();
358
+ }, 0);
359
+ }
360
+ }
361
+
362
+ private flushBatchedEvents(): void {
363
+ for (const { event, data } of this.pendingEvents) {
364
+ EventManager.emit(event, data);
365
+ }
366
+ this.pendingEvents.length = 0;
367
+ this.batchEmitScheduled = false;
368
+ }
369
+
370
+ // ✅ EXCELLENT: Debounce events (emit only after quiet period)
371
+ private debounceTimer: number | null = null;
372
+ private static readonly DEBOUNCE_MS: number = 300;
373
+
374
+ public emitDebounced(event: GameEvent, data: any): void {
375
+ if (this.debounceTimer !== null) {
376
+ clearTimeout(this.debounceTimer);
377
+ }
378
+
379
+ this.debounceTimer = setTimeout(() => {
380
+ EventManager.emit(event, data);
381
+ this.debounceTimer = null;
382
+ }, PerformanceOptimizedEvents.DEBOUNCE_MS) as any;
383
+ }
384
+ }
385
+
386
+ // ❌ WRONG: Emitting events in update loop
387
+ protected update(dt: number): void {
388
+ // Emits 60 events per second!
389
+ EventManager.emit(GameEvent.PLAYER_MOVED, this.node.position);
390
+ }
391
+
392
+ // ✅ BETTER: Throttle or emit only on significant changes
393
+ private lastPosition: Vec3 = new Vec3();
394
+ private static readonly MOVE_THRESHOLD: number = 1.0;
395
+
396
+ protected update(dt: number): void {
397
+ const distance = Vec3.distance(this.node.position, this.lastPosition);
398
+
399
+ if (distance >= PerformanceOptimizedEvents.MOVE_THRESHOLD) {
400
+ EventManager.emit(GameEvent.PLAYER_MOVED, this.node.position.clone());
401
+ this.lastPosition.set(this.node.position);
402
+ }
403
+ }
404
+ ```
405
+
406
+ ## Summary: Event Pattern Checklist
407
+
408
+ **EventDispatcher (Custom Events):**
409
+ - [ ] Use centralized EventManager with EventTarget
410
+ - [ ] Define event names as enum (not strings)
411
+ - [ ] Use typed event data interfaces
412
+ - [ ] Subscribe in onEnable(), unsubscribe in onDisable()
413
+ - [ ] Always pass `this` as target parameter for proper cleanup
414
+
415
+ **Node Events (Built-in):**
416
+ - [ ] Use Node.EventType constants (TOUCH_START, KEY_DOWN, etc.)
417
+ - [ ] Register listeners in onEnable()
418
+ - [ ] Unregister listeners in onDisable() with same parameters
419
+ - [ ] Handle EventTouch and EventKeyboard properly
420
+
421
+ **Event Cleanup:**
422
+ - [ ] Track all registered listeners for complete cleanup
423
+ - [ ] Unregister in both onDisable() and onDestroy()
424
+ - [ ] Use disposable pattern for automatic cleanup
425
+ - [ ] Clear event collections in onDestroy()
426
+
427
+ **Performance:**
428
+ - [ ] Throttle frequent events (max 10/second)
429
+ - [ ] Batch events to reduce overhead
430
+ - [ ] Debounce events for user input
431
+ - [ ] Never emit events in update() without throttling
432
+
433
+ **Always unsubscribe from events to prevent memory leaks.**