@ives_xxz/framework 1.4.16 → 1.5.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.
- package/FW.d.ts +49 -42
- package/FrameworkBase.ts +63 -0
- package/FrameworkBase.ts.meta +10 -0
- package/config/FWSystemConfig.ts +18 -0
- package/controller/FWLayerController.ts +3 -2
- package/data/FWData.ts +2 -5
- package/define/FWSystemDefine.ts +5 -0
- package/entry/FWEntry.ts +4 -4
- package/logic/FWLogic.ts +4 -7
- package/manager/FWAssetManager.ts +62 -67
- package/manager/FWAudioManager.ts +230 -185
- package/manager/FWBundleManager.ts +5 -6
- package/manager/FWEventManager.ts +91 -2
- package/manager/FWManager.ts +2 -56
- package/manager/FWObjectManager.ts +100 -33
- package/manager/FWPerformanceManager.ts +32 -34
- package/manager/FWPromiseManager.ts +0 -1
- package/manager/FWResManager.ts +5 -5
- package/manager/FWTimeManager.ts +12 -40
- package/package.json +1 -1
- package/service/FWService.ts +5 -52
- package/service/http/FWHttp.ts +7 -7
- package/service/socket/FWSocket.ts +0 -1
|
@@ -1,29 +1,54 @@
|
|
|
1
1
|
import { FWManager } from './FWManager';
|
|
2
|
-
import Framework from '../Framework';
|
|
3
2
|
import FWLog from '../log/FWLog';
|
|
3
|
+
import { FWSystemDefine } from '../define/FWSystemDefine';
|
|
4
|
+
|
|
5
|
+
class FWAudioData {
|
|
6
|
+
clip: cc.AudioClip;
|
|
7
|
+
volume: number = 1;
|
|
8
|
+
loop: boolean = false;
|
|
9
|
+
cb?: (id: number) => void;
|
|
10
|
+
tag?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class FWAudioPoolItem {
|
|
14
|
+
constructor(public audioId: number, public startTime: number, public tag?: string) {}
|
|
15
|
+
}
|
|
4
16
|
|
|
5
17
|
export default class FWAudioManager extends FWManager implements FW.AudioManager {
|
|
6
|
-
/**背景音量 */
|
|
7
18
|
musicVolume: number = 1;
|
|
8
|
-
/**音效音量 */
|
|
9
19
|
effectsVolume: number = 1;
|
|
10
|
-
/**播放音效的音量 */
|
|
11
20
|
soundVolume: number = 1;
|
|
12
21
|
|
|
13
|
-
|
|
22
|
+
private audioPool: Map<number, FWAudioPoolItem> = new Map();
|
|
23
|
+
private maxConcurrentAudio: number = 10;
|
|
24
|
+
private cleanupInterval: number = 5;
|
|
14
25
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
26
|
+
public initialize(): void {
|
|
27
|
+
this.autoClear();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 播放背景音乐
|
|
32
|
+
*/
|
|
33
|
+
async playMusic(path: string, volume?: number, loop?: boolean): Promise<void>;
|
|
34
|
+
async playMusic(music: cc.AudioClip, volume?: number, loop?: boolean): Promise<void>;
|
|
35
|
+
async playMusic(assetProperty: FW.AssetProperty, volume?: number, loop?: boolean): Promise<void>;
|
|
36
|
+
async playMusic(): Promise<void> {
|
|
19
37
|
try {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
38
|
+
const audioData = await this.processAudioArguments(
|
|
39
|
+
arguments,
|
|
40
|
+
FWSystemDefine.FWAudioType.MUSIC,
|
|
41
|
+
);
|
|
42
|
+
if (!audioData.clip) return;
|
|
43
|
+
|
|
44
|
+
const volume = audioData.volume ?? this.musicVolume;
|
|
45
|
+
const loop = audioData.loop ?? true;
|
|
46
|
+
|
|
47
|
+
cc.audioEngine.stopMusic();
|
|
48
|
+
const id = cc.audioEngine.playMusic(audioData.clip, loop);
|
|
26
49
|
cc.audioEngine.setVolume(id, volume);
|
|
50
|
+
|
|
51
|
+
FWLog.debug(`播放背景音乐: ${this.getAudioName(audioData.clip)}`);
|
|
27
52
|
} catch (e) {
|
|
28
53
|
FWLog.error('播放音乐失败:', e);
|
|
29
54
|
}
|
|
@@ -32,255 +57,275 @@ export default class FWAudioManager extends FWManager implements FW.AudioManager
|
|
|
32
57
|
stopMusic(): void {
|
|
33
58
|
cc.audioEngine.stopMusic();
|
|
34
59
|
}
|
|
60
|
+
|
|
35
61
|
pauseMusic(): void {
|
|
36
62
|
cc.audioEngine.pauseMusic();
|
|
37
63
|
}
|
|
64
|
+
|
|
38
65
|
resumeMusic(): void {
|
|
39
66
|
cc.audioEngine.resumeMusic();
|
|
40
67
|
}
|
|
41
|
-
|
|
68
|
+
|
|
69
|
+
/** 设置背景音效是否静音 */
|
|
42
70
|
setMusicMute(mute: boolean): void {
|
|
43
|
-
|
|
44
|
-
this.musicVolume = 1;
|
|
45
|
-
} else {
|
|
46
|
-
this.musicVolume = 0;
|
|
47
|
-
}
|
|
71
|
+
this.musicVolume = mute ? 0 : 1;
|
|
48
72
|
cc.audioEngine.setMusicVolume(this.musicVolume);
|
|
49
73
|
}
|
|
50
74
|
|
|
75
|
+
/**
|
|
76
|
+
* 播放音效
|
|
77
|
+
*/
|
|
51
78
|
async play(
|
|
52
79
|
path: string,
|
|
53
80
|
cb?: (id: number) => void,
|
|
54
81
|
volume?: number,
|
|
55
82
|
loop?: boolean,
|
|
83
|
+
tag?: string,
|
|
56
84
|
): Promise<number>;
|
|
57
85
|
async play(
|
|
58
86
|
audio: cc.AudioClip,
|
|
59
87
|
cb?: (id: number) => void,
|
|
60
88
|
volume?: number,
|
|
61
89
|
loop?: boolean,
|
|
90
|
+
tag?: string,
|
|
62
91
|
): Promise<number>;
|
|
63
92
|
async play(
|
|
64
93
|
assetProperty: FW.AssetProperty,
|
|
65
94
|
cb?: (id: number) => void,
|
|
66
95
|
volume?: number,
|
|
67
96
|
loop?: boolean,
|
|
97
|
+
tag?: string,
|
|
68
98
|
): Promise<number>;
|
|
69
99
|
async play(): Promise<number> {
|
|
70
100
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
101
|
+
if (this.audioPool.size >= this.maxConcurrentAudio) {
|
|
102
|
+
this.clearFinishedAudio();
|
|
103
|
+
if (this.audioPool.size >= this.maxConcurrentAudio) {
|
|
104
|
+
FWLog.warn('音频池已满,无法播放新音频');
|
|
105
|
+
return -1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const audioData = await this.processAudioArguments(
|
|
110
|
+
arguments,
|
|
111
|
+
FWSystemDefine.FWAudioType.SOUND,
|
|
76
112
|
);
|
|
77
|
-
if (!
|
|
78
|
-
|
|
79
|
-
const volume =
|
|
80
|
-
const loop =
|
|
81
|
-
const
|
|
113
|
+
if (!audioData.clip) return -1;
|
|
114
|
+
|
|
115
|
+
const volume = (audioData.volume ?? this.soundVolume) * this.effectsVolume;
|
|
116
|
+
const loop = audioData.loop ?? false;
|
|
117
|
+
const tag = audioData.tag;
|
|
118
|
+
|
|
119
|
+
const id = cc.audioEngine.play(audioData.clip, loop, volume);
|
|
120
|
+
|
|
121
|
+
this.audioPool.set(id, new FWAudioPoolItem(id, Date.now(), tag));
|
|
122
|
+
|
|
82
123
|
cc.audioEngine.setFinishCallback(id, () => {
|
|
83
|
-
|
|
124
|
+
audioData.cb?.(id);
|
|
125
|
+
this.audioPool.delete(id);
|
|
84
126
|
});
|
|
127
|
+
|
|
85
128
|
return id;
|
|
86
129
|
} catch (e) {
|
|
87
130
|
FWLog.error('播放音效失败:', e);
|
|
131
|
+
return -1;
|
|
88
132
|
}
|
|
89
133
|
}
|
|
134
|
+
|
|
90
135
|
/**
|
|
91
|
-
*
|
|
92
|
-
* @param id 停止
|
|
136
|
+
* 停止指定音效
|
|
93
137
|
*/
|
|
94
|
-
|
|
95
|
-
|
|
138
|
+
stop(id: number): void {
|
|
139
|
+
if (this.audioPool.has(id)) {
|
|
140
|
+
cc.audioEngine.stop(id);
|
|
141
|
+
this.audioPool.delete(id);
|
|
142
|
+
FWLog.debug(`停止音效: ID ${id}`);
|
|
143
|
+
}
|
|
96
144
|
}
|
|
145
|
+
|
|
97
146
|
pauseAll(): void {
|
|
98
147
|
cc.audioEngine.pauseAll();
|
|
148
|
+
FWLog.debug('暂停所有音效');
|
|
99
149
|
}
|
|
150
|
+
|
|
100
151
|
resumeAll(): void {
|
|
101
152
|
cc.audioEngine.resumeAll();
|
|
153
|
+
FWLog.debug('恢复所有音效');
|
|
102
154
|
}
|
|
155
|
+
|
|
103
156
|
stopAll(): void {
|
|
104
157
|
cc.audioEngine.stopAll();
|
|
158
|
+
this.audioPool.clear();
|
|
159
|
+
FWLog.debug('停止所有音效');
|
|
105
160
|
}
|
|
106
|
-
|
|
161
|
+
|
|
162
|
+
/** 设置播放音效是否静音 */
|
|
107
163
|
setSoundMute(mute: boolean): void {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
} else {
|
|
111
|
-
this.soundVolume = 0;
|
|
112
|
-
}
|
|
164
|
+
this.soundVolume = mute ? 0 : 1;
|
|
165
|
+
FWLog.debug(`音效${mute ? '静音' : '取消静音'}`);
|
|
113
166
|
}
|
|
114
167
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
async
|
|
119
|
-
async playEffect(): Promise<number> {
|
|
168
|
+
/**
|
|
169
|
+
* 预加载音频资源
|
|
170
|
+
*/
|
|
171
|
+
async preloadAudio(assetProperty: FW.AssetProperty): Promise<cc.AudioClip> {
|
|
120
172
|
try {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
173
|
+
let clip: cc.AudioClip;
|
|
174
|
+
|
|
175
|
+
if (typeof assetProperty === 'string') {
|
|
176
|
+
clip = await FW.Entry.resMgr.loadAsset<cc.AudioClip>({
|
|
177
|
+
path: assetProperty,
|
|
178
|
+
bundle: FW.Entry.bundleName,
|
|
179
|
+
});
|
|
180
|
+
} else {
|
|
181
|
+
clip = await FW.Entry.resMgr.loadAsset<cc.AudioClip>(assetProperty);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return clip;
|
|
127
185
|
} catch (e) {
|
|
128
|
-
|
|
186
|
+
return null;
|
|
129
187
|
}
|
|
130
188
|
}
|
|
131
189
|
|
|
132
190
|
/**
|
|
133
|
-
*
|
|
134
|
-
* @param effectName 声音文件名
|
|
135
|
-
* @returns
|
|
191
|
+
* 释放音频资源
|
|
136
192
|
*/
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return cc.audioEngine.stopEffect(audioID);
|
|
193
|
+
releaseAudio(assetProperty: FW.AssetProperty): void {
|
|
194
|
+
FW.Entry.resMgr.releaseAsset(assetProperty);
|
|
140
195
|
}
|
|
196
|
+
|
|
141
197
|
/**
|
|
142
|
-
*
|
|
143
|
-
* @param volume 音量
|
|
198
|
+
* 获取音频池信息
|
|
144
199
|
*/
|
|
145
|
-
|
|
146
|
-
|
|
200
|
+
getAudioPoolInfo(): { playing: number; maxConcurrent: number } {
|
|
201
|
+
return {
|
|
202
|
+
playing: this.audioPool.size,
|
|
203
|
+
maxConcurrent: this.maxConcurrentAudio,
|
|
204
|
+
};
|
|
147
205
|
}
|
|
206
|
+
|
|
148
207
|
/**
|
|
149
|
-
*
|
|
208
|
+
* 设置最大并发音频数
|
|
150
209
|
*/
|
|
151
|
-
|
|
152
|
-
|
|
210
|
+
setMaxConcurrentAudio(max: number): void {
|
|
211
|
+
this.maxConcurrentAudio = Math.max(1, max);
|
|
153
212
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 根据标签停止音效
|
|
216
|
+
*/
|
|
217
|
+
stopByTag(tag: string): void {
|
|
218
|
+
const arr: number[] = [];
|
|
219
|
+
|
|
220
|
+
this.audioPool.forEach((item, id) => {
|
|
221
|
+
if (item.tag === tag) {
|
|
222
|
+
arr.push(id);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
arr.forEach((id) => {
|
|
227
|
+
this.stop(id);
|
|
228
|
+
});
|
|
162
229
|
}
|
|
163
230
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
volume?: number,
|
|
180
|
-
loop?: boolean,
|
|
181
|
-
): Promise<{
|
|
182
|
-
clip: cc.AudioClip;
|
|
183
|
-
volume: number;
|
|
184
|
-
loop: boolean;
|
|
185
|
-
cb: (id: number) => void;
|
|
186
|
-
}>;
|
|
187
|
-
|
|
188
|
-
private async dataProcessing(
|
|
189
|
-
assetProperty: FW.AssetProperty,
|
|
190
|
-
cb?: (id: number) => void,
|
|
191
|
-
volume?: number,
|
|
192
|
-
loop?: boolean,
|
|
193
|
-
): Promise<{
|
|
194
|
-
clip: cc.AudioClip;
|
|
195
|
-
volume: number;
|
|
196
|
-
loop: boolean;
|
|
197
|
-
cb: (id: number) => void;
|
|
198
|
-
}>;
|
|
199
|
-
|
|
200
|
-
private async dataProcessing(
|
|
201
|
-
path: string,
|
|
202
|
-
volume?: number,
|
|
203
|
-
loop?: boolean,
|
|
204
|
-
): Promise<{
|
|
205
|
-
clip: cc.AudioClip;
|
|
206
|
-
volume: number;
|
|
207
|
-
loop: boolean;
|
|
208
|
-
cb: (id: number) => void;
|
|
209
|
-
}>;
|
|
210
|
-
private async dataProcessing(
|
|
211
|
-
music: cc.AudioClip,
|
|
212
|
-
volume?: number,
|
|
213
|
-
loop?: boolean,
|
|
214
|
-
): Promise<{
|
|
215
|
-
clip: cc.AudioClip;
|
|
216
|
-
volume: number;
|
|
217
|
-
loop: boolean;
|
|
218
|
-
cb: (id: number) => void;
|
|
219
|
-
}>;
|
|
220
|
-
private async dataProcessing(
|
|
221
|
-
assetProperty: FW.AssetProperty,
|
|
222
|
-
volume?: number,
|
|
223
|
-
loop?: boolean,
|
|
224
|
-
): Promise<{
|
|
225
|
-
clip: cc.AudioClip;
|
|
226
|
-
volume: number;
|
|
227
|
-
loop: boolean;
|
|
228
|
-
cb: (id: number) => void;
|
|
229
|
-
}>;
|
|
230
|
-
private async dataProcessing(): Promise<{
|
|
231
|
-
clip: cc.AudioClip;
|
|
232
|
-
volume: number;
|
|
233
|
-
loop: boolean;
|
|
234
|
-
cb: (id: number) => void;
|
|
235
|
-
}> {
|
|
236
|
-
let clip: cc.AudioClip;
|
|
237
|
-
if (typeof arguments[0] === 'string') {
|
|
238
|
-
const bundle = FW.Entry.bundleName;
|
|
239
|
-
const path = arguments[0];
|
|
240
|
-
clip = await FW.Entry.resMgr.loadAsset<cc.AudioClip>(<FW.AssetProperty>{
|
|
241
|
-
path: path,
|
|
242
|
-
bundle: bundle,
|
|
243
|
-
});
|
|
244
|
-
} else if (typeof arguments[0] === 'object') {
|
|
245
|
-
const bundle = (arguments[0] as FW.AssetProperty).bundle || FW.Entry.bundleName;
|
|
246
|
-
const path = (arguments[0] as FW.AssetProperty).path;
|
|
247
|
-
clip = await FW.Entry.resMgr.loadAsset<cc.AudioClip>(<FW.AssetProperty>{
|
|
248
|
-
path: path,
|
|
249
|
-
bundle: bundle,
|
|
250
|
-
});
|
|
251
|
-
} else if (arguments[0] instanceof cc.AudioClip) {
|
|
252
|
-
clip = arguments[0];
|
|
231
|
+
/**
|
|
232
|
+
* 处理音频参数
|
|
233
|
+
*/
|
|
234
|
+
private async processAudioArguments(
|
|
235
|
+
args: IArguments,
|
|
236
|
+
type: FWSystemDefine.FWAudioType,
|
|
237
|
+
): Promise<FWAudioData> {
|
|
238
|
+
const audioData = new FWAudioData();
|
|
239
|
+
const argsArray = Array.from(args);
|
|
240
|
+
|
|
241
|
+
if (argsArray[0] instanceof cc.AudioClip) {
|
|
242
|
+
audioData.clip = argsArray[0];
|
|
243
|
+
} else {
|
|
244
|
+
const assetProperty = this.normalizeAssetProperty(argsArray[0]);
|
|
245
|
+
audioData.clip = await this.loadAudioClip(assetProperty);
|
|
253
246
|
}
|
|
254
247
|
|
|
255
|
-
|
|
248
|
+
if (type === FWSystemDefine.FWAudioType.MUSIC) {
|
|
249
|
+
audioData.volume = argsArray[1];
|
|
250
|
+
audioData.loop = argsArray[2];
|
|
251
|
+
} else {
|
|
252
|
+
audioData.cb = argsArray[1];
|
|
253
|
+
audioData.volume = argsArray[2];
|
|
254
|
+
audioData.loop = argsArray[3];
|
|
255
|
+
audioData.tag = argsArray[4];
|
|
256
|
+
}
|
|
256
257
|
|
|
257
|
-
|
|
258
|
+
return audioData;
|
|
259
|
+
}
|
|
258
260
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
261
|
+
/**
|
|
262
|
+
* 标准化资源属性
|
|
263
|
+
*/
|
|
264
|
+
private normalizeAssetProperty(input: any): FW.AssetProperty {
|
|
265
|
+
if (typeof input === 'string') {
|
|
266
|
+
return {
|
|
267
|
+
path: input,
|
|
268
|
+
bundle: FW.Entry.bundleName,
|
|
269
|
+
};
|
|
266
270
|
}
|
|
271
|
+
return input;
|
|
272
|
+
}
|
|
267
273
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
274
|
+
/**
|
|
275
|
+
* 加载音频片段
|
|
276
|
+
*/
|
|
277
|
+
private async loadAudioClip(assetProperty: FW.AssetProperty): Promise<cc.AudioClip> {
|
|
278
|
+
try {
|
|
279
|
+
return await FW.Entry.resMgr.loadAsset<cc.AudioClip>(assetProperty);
|
|
280
|
+
} catch (e) {
|
|
281
|
+
return null;
|
|
272
282
|
}
|
|
283
|
+
}
|
|
273
284
|
|
|
274
|
-
|
|
275
|
-
|
|
285
|
+
/**
|
|
286
|
+
* 生成缓存键
|
|
287
|
+
*/
|
|
288
|
+
private getCacheKey(assetProperty: FW.AssetProperty): string {
|
|
289
|
+
if (typeof assetProperty === 'string') {
|
|
290
|
+
return `${FW.Entry.bundleName}_${assetProperty}`;
|
|
276
291
|
}
|
|
292
|
+
return `${assetProperty.bundle || FW.Entry.bundleName}_${assetProperty.path}`;
|
|
293
|
+
}
|
|
277
294
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
295
|
+
/**
|
|
296
|
+
* 获取音频名称
|
|
297
|
+
*/
|
|
298
|
+
private getAudioName(clip: cc.AudioClip): string {
|
|
299
|
+
return clip.name || '未知音频';
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* 清理已完成的音频
|
|
304
|
+
*/
|
|
305
|
+
private clearFinishedAudio(): void {
|
|
306
|
+
const currentTime = Date.now();
|
|
307
|
+
const maxAge = 30000;
|
|
308
|
+
|
|
309
|
+
this.audioPool.forEach((item, id) => {
|
|
310
|
+
if (!cc.audioEngine.getState(id)) {
|
|
311
|
+
this.audioPool.delete(id);
|
|
312
|
+
} else if (currentTime - item.startTime > maxAge) {
|
|
313
|
+
FWLog.warn(`强制停止超时音频: ID ${id}`);
|
|
314
|
+
this.stop(id);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* 启动自动清理
|
|
321
|
+
*/
|
|
322
|
+
private autoClear(): void {
|
|
323
|
+
FW.Entry.timeMgr.schedule(
|
|
324
|
+
this.clearFinishedAudio,
|
|
325
|
+
this.cleanupInterval,
|
|
326
|
+
cc.macro.REPEAT_FOREVER,
|
|
327
|
+
this,
|
|
328
|
+
);
|
|
284
329
|
}
|
|
285
330
|
|
|
286
331
|
public onDestroy(): void {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FWManager } from './FWManager';
|
|
2
2
|
import FWLog from '../log/FWLog';
|
|
3
3
|
import Framework from '../Framework';
|
|
4
|
+
import { FWSystemConfig } from '../config/FWSystemConfig';
|
|
4
5
|
|
|
5
6
|
export class FWBundleManager extends FWManager implements FW.BundleManager {
|
|
6
7
|
bundleMap: Map<string, cc.AssetManager.Bundle>;
|
|
@@ -31,11 +32,8 @@ export class FWBundleManager extends FWManager implements FW.BundleManager {
|
|
|
31
32
|
if (!bundleName) return;
|
|
32
33
|
if (this.bundleMap.has(bundleName)) return this.bundleMap.get(bundleName);
|
|
33
34
|
|
|
34
|
-
return
|
|
35
|
-
(
|
|
36
|
-
resolve: (value: cc.AssetManager.Bundle | PromiseLike<cc.AssetManager.Bundle>) => void,
|
|
37
|
-
reject: (reason?: any) => void,
|
|
38
|
-
) => {
|
|
35
|
+
return await this.invoke(
|
|
36
|
+
FW.Entry.promiseMgr.execute((resolve, reject, signal) => {
|
|
39
37
|
const remote = this.remoteBundleConfigMap.get(bundleName);
|
|
40
38
|
const url = remote ? remote.url : '';
|
|
41
39
|
const path = `${url}${bundleName}`;
|
|
@@ -54,7 +52,8 @@ export class FWBundleManager extends FWManager implements FW.BundleManager {
|
|
|
54
52
|
resolve(bundle);
|
|
55
53
|
},
|
|
56
54
|
);
|
|
57
|
-
},
|
|
55
|
+
}, FWSystemConfig.PromiseConfig.loadBundle).promise,
|
|
56
|
+
`loadBundle -> ${bundleName}`,
|
|
58
57
|
);
|
|
59
58
|
}
|
|
60
59
|
|
|
@@ -18,6 +18,7 @@ class FWObserver implements FW.Observer {
|
|
|
18
18
|
private readonly target: FW.TargetType,
|
|
19
19
|
public readonly priority: number,
|
|
20
20
|
public readonly intercept: boolean,
|
|
21
|
+
public readonly once: boolean = false,
|
|
21
22
|
) {
|
|
22
23
|
this.cb = cb;
|
|
23
24
|
this.target = target;
|
|
@@ -55,6 +56,7 @@ class FWObserver implements FW.Observer {
|
|
|
55
56
|
args10,
|
|
56
57
|
);
|
|
57
58
|
}
|
|
59
|
+
|
|
58
60
|
/**
|
|
59
61
|
* 目标比较
|
|
60
62
|
* @param target 目标对象
|
|
@@ -115,14 +117,31 @@ export default class FWEventManager implements FW.EventManager {
|
|
|
115
117
|
) {
|
|
116
118
|
const observers = this.listeners[eventName];
|
|
117
119
|
if (!observers) return;
|
|
120
|
+
|
|
118
121
|
let shouldStopPropagation = false;
|
|
119
|
-
|
|
122
|
+
const observersToRemove: FW.Observer[] = [];
|
|
123
|
+
|
|
124
|
+
const observersCopy = [...observers];
|
|
125
|
+
|
|
126
|
+
for (const observer of observersCopy) {
|
|
120
127
|
if (shouldStopPropagation) break;
|
|
128
|
+
|
|
129
|
+
if (observers.indexOf(observer) === -1) continue;
|
|
130
|
+
|
|
121
131
|
observer.notify(args1, args2, args3, args4, args5, args6, args7, args8, args9, args10);
|
|
132
|
+
|
|
133
|
+
if (observer.once) {
|
|
134
|
+
observersToRemove.push(observer);
|
|
135
|
+
}
|
|
136
|
+
|
|
122
137
|
if (observer.intercept) {
|
|
123
138
|
shouldStopPropagation = true;
|
|
124
139
|
}
|
|
125
140
|
}
|
|
141
|
+
|
|
142
|
+
if (observersToRemove.length > 0) {
|
|
143
|
+
this.removeObservers(eventName, observersToRemove);
|
|
144
|
+
}
|
|
126
145
|
}
|
|
127
146
|
|
|
128
147
|
/**
|
|
@@ -149,20 +168,26 @@ export default class FWEventManager implements FW.EventManager {
|
|
|
149
168
|
options?: {
|
|
150
169
|
priority?: FWSystemDefine.FWPriorityOrder;
|
|
151
170
|
intercept?: boolean;
|
|
171
|
+
once?: boolean;
|
|
152
172
|
},
|
|
153
173
|
) {
|
|
154
174
|
const observers = this.listeners[eventName];
|
|
155
175
|
const define = FWSystemDefine.FWPriorityOrder;
|
|
156
176
|
const priority = options?.priority === undefined ? define.NORMAL : options.priority;
|
|
157
177
|
const intercept = options?.intercept === undefined ? false : options.intercept;
|
|
158
|
-
const
|
|
178
|
+
const once = options?.once === undefined ? false : options.once;
|
|
179
|
+
|
|
180
|
+
const observer = new FWObserver(eventName, cb, target, priority, intercept, once);
|
|
181
|
+
|
|
159
182
|
if (!observers) {
|
|
160
183
|
this.listeners[eventName] = [];
|
|
161
184
|
}
|
|
185
|
+
|
|
162
186
|
const order = Object.values(define);
|
|
163
187
|
const insertIndex = this.listeners[eventName].findIndex(
|
|
164
188
|
(o) => order[o.priority] > order[priority],
|
|
165
189
|
);
|
|
190
|
+
|
|
166
191
|
if (insertIndex === -1) {
|
|
167
192
|
this.listeners[eventName].push(observer);
|
|
168
193
|
} else {
|
|
@@ -170,6 +195,39 @@ export default class FWEventManager implements FW.EventManager {
|
|
|
170
195
|
}
|
|
171
196
|
}
|
|
172
197
|
|
|
198
|
+
/**
|
|
199
|
+
* 注册一次性事件
|
|
200
|
+
* @param eventName 事件名
|
|
201
|
+
* @param cb 回调函数
|
|
202
|
+
* @param target 事件回调绑定目标
|
|
203
|
+
* @param options 选项
|
|
204
|
+
*/
|
|
205
|
+
public registerOnce(
|
|
206
|
+
eventName: string | number,
|
|
207
|
+
cb: (
|
|
208
|
+
args1?: FW.EventManagerArgs,
|
|
209
|
+
args2?: FW.EventManagerArgs,
|
|
210
|
+
args3?: FW.EventManagerArgs,
|
|
211
|
+
args4?: FW.EventManagerArgs,
|
|
212
|
+
args5?: FW.EventManagerArgs,
|
|
213
|
+
args6?: FW.EventManagerArgs,
|
|
214
|
+
args7?: FW.EventManagerArgs,
|
|
215
|
+
args8?: FW.EventManagerArgs,
|
|
216
|
+
args9?: FW.EventManagerArgs,
|
|
217
|
+
args10?: FW.EventManagerArgs,
|
|
218
|
+
) => void,
|
|
219
|
+
target: FW.TargetType,
|
|
220
|
+
options?: {
|
|
221
|
+
priority?: FWSystemDefine.FWPriorityOrder;
|
|
222
|
+
intercept?: boolean;
|
|
223
|
+
},
|
|
224
|
+
) {
|
|
225
|
+
this.register(eventName, cb, target, {
|
|
226
|
+
...options,
|
|
227
|
+
once: true, // 强制设置为一次性事件
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
173
231
|
/**
|
|
174
232
|
* 注销事件
|
|
175
233
|
* @param eventName
|
|
@@ -268,6 +326,37 @@ export default class FWEventManager implements FW.EventManager {
|
|
|
268
326
|
});
|
|
269
327
|
}
|
|
270
328
|
|
|
329
|
+
/**
|
|
330
|
+
* 移除指定的观察者列表
|
|
331
|
+
* @param eventName 事件名
|
|
332
|
+
* @param observersToRemove 待移除的观察者列表
|
|
333
|
+
*/
|
|
334
|
+
private removeObservers(eventName: string | number, observersToRemove: FW.Observer[]): void {
|
|
335
|
+
const observers = this.listeners[eventName];
|
|
336
|
+
if (!observers) return;
|
|
337
|
+
|
|
338
|
+
for (const observerToRemove of observersToRemove) {
|
|
339
|
+
const index = observers.indexOf(observerToRemove);
|
|
340
|
+
if (index !== -1) {
|
|
341
|
+
observers.splice(index, 1);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (observers.length === 0) {
|
|
346
|
+
delete this.listeners[eventName];
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* 获取事件监听器数量
|
|
352
|
+
* @param eventName 事件名
|
|
353
|
+
* @returns 监听器数量
|
|
354
|
+
*/
|
|
355
|
+
public getListenerCount(eventName: string | number): number {
|
|
356
|
+
const observers = this.listeners[eventName];
|
|
357
|
+
return observers ? observers.length : 0;
|
|
358
|
+
}
|
|
359
|
+
|
|
271
360
|
/** 销毁 */
|
|
272
361
|
public onDestroy(): void {
|
|
273
362
|
this.listeners = cc.js.createMap();
|