keytops-game-framework 1.0.21 → 1.0.22

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/dist/index.js CHANGED
@@ -6832,2007 +6832,2009 @@ class Task extends EventDispatcher {
6832
6832
  }
6833
6833
  Task.Event = Event$1;
6834
6834
 
6835
- /**
6836
- * 注册进入视图时,上报的事件名称,不注册则上报视图配置的name属性
6837
- * @param analyticsName 可选参数,默认为view的name,可以指定为上报的中文名称
6838
- * @param group 分组,默认为default,方便分类统计
6839
- * @returns
6840
- */
6841
- function viewAnalytics(analyticsName, group = "default") {
6842
- return function (target, propertyKey) {
6843
- viewManager.registerAnalytics(target, analyticsName, group);
6844
- };
6845
- }
6846
- /**
6847
- * 视图管理类
6848
- */
6849
- class ViewManager {
6850
- /**
6851
- * 注册视图上报事件的视图名称,一般为中文方便数据分辨
6852
- * @param viewClass
6853
- * @param analyticsName 可选参数,默认为view的name,可以指定为上报的中文名称
6854
- * @param group 分组,可选参数,默认为default,方便分类统计
6855
- */
6856
- registerAnalytics(viewClass, analyticsName, group = "default") {
6857
- let config = this._getViewConfig(viewClass);
6858
- if (config) {
6859
- this._viewAnalyticsMap.set(config.name, { name: analyticsName || config.name, group });
6860
- }
6861
- else {
6862
- throw new Error(`未获取到视图${viewClass}的配置`);
6835
+ class EffectAudioSourceProxy {
6836
+ constructor() {
6837
+ this._audioNode = null;
6838
+ this._audioSource = null;
6839
+ this._onFinishCallBack = null;
6840
+ this._audioNode = cc.find("__audioNode__");
6841
+ if (!this._audioNode) {
6842
+ this._audioNode = new cc.Node();
6843
+ this._audioNode.name = '__audioNode__';
6844
+ cc.director.getScene().addChild(this._audioNode);
6845
+ cc.director.addPersistRootNode(this._audioNode);
6863
6846
  }
6847
+ this._audioSource = this._audioNode.addComponent(cc.AudioSource);
6864
6848
  }
6865
6849
  /**
6866
- * 注册视图类对应的视图配置
6867
- * @param viewName 视图名称
6868
- * @param config 视图配置
6850
+ * 声音大小
6869
6851
  */
6870
- registerView(viewName, config) {
6871
- if (this._viewConfigMap.has(viewName)) {
6872
- throw new Error(`已经存在名称为${viewName}的View`);
6852
+ set volume(value) {
6853
+ if (!this._audioNode || !this._audioSource) {
6854
+ return;
6873
6855
  }
6874
- this._viewConfigMap.set(viewName, config);
6856
+ this._audioSource.volume = value;
6875
6857
  }
6876
6858
  /**
6877
- * 注册closeTouch默认遮罩视图
6878
- * @param config 视图配置|Class|名称
6859
+ * 声音大小
6879
6860
  */
6880
- registerMaskView(config) {
6881
- let viewConfig = this._getViewConfig(config);
6882
- if (!viewConfig) {
6883
- throw new Error(`未获取到默认遮罩视图${config}的配置`);
6861
+ get volume() {
6862
+ if (!this._audioNode || !this._audioSource) {
6863
+ return 1;
6884
6864
  }
6885
- this._defaultMaskViewConfig = viewConfig;
6886
- }
6887
- getViewConfig(config) {
6888
- return Object.assign({}, this._getViewConfig(config));
6865
+ return this._audioSource.volume;
6889
6866
  }
6890
6867
  /**
6891
- * [内部直接获取]获取视图配置
6892
- * @param config
6868
+ * 渐进式播放
6869
+ * @param clip
6870
+ * @param volume
6871
+ * @param loop
6872
+ * @param onFinishCallBack
6893
6873
  * @returns
6894
6874
  */
6895
- _getViewConfig(config) {
6896
- if (config == null) {
6897
- console.error(`[view] 获取视图配置,参数不能为空`);
6898
- return null;
6899
- }
6900
- if (typeof config == "string") {
6901
- if (!this._viewConfigMap.has(config)) {
6902
- console.error(`[view]${config}视图配置未注册`);
6903
- return null;
6904
- }
6905
- return this._viewConfigMap.get(config);
6906
- }
6907
- if ("path" in config) {
6908
- return config;
6909
- }
6910
- let values = this._viewConfigMap.values();
6911
- while (true) {
6912
- let item = values.next();
6913
- if (!item || item.done) {
6914
- return null;
6915
- }
6916
- if (item.value['viewClass'] == config) {
6917
- return item.value;
6918
- }
6919
- }
6875
+ playfade(clip, volume, loop = false, onFinishCallBack) {
6876
+ this.play(clip, volume, loop, onFinishCallBack);
6877
+ return this.fadeIn();
6920
6878
  }
6921
- constructor() {
6922
- this._viewConfigMap = new Map();
6923
- this._viewAnalyticsMap = new Map();
6924
- this._currentStack = [];
6925
- this._viewCache = new Map();
6926
- this._touchLocks = new Set();
6927
- if (ViewManager.created) {
6928
- throw new Error("ViewManager 是单例");
6929
- }
6930
- ViewManager.created = true;
6879
+ /**
6880
+ * 播放
6881
+ * @param clip
6882
+ * @param volume
6883
+ * @param loop
6884
+ * @param onFinishCallBack
6885
+ * @returns
6886
+ */
6887
+ play(clip, volume, loop = false, onFinishCallBack) {
6888
+ this._audioSource.clip = clip;
6889
+ this._audioSource.loop = loop;
6890
+ this._audioSource.volume = volume;
6891
+ this._audioSource.playOnAwake = false;
6892
+ this._onFinishCallBack = onFinishCallBack;
6893
+ this._audioNode.on(cc.AudioSource.EventType.ENDED, this._onAudioEnded, this);
6894
+ this._audioSource.play();
6895
+ return this;
6931
6896
  }
6932
6897
  /**
6933
- * 场景启动后设置场景,不建议手动调用
6934
- * @param root
6898
+ * 渐进
6899
+ * @returns
6935
6900
  */
6936
- setRoot(root) {
6937
- this._viewCache.forEach((views) => {
6938
- for (const view of views) {
6939
- view.allDestroy();
6940
- }
6901
+ fadeIn() {
6902
+ return new Promise((resolve) => {
6903
+ const targetVolume = this.volume;
6904
+ cc.tween(this).set({ volume: 0 }).to(0.2, { volume: targetVolume }).call(() => {
6905
+ resolve(this);
6906
+ }).start();
6941
6907
  });
6942
- this._viewCache.clear();
6943
- this._currentStack.length = 0;
6944
- this.event("open", root);
6945
- this.reportViewAnalytics("open", root);
6946
- this._scene = root;
6947
- this._currentView = null;
6948
- businessCenter && businessCenter.start(RewardVideoMaskBusiness);
6949
6908
  }
6950
6909
  /**
6951
- * 切换场景
6952
- * @param config 目标场景的配置|Class|名称
6953
- * @param data
6910
+ * 渐出
6911
+ * @param stop
6954
6912
  * @returns
6955
6913
  */
6956
- switchScene(config, ...data) {
6957
- return __awaiter(this, void 0, void 0, function* () {
6958
- config = this._getViewConfig(config);
6959
- let view = this.getCacheView(config);
6960
- if (view) {
6961
- view = yield this._switchView(view, ...data);
6962
- }
6963
- else {
6964
- view = yield this._switchViewByConfig(config, ...data);
6965
- }
6966
- // this.cacheView(view);
6967
- // this._currentStack.push(config);
6968
- return view;
6914
+ fedeOut(stop = true) {
6915
+ return new Promise((resolve) => {
6916
+ cc.tween(this).to(0.2, { volume: 0 }).call(() => {
6917
+ stop && this.stop();
6918
+ resolve(this);
6919
+ }).start();
6969
6920
  });
6970
6921
  }
6971
6922
  /**
6972
- * 当前场景
6923
+ * 暂停
6973
6924
  * @returns
6974
6925
  */
6975
- scene() {
6976
- return this._scene;
6926
+ pause() {
6927
+ if (!this._audioNode || !this._audioSource) {
6928
+ return;
6929
+ }
6930
+ this._audioSource.pause();
6977
6931
  }
6978
6932
  /**
6979
- * 开启当前场景的可交互性
6980
- * @param token closeTouch返回的触摸锁令牌。传入时仅释放该锁,所有锁释放后才会真正开启触摸;不传则清空全部触摸锁并开启触摸。
6933
+ * 恢复
6934
+ * @returns
6981
6935
  */
6982
- openTouch(token) {
6983
- if (token) {
6984
- this._touchLocks.delete(token);
6985
- }
6986
- else {
6987
- this._touchLocks.clear();
6936
+ resume() {
6937
+ if (!this._audioNode || !this._audioSource) {
6938
+ return;
6988
6939
  }
6989
- this._applyTouchState();
6940
+ this._audioSource.play();
6990
6941
  }
6991
6942
  /**
6992
- * 关闭当前场景的可交互性
6993
- * @param delay 可选参数,默认200毫秒,显示maskView的延迟时间。
6994
- * @param maskViewConfig 可选参数,默认为空白,要显示的遮罩试图。
6995
- * @returns 当前触摸锁令牌,可传给openTouch精确释放本次锁。
6943
+ * 渐进停止
6944
+ * @returns
6996
6945
  */
6997
- closeTouch(delay = 200, maskViewConfig = null) {
6998
- return __awaiter(this, void 0, void 0, function* () {
6999
- const token = this._lockTouch();
7000
- let config = maskViewConfig == null ? this._defaultMaskViewConfig : this._getViewConfig(maskViewConfig);
7001
- if (!config) {
7002
- return token;
7003
- }
7004
- if (delay <= 0) {
7005
- yield this._showMaskView(config, token);
7006
- return token;
7007
- }
7008
- timer.once(delay, this, this._showMaskView, [config, token]);
7009
- return token;
7010
- });
7011
- }
7012
- _lockTouch() {
7013
- const token = Symbol("touch-lock");
7014
- this._touchLocks.add(token);
7015
- this._applyTouchState();
7016
- return token;
6946
+ stopFade() {
6947
+ return this.fedeOut(true).then(() => { });
7017
6948
  }
7018
- _applyTouchState() {
7019
- const locked = this._touchLocks.size > 0;
7020
- if (!locked) {
7021
- timer.clear(this, this._showMaskView);
7022
- if (this._currentMaskView) {
7023
- this._currentMaskView.removeFromParent(true);
7024
- this._currentMaskView = null;
7025
- }
6949
+ /**
6950
+ * 停止
6951
+ * @returns
6952
+ */
6953
+ stop() {
6954
+ if (!this._audioNode || !this._audioSource) {
6955
+ return;
7026
6956
  }
7027
- if (this._scene) {
7028
- this._scene.touchEnabled = !locked;
6957
+ this._audioSource.stop();
6958
+ this._audioNode.off(cc.AudioSource.EventType.ENDED, this._onAudioEnded, this);
6959
+ }
6960
+ _onAudioEnded(audioSource) {
6961
+ if (audioSource == this._audioSource) {
6962
+ this._onFinishCallBack && this._onFinishCallBack();
6963
+ this._audioNode.off(cc.AudioSource.EventType.ENDED, this._onAudioEnded, this);
7029
6964
  }
7030
6965
  }
7031
- _showMaskView(maskViewConfig, token) {
7032
- return __awaiter(this, void 0, void 0, function* () {
7033
- if (!this._scene || !this._touchLocks.has(token) || this._currentMaskView) {
7034
- return;
7035
- }
7036
- let view = this.getCacheView(maskViewConfig);
7037
- if (view) {
7038
- view = yield this._addView(view, this._scene);
7039
- }
7040
- else {
7041
- view = yield this._loadViewByConfig(maskViewConfig, this._scene, "显示遮罩视图错误");
7042
- this.cacheView(view);
7043
- }
7044
- if (!this._touchLocks.has(token)) {
7045
- view.removeFromParent(true);
7046
- return;
7047
- }
7048
- this._currentMaskView = view;
7049
- timer.frameNext(this, () => {
7050
- if (this._currentMaskView == view && this._touchLocks.has(token)) {
7051
- view.setData();
7052
- }
7053
- });
7054
- });
6966
+ /**
6967
+ * 是否循环
6968
+ */
6969
+ get loop() {
6970
+ return this._audioSource ? this._audioSource.loop : false;
7055
6971
  }
7056
6972
  /**
7057
- * 当前主视图
7058
- * @returns
6973
+ * 是否播放中
7059
6974
  */
7060
- view() {
7061
- return this._currentView;
6975
+ get playing() {
6976
+ return this._audioSource ? this._audioSource.playing : false;
6977
+ }
6978
+ reset() {
6979
+ this.stop();
6980
+ cc.Tween.stopAllByTarget(this);
6981
+ this._onFinishCallBack = null;
6982
+ }
6983
+ destroy() {
6984
+ this._audioSource.destroy();
6985
+ this._audioSource = null;
6986
+ this._audioNode = null;
6987
+ this._onFinishCallBack = null;
6988
+ }
6989
+ }
6990
+ class AudioManager {
6991
+ constructor() {
6992
+ this._musicVolume = null;
6993
+ this._effectVolume = null;
6994
+ this._effectPool = new Pool(EffectAudioSourceProxy); //cc.AudioSource.maxAudioChannel - 1);
7062
6995
  }
7063
6996
  /**
7064
- * 切换主视图到目标视图
7065
- * @param target 目标视图的配置|Class|名称
7066
- * @param datas 目标视图初始化参数
6997
+ * 音效音量大小
7067
6998
  */
7068
- switchTo(config, ...data) {
7069
- return __awaiter(this, void 0, void 0, function* () {
7070
- config = this._getViewConfig(config);
7071
- if (!this._scene) {
7072
- throw new Error("根View不存在");
7073
- }
7074
- let view = this.getCacheView(config);
7075
- if (view) {
7076
- view = yield this._switchView(view, ...data);
7077
- }
7078
- else {
7079
- view = yield this._switchViewByConfig(config, ...data);
7080
- }
7081
- this.cacheView(view);
7082
- this._currentStack.push(config);
7083
- return view;
7084
- });
6999
+ get effectVolume() {
7000
+ if (this._effectVolume == null) {
7001
+ this._effectVolume = storage.effectsVolume;
7002
+ }
7003
+ return this._effectVolume;
7085
7004
  }
7086
7005
  /**
7087
- * 切回当前主视图到上一个主视图。
7088
- * @param data
7089
- * @returns
7006
+ * 音效音量大小
7090
7007
  */
7091
- switchBack(...data) {
7092
- return __awaiter(this, void 0, void 0, function* () {
7093
- if (this._currentStack.length == 0) {
7094
- console.warn("上一个视图不存在");
7095
- return null;
7096
- }
7097
- //移除当前视图config
7098
- this._currentStack.pop();
7099
- //获取之前视图config
7100
- let lastViewConfig = this._currentStack.pop();
7101
- if (!lastViewConfig) {
7102
- console.warn("上个主视图为空,");
7103
- return null;
7104
- }
7105
- return yield this.switchTo(lastViewConfig, ...data);
7106
- });
7008
+ set effectVolume(value) {
7009
+ storage.effectsVolume = this._effectVolume = value;
7010
+ let usingEffect = this._effectPool['_usingArray'];
7011
+ usingEffect = usingEffect.concat();
7012
+ for (let i = 0; i < usingEffect.length; i++) {
7013
+ const effectProxy = usingEffect[i];
7014
+ effectProxy.volume = value;
7015
+ }
7107
7016
  }
7108
- _switchView(view, ...datas) {
7109
- return __awaiter(this, void 0, void 0, function* () {
7110
- this._currentView && this._currentView.removeFromParent(!this._currentView.config.cache);
7111
- this._currentView = null;
7112
- this._currentView = view;
7113
- this._scene.addView(this._currentView, view.config.zIndex);
7114
- this._currentView.setData(...datas);
7115
- return this._currentView;
7116
- });
7017
+ /**
7018
+ * BGM音量大小
7019
+ */
7020
+ get musicVolume() {
7021
+ if (this._musicVolume == null) {
7022
+ this._musicVolume = storage.musicVolume;
7023
+ }
7024
+ return this._musicVolume;
7117
7025
  }
7118
- _switchViewByConfig(viewConfig, ...datas) {
7119
- return __awaiter(this, void 0, void 0, function* () {
7120
- const touchToken = this._lockTouch();
7121
- let loader;
7122
- try {
7123
- loader = yield this.loadView(viewConfig);
7124
- }
7125
- catch (error) {
7126
- this.openTouch(touchToken);
7127
- console.error(`切换视图错误 code:${error.code}, msg:${error.msg || error.message}`);
7128
- throw new Error(`切换视图错误 code:${error.code}, msg:${error.msg || error.message}`);
7129
- }
7130
- let name = viewConfig.name || viewConfig.path.substring(viewConfig.path.lastIndexOf("/") + 1);
7131
- this._currentView && this._currentView.removeFromParent(!this._currentView.config.cache);
7132
- this._currentView = null;
7133
- let view = loader.initView(name, true);
7134
- view.name = name;
7135
- view.config = viewConfig;
7136
- view.analyticsInfo = this._viewAnalyticsMap.get(viewConfig.name);
7137
- if (view['addToBG']) {
7138
- this.setRoot(view);
7139
- }
7140
- else {
7141
- this._currentView = view;
7142
- this._scene.addView(view, viewConfig.zIndex);
7143
- }
7144
- timer.frameNext(this, () => {
7145
- this.openTouch(touchToken);
7146
- view.setData(...datas);
7147
- });
7148
- return view;
7149
- });
7026
+ /**
7027
+ * BGM音量大小
7028
+ */
7029
+ set musicVolume(value) {
7030
+ storage.musicVolume = this._musicVolume = value;
7031
+ this._music && (this._music.volume = value);
7150
7032
  }
7151
7033
  /**
7152
- * 通过视图配置添加视图
7153
- * @param viewConfig 要添加的视图配置|Class|名称
7154
- * @param parent 父级视图,默认为当前主视图,即viewMananger.current()
7155
- * @param datas 传入setData的数据
7034
+ * 播放音效
7035
+ * @param clip
7036
+ * @param loop 是否循环,默认为false。传入true,需要手动调用recoverEffect进行回收
7037
+ * @param onFinishCallBack 播放完回调
7038
+ * @param volume 当此播放的声音大小,默认为统一effect的大小
7156
7039
  */
7157
- addView(config, parent, ...datas) {
7158
- return __awaiter(this, void 0, void 0, function* () {
7159
- config = this._getViewConfig(config);
7160
- parent = parent || this._currentView;
7161
- if (!parent) {
7162
- throw new Error("当前View不存在, 且未传入父级视图");
7163
- }
7164
- let view = this.getCacheView(config);
7165
- if (view) {
7166
- view = yield this._addView(view, parent, ...datas);
7040
+ playEffect(clip, loop = false, onFinishCallBack, volume = null) {
7041
+ const effectProxy = this._effectPool.allocate();
7042
+ effectProxy.play(clip, volume == null ? this.effectVolume : volume, loop, () => {
7043
+ if (!loop) {
7044
+ this.recoverEffect(effectProxy);
7167
7045
  }
7168
7046
  else {
7169
- view = yield this._addViewbyConfig(config, parent, ...datas);
7170
- }
7171
- this.cacheView(view);
7172
- return view;
7173
- });
7174
- }
7175
- _addView(view, parent, ...datas) {
7176
- return __awaiter(this, void 0, void 0, function* () {
7177
- parent.addView(view, view.config.zIndex);
7178
- view.setData(...datas);
7179
- return view;
7180
- });
7181
- }
7182
- _addViewbyConfig(config, parent, ...datas) {
7183
- return __awaiter(this, void 0, void 0, function* () {
7184
- const touchToken = this._lockTouch();
7185
- let view;
7186
- try {
7187
- view = yield this._loadViewByConfig(config, parent, "添加视图错误");
7188
- }
7189
- catch (error) {
7190
- this.openTouch(touchToken);
7191
- throw error;
7192
- }
7193
- timer.frameNext(this, () => {
7194
- this.openTouch(touchToken);
7195
- view.setData(...datas);
7196
- });
7197
- return view;
7198
- });
7199
- }
7200
- _loadViewByConfig(config, parent, errorPrefix) {
7201
- return __awaiter(this, void 0, void 0, function* () {
7202
- let loader;
7203
- try {
7204
- loader = yield this.loadView(config);
7205
- }
7206
- catch (error) {
7207
- console.error(`${errorPrefix} code:${error.code}, msg:${error.msg || error.message}`);
7208
- throw new Error(`${errorPrefix} code:${error.code}, msg:${error.msg || error.message}`);
7047
+ console.warn("需要手动回收音效播放器");
7209
7048
  }
7210
- let name = config.name || config.path.substring(config.path.lastIndexOf("/") + 1);
7211
- let view = loader.initView(name, true);
7212
- view.name = name;
7213
- view.config = config;
7214
- view.analyticsInfo = this._viewAnalyticsMap.get(config.name);
7215
- parent.addView(view, config.zIndex);
7216
- return view;
7049
+ onFinishCallBack && onFinishCallBack();
7217
7050
  });
7051
+ return effectProxy;
7218
7052
  }
7219
7053
  /**
7220
- * 加载视图到内存,之后还需要调用loader.initView接口获取view
7221
- * @param config 要加载的视图配置|Class|名称
7222
- * @param task 任务载体
7054
+ * 回收音效播放器,用于effect多次复用后的回收
7055
+ * @param proxy
7223
7056
  */
7224
- loadView(config, task) {
7225
- return new Promise((resolve, reject) => {
7226
- config = this._getViewConfig(config);
7227
- let loader = this.impl.getLoader(config).init(config);
7228
- task = task || new Task();
7229
- task.once(Task.Event.COMPLETE, this, () => {
7230
- resolve(loader);
7231
- });
7232
- task.once(Task.Event.ERROR, this, (type, task, reason) => {
7233
- reject(reason);
7234
- });
7235
- loader.load(task);
7236
- });
7057
+ recoverEffect(proxy) {
7058
+ this._effectPool.recover(proxy);
7237
7059
  }
7238
7060
  /**
7239
- * 获取缓存视图
7240
- * @param config
7241
- * @returns
7061
+ * 停止所有音效
7242
7062
  */
7243
- getCacheView(config) {
7244
- config = this._getViewConfig(config);
7245
- let views = this._viewCache.get(config.path);
7246
- if (!views || views.length == 0) {
7247
- return null;
7248
- }
7249
- for (const view of views) {
7250
- if (!view.inStage) {
7251
- return view;
7252
- }
7063
+ stopAllEffect() {
7064
+ let usingEffect = this._effectPool['_usingArray'];
7065
+ usingEffect = usingEffect.concat();
7066
+ for (let i = 0; i < usingEffect.length; i++) {
7067
+ const effectProxy = usingEffect[i];
7068
+ effectProxy.stop();
7069
+ this.recoverEffect(effectProxy);
7253
7070
  }
7254
- return null;
7255
7071
  }
7256
7072
  /**
7257
- * 缓存视图
7258
- * @param view
7259
- * @param force 默认为false,不考虑view.config.cache的值,强制增加到缓存
7260
- * @returns
7073
+ * 播放背景音乐
7074
+ * @param clip
7075
+ * @param fade 是否渐进式播放,默认为true
7076
+ * @param loop 是否循环,默认为true
7077
+ * @param onFinishCallBack 播放完回调
7078
+ * @param volume 当此播放的声音大小,默认为统一music的大小
7261
7079
  */
7262
- cacheView(view, force = false) {
7263
- if (!view || !view.config || (!view.config.cache && !force)) {
7264
- return false;
7265
- }
7266
- let views = this._viewCache.get(view.config.path);
7267
- if (!views) {
7268
- views = [view];
7269
- this._viewCache.set(view.config.path, views);
7270
- return true;
7271
- }
7272
- else if (!views.includes(view)) {
7273
- views.push(view);
7274
- return true;
7080
+ playMusic(clip, fade = true, loop = true, onFinishCallBack, volume = null) {
7081
+ if (!this._music) {
7082
+ this._music = new EffectAudioSourceProxy();
7275
7083
  }
7276
- return false;
7084
+ this._music.playing && this._music.stop();
7085
+ volume = volume == null ? this.musicVolume : volume;
7086
+ fade ? this._music.playfade(clip, volume, loop, onFinishCallBack) : this._music.play(clip, volume, loop, onFinishCallBack);
7277
7087
  }
7278
7088
  /**
7279
- * 从缓存列表中移除视图。
7280
- * @param view
7089
+ * 暂停播放背景音乐
7281
7090
  * @returns
7282
7091
  */
7283
- cancelCache(view) {
7284
- if (!view || !view.config || !view.config.path) {
7285
- return false;
7286
- }
7287
- let views = this._viewCache.get(view.config.path);
7288
- if (!views || views.length == 0) {
7289
- return false;
7290
- }
7291
- const index = views.indexOf(view);
7292
- if (index != -1) {
7293
- views.splice(index, 1);
7294
- return true;
7092
+ pauseMusic() {
7093
+ if (!this._music) {
7094
+ return;
7295
7095
  }
7296
- return false;
7297
- }
7298
- /**
7299
- * [快捷方式]增加视图打开的事件监听
7300
- * @param targetView 目标视图Class|名称
7301
- * @param listener 响应回调
7302
- * @param caller 回调this
7303
- * @param once 是否只监听对应视图打开一次。
7304
- * @param args 其他参数
7305
- */
7306
- onViewOpen(targetView, caller, listener, once = false, ...args) {
7307
- this._viewOpenEventMap = this._viewOpenEventMap || new Map();
7308
- this._viewOpenEventMap.set(listener, { event: "open", viewConfig: this._getViewConfig(targetView), caller, listener, once, args });
7309
- this.offViewEvent("open", this, this._onViewOpen);
7310
- this.onViewEvent("open", this, this._onViewOpen);
7311
- }
7312
- _onViewOpen(viewName, ...args) {
7313
- this._viewOpenEventMap.forEach((value, key) => {
7314
- if (value.viewConfig.name == viewName) {
7315
- value.listener.apply(value.caller, value.args);
7316
- value.once && this._viewOpenEventMap.delete(key);
7317
- }
7318
- });
7096
+ this._music.pause();
7319
7097
  }
7320
7098
  /**
7321
- * [快捷方式]移除视图打开的事件监听
7322
- * @param listener
7099
+ * 恢复播放背景音乐
7323
7100
  * @returns
7324
7101
  */
7325
- offViewOpen(listener) {
7326
- return this._viewOpenEventMap && this._viewOpenEventMap.delete(listener);
7327
- }
7328
- /**
7329
- * [快捷方式]增加视图关闭的事件监听
7330
- * @param targetView 目标视图Class|名称
7331
- * @param listener 响应回调
7332
- * @param caller 回调this
7333
- * @param once 是否只监听对应视图关闭一次。
7334
- * @param args 其他参数
7335
- */
7336
- onViewClose(targetView, caller, listener, once = false, ...args) {
7337
- this._viewCloseEventMap = this._viewCloseEventMap || new Map();
7338
- this._viewCloseEventMap.set(listener, { event: "close", viewConfig: this._getViewConfig(targetView), caller, listener, once, args });
7339
- this.offViewEvent("close", this, this._onViewClose);
7340
- this.onViewEvent("close", this, this._onViewClose);
7102
+ resumeMusic() {
7103
+ if (!this._music) {
7104
+ return;
7105
+ }
7106
+ this._music.resume();
7341
7107
  }
7342
7108
  /**
7343
- * [快捷方式]移除视图关闭的事件监听
7344
- * @param listener
7109
+ * 停止背景音乐
7110
+ * @param fade 是否渐出
7345
7111
  * @returns
7346
7112
  */
7347
- offViewClose(listener) {
7348
- return this._viewCloseEventMap && this._viewCloseEventMap.delete(listener);
7349
- }
7350
- _onViewClose(viewName, ...args) {
7351
- this._viewCloseEventMap.forEach((value, key) => {
7352
- if (value.viewConfig.name == viewName) {
7353
- value.listener.apply(value.caller, value.args.concat(args));
7354
- value.once && this._viewCloseEventMap.delete(key);
7113
+ stopMusic(fade = true) {
7114
+ return __awaiter(this, void 0, void 0, function* () {
7115
+ if (!this._music) {
7116
+ return;
7355
7117
  }
7118
+ return fade ? yield this._music.stopFade() : this._music.stop();
7356
7119
  });
7357
7120
  }
7358
- /**
7359
- * 增加视图事件监听
7360
- * @param event 视图事件名称
7361
- * @param caller 回调this
7362
- * @param listener 响应回调
7363
- * @param once 是否只监听对应视图关闭一次。
7364
- * @param args 其他参数
7365
- */
7366
- onViewEvent(event, caller, listener, once = false, ...args) {
7367
- if (!this._viewEvent) {
7368
- this._viewEvent = new EventDispatcher();
7369
- }
7370
- if (once) {
7371
- this._viewEvent.once(event, caller, listener, args);
7372
- }
7373
- else {
7374
- this._viewEvent.on(event, caller, listener, args);
7375
- }
7376
- }
7377
- /**
7378
- * 移除视图事件监听
7379
- * @param event 事件类型
7380
- * @param caller 事件侦听函数的执行域。
7381
- * @param listener 事件侦听函数。
7382
- * @returns
7383
- */
7384
- offViewEvent(event, caller, listener) {
7385
- if (!this._viewEvent) {
7386
- return;
7387
- }
7388
- this._viewEvent.off(event, caller, listener);
7389
- }
7390
- /**
7391
- * 广播视图事件
7392
- * @param event 视图事件
7393
- * @param view 视图
7394
- */
7395
- event(event, view, ...args) {
7396
- if (this._viewEvent) {
7397
- args.unshift(view.name);
7398
- this._viewEvent.event(event, args);
7399
- }
7400
- }
7401
- /**
7402
- * 上报视图统计数据(open\close\...)
7403
- * @param event 事件
7404
- * @param view 视图
7405
- * @param data 上报附带信息
7406
- */
7407
- reportViewAnalytics(event, view, data) {
7408
- let maskViewconfig = this._currentMaskView && this._currentMaskView.config;
7409
- if (maskViewconfig && view.name == maskViewconfig.name) {
7410
- return;
7411
- }
7412
- let analyticsInfo = this._viewAnalyticsMap.get(view.name);
7413
- if (analyticsInfo) {
7414
- data = data || (view.getAnalyticsDataOnViewEvent && view.getAnalyticsDataOnViewEvent(event)) || {};
7415
- data.action = event;
7416
- data.name = analyticsInfo.name;
7417
- data.group = analyticsInfo.group || "default";
7418
- //open:进入时刻, close:停留时长
7419
- data.stay = Math.floor((App.durationOfLaunch - (analyticsInfo.lastOpenTime || 0)) / 1000);
7420
- analytics.base.report("view", data);
7421
- analyticsInfo.lastOpenTime = event == "open" ? App.durationOfLaunch : 0;
7422
- }
7423
- }
7424
- get impl() {
7425
- if (this._impl == null) {
7426
- this._impl = Injector.getInject(ViewManager.KEY);
7427
- }
7428
- if (this._impl == null) {
7429
- throw new Error(ViewManager.KEY + "未注入!");
7430
- }
7431
- return this._impl;
7432
- }
7433
7121
  }
7434
- ViewManager.KEY = "ViewManager";
7435
- ViewManager.created = false;
7436
7122
  /**
7437
- * 视图管理器
7123
+ * 音效管理
7438
7124
  */
7439
- const viewManager = new ViewManager();
7125
+ const audio = new AudioManager();
7440
7126
 
7441
- class INativeHelper {
7127
+ const GC_CD = 60 * 1000;
7128
+ /**
7129
+ * 资源管理
7130
+ */
7131
+ class ResourceManager {
7442
7132
  constructor() {
7443
- this._callbackCount = 0;
7444
- }
7445
- call(className, methodName, ...args) {
7446
- this.callWithReturnType(className, methodName, null, ...args);
7133
+ this._loadPromiseMap = new Map();
7134
+ this._loadBunldePromiseMap = new Map();
7135
+ this._waitToReleaseBundles = new Map();
7136
+ this._startedGC = false;
7447
7137
  }
7448
- registerCallback(caller, method, times, ...args) {
7449
- if (caller == null || method == null) {
7450
- return "";
7451
- }
7452
- ++this._callbackCount;
7453
- let callbackName = 'NativeHelper.callback' + this._callbackCount;
7454
- window[callbackName] = () => {
7455
- method.apply(caller, args);
7456
- if (--times <= 0) {
7457
- window[callbackName] = null;
7458
- }
7459
- };
7460
- return `window['${callbackName}']()`;
7138
+ preload(path, task) {
7139
+ return __awaiter(this, void 0, void 0, function* () {
7140
+ let paths = typeof path === "string" ? [path] : path;
7141
+ let pathInfoList = paths.map((value) => {
7142
+ return this.parsePath(value);
7143
+ });
7144
+ let loadPromiseList = pathInfoList.map((info) => {
7145
+ return !info.isRemote ? this._preLoadFromBundle(info, task) : this._preLoadFromRemote(info, task);
7146
+ });
7147
+ return Promise.all(loadPromiseList).then((value) => {
7148
+ return value.length == 1 ? value[0] : value;
7149
+ });
7150
+ });
7461
7151
  }
7462
- }
7463
-
7464
- /**
7465
- @name: NativeHelper
7466
- @desc: cocos 2.4.x 下nativeHelper
7467
- @author: timoo
7468
- @date: 2022/12/02
7469
- */
7470
- class CocosNativeHelper extends INativeHelper {
7471
- callWithReturnType(className, methodName, returnType, ...args) {
7472
- if (!className) {
7152
+ preLoadScene(path, task) {
7153
+ return __awaiter(this, void 0, void 0, function* () {
7154
+ let paths = typeof path === "string" ? [path] : path;
7155
+ let pathInfoList = paths.map((value) => {
7156
+ let result = this.parsePath(value);
7157
+ if (result.isRemote) {
7158
+ throw new Error(`不支持从远程预加载场景${value}`);
7159
+ }
7160
+ return result;
7161
+ });
7162
+ let loadPromiseList = pathInfoList.map((info) => __awaiter(this, void 0, void 0, function* () {
7163
+ let bundle = yield this.getBundle(info.bundle);
7164
+ return new Promise((resolve) => {
7165
+ if (!bundle) {
7166
+ resolve(null);
7167
+ task && task.onError("preLoadScene", `加载${info.fullPath}时 bundle${info.bundle}加载失败`);
7168
+ }
7169
+ bundle.preloadScene(info.path, (error) => {
7170
+ if (error) {
7171
+ resolve(null);
7172
+ task && task.onError(error.name, error.message);
7173
+ }
7174
+ resolve(info.fullPath);
7175
+ task && task.onComplete();
7176
+ });
7177
+ });
7178
+ }));
7179
+ return Promise.all(loadPromiseList).then((value) => {
7180
+ return value.length > 0 ? (value.length == 1 ? value[0] : value) : null;
7181
+ });
7182
+ });
7183
+ }
7184
+ _preLoadFromRemote(info, task) {
7185
+ return __awaiter(this, void 0, void 0, function* () {
7186
+ if (!info.isRemote) {
7187
+ throw new Error(`${info.fullPath}不是远程资源地址`);
7188
+ }
7189
+ if (info.isDir) {
7190
+ throw new Error(`不支持对远程Dir的加载`);
7191
+ }
7192
+ return new Promise((resolve, reject) => {
7193
+ cc.assetManager.loadRemote(info.fullPath, (error, asset) => {
7194
+ if (error) {
7195
+ resolve(null);
7196
+ task && task.onError(error.name, error.message);
7197
+ }
7198
+ else {
7199
+ resolve(info.fullPath);
7200
+ task && task.onComplete();
7201
+ }
7202
+ });
7203
+ });
7204
+ });
7205
+ }
7206
+ _preLoadFromBundle(info, task) {
7207
+ return __awaiter(this, void 0, void 0, function* () {
7208
+ let bundle = yield this.getBundle(info.bundle);
7209
+ if (!bundle) {
7210
+ task && task.onError("_preLoadFromBundle", `加载${info.fullPath}时 bundle${info.bundle}加载失败`);
7211
+ return null;
7212
+ }
7213
+ return new Promise((resolve) => {
7214
+ let onProgress = (finish, total) => {
7215
+ task && task.onProgress(finish / total);
7216
+ };
7217
+ let onComplete = (error) => {
7218
+ if (error) {
7219
+ resolve(null);
7220
+ task && task.onError(error.name, error.message);
7221
+ }
7222
+ else {
7223
+ resolve(info.fullPath);
7224
+ task && task.onComplete();
7225
+ }
7226
+ };
7227
+ if (info.path == "") {
7228
+ onComplete(null);
7229
+ }
7230
+ else if (!info.isDir) {
7231
+ bundle.preload(info.path, onProgress, onComplete);
7232
+ }
7233
+ else {
7234
+ bundle.preloadDir(info.path, onProgress, onComplete);
7235
+ }
7236
+ });
7237
+ });
7238
+ }
7239
+ load(path, assetType, task) {
7240
+ return __awaiter(this, void 0, void 0, function* () {
7241
+ let paths = typeof path === "string" ? [path] : path;
7242
+ let pathInfoList = paths.map((value) => {
7243
+ return this.parsePath(value);
7244
+ });
7245
+ let result = [];
7246
+ for (const info of pathInfoList) {
7247
+ if (!info.isRemote) {
7248
+ let assets = yield this._loadFromBundle(info, assetType, task);
7249
+ if (assets instanceof cc.Asset) {
7250
+ result.push(assets);
7251
+ }
7252
+ else {
7253
+ result.push(...assets);
7254
+ }
7255
+ continue;
7256
+ }
7257
+ let asset = yield this._loadfromRemote(info, task);
7258
+ if (assetType === cc.SpriteFrame) {
7259
+ asset = cc.SpriteFrame.createWithImage(asset);
7260
+ }
7261
+ result.push(asset);
7262
+ }
7263
+ return typeof path === "string" ? result[0] : result;
7264
+ });
7265
+ }
7266
+ _loadFromBundle(info, type, task) {
7267
+ return __awaiter(this, void 0, void 0, function* () {
7268
+ let bundle = yield this.getBundle(info.bundle);
7269
+ if (!bundle) {
7270
+ task && task.onError("_loadFromBundle", `加载${info.fullPath}时 bundle${info.bundle}加载失败`);
7271
+ return null;
7272
+ }
7273
+ if (this._loadPromiseMap.has(info.fullPath)) {
7274
+ return this._loadPromiseMap.get(info.fullPath).then((value) => {
7275
+ task && task.onComplete();
7276
+ return value;
7277
+ });
7278
+ }
7279
+ let promise = new Promise((resolve) => {
7280
+ let onProgress = (finish, total) => {
7281
+ task && task.onProgress(finish / total);
7282
+ };
7283
+ let onComplete = (error, assets) => {
7284
+ if (error) {
7285
+ console.error("加载资源发生错误", info, error);
7286
+ resolve(null);
7287
+ task && task.onError(error.name, error.message);
7288
+ }
7289
+ else {
7290
+ resolve(assets);
7291
+ task && task.onComplete();
7292
+ }
7293
+ };
7294
+ if (info.path == "") {
7295
+ onComplete(null, null);
7296
+ }
7297
+ else if (!info.isDir) {
7298
+ bundle.load(info.path, type, onProgress, onComplete);
7299
+ }
7300
+ else {
7301
+ bundle.loadDir(info.path, type, onProgress, onComplete);
7302
+ }
7303
+ });
7304
+ this._loadPromiseMap.set(info.fullPath, promise);
7305
+ return promise;
7306
+ });
7307
+ }
7308
+ _loadfromRemote(info, task) {
7309
+ if (!info.isRemote) {
7310
+ throw new Error(`${info.fullPath}不是远程资源地址`);
7311
+ }
7312
+ if (info.isDir) {
7313
+ throw new Error(`不支持对远程Dir的加载`);
7314
+ }
7315
+ if (this._loadPromiseMap.has(info.fullPath)) {
7316
+ return this._loadPromiseMap.get(info.fullPath);
7317
+ }
7318
+ let promise = new Promise((resolve) => {
7319
+ cc.assetManager.loadRemote(info.fullPath, (error, asset) => {
7320
+ if (error) {
7321
+ resolve(null);
7322
+ task && task.onError(error.name, error.message);
7323
+ }
7324
+ else {
7325
+ resolve(asset);
7326
+ task && task.onComplete();
7327
+ }
7328
+ });
7329
+ });
7330
+ this._loadPromiseMap.set(info.fullPath, promise);
7331
+ return promise;
7332
+ }
7333
+ /**
7334
+ * 解析资源路径成PathInfo
7335
+ * @param fullPath - 资源路径应该符合bundle://cc.path/to/resource格式
7336
+ * @returns - `PathInfo` 资源信息
7337
+ */
7338
+ parsePath(fullPath) {
7339
+ let tempPath = fullPath.split("://");
7340
+ if (tempPath.length != 2) {
7341
+ throw new Error(`资源地址${fullPath}格式错误,应该符合bundle://cc.path/to/resource格式`); //.suffix
7342
+ }
7343
+ let isDir = fullPath.charAt(fullPath.length - 1) == "/";
7344
+ let bundle = tempPath[0];
7345
+ let isRemote = bundle === "https" || bundle === "http";
7346
+ let suffix = cc.path.extname(fullPath).toLowerCase();
7347
+ let simplePath = suffix == "" ? tempPath[1] : tempPath[1].replace(suffix, "");
7348
+ return { bundle, path: simplePath, isRemote, isDir, fullPath };
7349
+ }
7350
+ /**
7351
+ * 获取目标bundle的资源的完整路径
7352
+ * @param bundleName - 资源所在bundle名称
7353
+ * @param subPath - 可选参数, 相对子路径
7354
+ * @returns
7355
+ */
7356
+ getPath(bundleName, subPath = "") {
7357
+ if (subPath.includes("://")) {
7358
+ return subPath;
7359
+ }
7360
+ return `${bundleName}://${subPath}`;
7361
+ }
7362
+ /**
7363
+ * 获取主包下资源的完整路径
7364
+ * @param subPath 资源子路径
7365
+ * @returns
7366
+ */
7367
+ getPathInMain(subPath) {
7368
+ return this.getPath("main", subPath);
7369
+ }
7370
+ /**
7371
+ * 获取动态包下资源的完整路径
7372
+ * @param subPath 资源子路径
7373
+ * @returns
7374
+ */
7375
+ getPathInResources(subPath) {
7376
+ return this.getPath("resources", subPath);
7377
+ }
7378
+ /**
7379
+ * 加载Bundle
7380
+ * @param bundleName Bundle名称
7381
+ * @returns `Promise<cc.AssetManager.Bundle>`
7382
+ */
7383
+ getBundle(bundleName) {
7384
+ this._removeBundleFromReleaseMap(bundleName);
7385
+ this._startGC();
7386
+ if (this._loadBunldePromiseMap.has(bundleName)) {
7387
+ return this._loadBunldePromiseMap.get(bundleName);
7388
+ }
7389
+ let promise = new Promise((resolve) => {
7390
+ let bundle = cc.assetManager.getBundle(bundleName);
7391
+ if (!!bundle) {
7392
+ resolve(bundle);
7393
+ return;
7394
+ }
7395
+ let version = this._getBundleVersion(bundleName);
7396
+ cc.assetManager.loadBundle(bundleName, version ? { version: version } : null, (error, bundle) => {
7397
+ if (error) {
7398
+ console.error(`LoadBundle ${bundleName} Error:`, error);
7399
+ resolve(null);
7400
+ }
7401
+ else {
7402
+ resolve(bundle);
7403
+ }
7404
+ });
7405
+ });
7406
+ this._loadBunldePromiseMap.set(bundleName, promise);
7407
+ return promise;
7408
+ }
7409
+ /**
7410
+ * bundle是否被加载过,且有效
7411
+ * @param bundleName
7412
+ * @returns
7413
+ */
7414
+ isBundleValid(bundleName) {
7415
+ return __awaiter(this, void 0, void 0, function* () {
7416
+ if (this._loadBunldePromiseMap.has(bundleName)) {
7417
+ let bundle = yield this._loadBunldePromiseMap.get(bundleName);
7418
+ return bundle && cc.isValid(bundle);
7419
+ }
7420
+ return false;
7421
+ });
7422
+ }
7423
+ /**
7424
+ * 移除并销毁bundle,以及bundle下所有资源。
7425
+ * @param bundleName bundle名称
7426
+ * @param delay 是否延后销毁,默认为true
7427
+ * @returns
7428
+ */
7429
+ removeBundle(bundleName, delay = true) {
7430
+ return __awaiter(this, void 0, void 0, function* () {
7431
+ if (this.isBundleValid(bundleName)) {
7432
+ let bundle = yield this._loadBunldePromiseMap.get(bundleName);
7433
+ if (delay) {
7434
+ this._pushBundleToReleaseMap(bundle);
7435
+ return true;
7436
+ }
7437
+ return this._onRemoveBundle(bundle);
7438
+ }
7439
+ return false;
7440
+ });
7441
+ }
7442
+ /**
7443
+ * 推送bundle到GC队列
7444
+ * @param bundle
7445
+ */
7446
+ _pushBundleToReleaseMap(bundle) {
7447
+ if (bundle && cc.isValid(bundle)) {
7448
+ console.log(`[GCBundle] Pre Remove Bundle:${bundle.name}`);
7449
+ this._waitToReleaseBundles.set(bundle.name, bundle);
7450
+ }
7451
+ }
7452
+ /**
7453
+ * 删除等待销毁的bundle,如果有
7454
+ * @param bundleName
7455
+ * @returns
7456
+ */
7457
+ _removeBundleFromReleaseMap(bundleName) {
7458
+ if (this._waitToReleaseBundles.has(bundleName)) {
7459
+ console.log(`[GCBundle] Cancel Pre Remove Bundle:${bundleName}`);
7460
+ }
7461
+ return this._waitToReleaseBundles.delete(bundleName);
7462
+ }
7463
+ /**
7464
+ * 真正移除bundle
7465
+ * @param bundle 目标bundle
7466
+ * @returns
7467
+ */
7468
+ _onRemoveBundle(bundle) {
7469
+ if (bundle && bundle.name) {
7470
+ //删除bundle的加载promise
7471
+ this._loadBunldePromiseMap.delete(bundle.name);
7472
+ //删除bundle对应的资源缓存
7473
+ this._loadPromiseMap.forEach((value, fullPath) => {
7474
+ if (this.parsePath(fullPath).bundle == bundle.name) {
7475
+ this._loadPromiseMap.delete(fullPath);
7476
+ }
7477
+ });
7478
+ if (cc.isValid(bundle)) {
7479
+ bundle.releaseAll();
7480
+ cc.assetManager.removeBundle(bundle);
7481
+ }
7482
+ //删除等待移除的bundle
7483
+ this._waitToReleaseBundles.delete(bundle.name);
7484
+ return true;
7485
+ }
7486
+ return false;
7487
+ }
7488
+ /**
7489
+ * 开始Bundle GC,只执行一次
7490
+ * @returns
7491
+ */
7492
+ _startGC() {
7493
+ if (this._startedGC) {
7494
+ return;
7495
+ }
7496
+ this._startedGC = true;
7497
+ timer.loop(GC_CD, this, this._onGC);
7498
+ }
7499
+ /**
7500
+ * GC Bundle
7501
+ * @returns
7502
+ */
7503
+ _onGC() {
7504
+ const count = this._waitToReleaseBundles.size;
7505
+ if (count == 0) {
7506
+ return;
7507
+ }
7508
+ const now = Date.now();
7509
+ this._waitToReleaseBundles.forEach((bundle) => {
7510
+ console.log(`[GCBundle] Remove Bundle:${bundle.name}`);
7511
+ this._onRemoveBundle(bundle);
7512
+ });
7513
+ this._waitToReleaseBundles.clear();
7514
+ console.log(`[GCBundle] [${count}] cost:${Date.now() - now} milliseconds`);
7515
+ }
7516
+ /**
7517
+ * 手动设置bundle的版本,可新增可以覆盖。
7518
+ * @param map
7519
+ */
7520
+ setBundleVersion(map) {
7521
+ this._bundleVersionMap = this._bundleVersionMap || new Map();
7522
+ map.forEach((value, key) => {
7523
+ this._bundleVersionMap.set(value, key);
7524
+ });
7525
+ }
7526
+ /**
7527
+ * 获取bundle的版本
7528
+ * @param bundleName
7529
+ * @returns
7530
+ */
7531
+ _getBundleVersion(bundleName) {
7532
+ return this._bundleVersionMap && this._bundleVersionMap.get(bundleName);
7533
+ }
7534
+ }
7535
+ /**
7536
+ * cocos资源加载和管理
7537
+ */
7538
+ const res = new ResourceManager();
7539
+
7540
+ var View_1;
7541
+ const { ccclass: ccclass$2, property: property$2, menu: menu$2 } = cc._decorator;
7542
+ var ViewLevel;
7543
+ (function (ViewLevel) {
7544
+ ViewLevel[ViewLevel["TOPUP"] = 500] = "TOPUP";
7545
+ ViewLevel[ViewLevel["NET"] = 400] = "NET";
7546
+ ViewLevel[ViewLevel["TUTORIAL"] = 300] = "TUTORIAL";
7547
+ ViewLevel[ViewLevel["ALERT"] = 200] = "ALERT";
7548
+ ViewLevel[ViewLevel["UI"] = 100] = "UI";
7549
+ ViewLevel[ViewLevel["BG"] = 1] = "BG";
7550
+ })(ViewLevel || (ViewLevel = {}));
7551
+ let View = View_1 = class View extends cc.Component {
7552
+ constructor() {
7553
+ super(...arguments);
7554
+ /**
7555
+ * 是否可以交互
7556
+ */
7557
+ this._touchEnabled = true;
7558
+ }
7559
+ /**
7560
+ * 是否在舞台中显示着
7561
+ */
7562
+ get inStage() {
7563
+ return cc.isValid(this.node) && this.node.activeInHierarchy;
7564
+ }
7565
+ /**
7566
+ * 视图是否响应交互
7567
+ */
7568
+ get touchEnabled() {
7569
+ return this._touchEnabled;
7570
+ }
7571
+ /**
7572
+ * 视图是否响应交互
7573
+ */
7574
+ set touchEnabled(value) {
7575
+ this._touchEnabled = value;
7576
+ if (value && !this._mask) {
7473
7577
  return;
7474
7578
  }
7475
- if (cc.sys.os == cc.sys.OS.ANDROID) {
7476
- let argsSig = this.getArgsSig(args, returnType);
7477
- console.log("callWithReturnType:", className, methodName, argsSig, args.join(","));
7478
- return cc.native.reflection.callStaticMethod(className, methodName, argsSig, ...args);
7579
+ if (!this._mask) {
7580
+ this._mask = new cc.Node();
7581
+ this._mask.name = "mask";
7582
+ let transform = this._mask.addComponent(cc.UITransform);
7583
+ const viewSize = cc.view.getVisibleSize();
7584
+ transform.setContentSize(viewSize.width, viewSize.height);
7585
+ this._mask.addComponent(cc.BlockInputEvents);
7586
+ // this.node.addChild(this.mask);
7587
+ this.node.addChild(this._mask);
7588
+ transform.priority = ViewLevel.TOPUP;
7589
+ this._mask.layer = this.node.layer;
7479
7590
  }
7480
- else if (cc.sys.os == cc.sys.OS.IOS) ;
7591
+ this._mask.active = !value;
7481
7592
  }
7482
- getArgsSig(args, returnType) {
7483
- let sig = ["("];
7484
- for (let i = 0; i < args.length; i++) {
7485
- const element = args[i];
7486
- sig.push(this.getValueTypeStr(element));
7487
- }
7488
- sig.push(")", this.getValueTypeStr(returnType));
7489
- return sig.join("");
7593
+ /**
7594
+ * 添加其他视图
7595
+ * @param view 其他视图
7596
+ * @param index 视图索引
7597
+ */
7598
+ addView(view, index) {
7599
+ view.setControl(this._control);
7600
+ view.node.parent = this.node;
7601
+ (view.node.getComponent(cc.UITransform) || view.node.addComponent(cc.UITransform)).priority = index;
7602
+ viewManager.event("open", view);
7603
+ viewManager.reportViewAnalytics("open", view);
7604
+ analytics.session.updateSessionDuration();
7490
7605
  }
7491
- getValueTypeStr(value) {
7492
- if (value == null || value == undefined) {
7493
- return "V";
7606
+ /**
7607
+ * 移除子视图
7608
+ * @param view 子视图
7609
+ * @param destroy 是否销毁,默认为true
7610
+ * @param closeEventParams 视图close事件的参数
7611
+ */
7612
+ removeView(view, destroy = true, ...closeEventParams) {
7613
+ if (view.parentView == this) {
7614
+ destroy && view.node.destroyAllChildren();
7615
+ view.node.removeFromParent();
7616
+ viewManager.event("close", view, ...closeEventParams);
7617
+ viewManager.reportViewAnalytics("close", view);
7618
+ analytics.session.updateSessionDuration();
7494
7619
  }
7495
- let typeStr = typeof value;
7496
- if (typeStr == "number") {
7497
- if (value % 1 != 0) { //float
7498
- return "F";
7499
- }
7500
- else {
7501
- return "I";
7620
+ }
7621
+ /**
7622
+ * 设置主场景所创建的Control
7623
+ * @param control
7624
+ */
7625
+ setControl(control) {
7626
+ this._control = control;
7627
+ }
7628
+ control() {
7629
+ return this._control;
7630
+ }
7631
+ /**
7632
+ * 实例化后显示到舞台之后调用,缓存视图重新显示时也会调用。
7633
+ * @param data
7634
+ */
7635
+ setData(...data) {
7636
+ }
7637
+ /**
7638
+ * 上报当前视图统计数据
7639
+ * @param event open和close以外的统计名称,名称必须为全小写,无下划线之外的其他特殊字符。
7640
+ * @param data 上报附带信息,可选参数,为空时会尝试从getAnalyticsDataOnViewEvent获取附带信息。
7641
+ */
7642
+ _report(event, data) {
7643
+ if (event == "open" || event == "close")
7644
+ return;
7645
+ viewManager.reportViewAnalytics(event, this, data);
7646
+ }
7647
+ /**
7648
+ * 播放BG音乐
7649
+ * @param path 路径 - `bundleName://path/to/asset` 目标音频地址。
7650
+ * @param fade 是否渐进式播放,默认为true
7651
+ * @param loop 是否循环 默认为true
7652
+ * @param onFinishCallBack 单次播放结束后的回调箭头函数(cocos的锅)
7653
+ * @returns 背景音乐的audioId
7654
+ *
7655
+ * @example
7656
+ * _playBG("https://server.com/game/music.mp3")
7657
+ * _playBG("main://path/to/music")
7658
+ * _playBG("resources://path/to/music")
7659
+ */
7660
+ playBG(path, fade = true, loop = true, onFinishCallBack, volume = null) {
7661
+ return __awaiter(this, void 0, void 0, function* () {
7662
+ let clip = yield res.load(path);
7663
+ if (clip) {
7664
+ audio.playMusic(clip, fade, loop, onFinishCallBack, volume);
7502
7665
  }
7666
+ });
7667
+ }
7668
+ /**
7669
+ * 播放音效
7670
+ * @param path 路径 - `bundleName://path/to/asset` 目标音频地址。
7671
+ * @param onFinishCallBack 单次播放结束后的回调箭头函数(cocos的锅)
7672
+ * @returns 音效的audioId
7673
+ */
7674
+ playEffect(path, onFinishCallBack, volume = null) {
7675
+ return __awaiter(this, void 0, void 0, function* () {
7676
+ let clip = yield res.load(path);
7677
+ return new Promise((reslove) => {
7678
+ if (clip) {
7679
+ audio.playEffect(clip, false, () => {
7680
+ onFinishCallBack && onFinishCallBack();
7681
+ reslove();
7682
+ }, volume);
7683
+ }
7684
+ });
7685
+ });
7686
+ }
7687
+ /**
7688
+ * 播放激励视频的快捷方式。
7689
+ * @param from 可选参数,可以附带广告行为的来源,以及其他需要统计的信息
7690
+ * @param stopRecorder 可选参数,是否暂停录屏, 默认为true
7691
+ */
7692
+ showRewardVideo(from, stopRecorder = true) {
7693
+ return new Promise((resolve) => {
7694
+ stopRecorder && publisher.record && publisher.record.pauseRecord();
7695
+ viewManager.closeTouch();
7696
+ //解决部分平台(tt)拉起视频时,最小化视频播放不出来的bug。
7697
+ const openTouch = () => {
7698
+ viewManager.openTouch();
7699
+ App.offShow(openTouch);
7700
+ };
7701
+ App.onShow(openTouch);
7702
+ from = from || {};
7703
+ // from.name = this.analyticsInfo ? this.analyticsInfo.name : this.name;
7704
+ publisher.ad.showRewardVideo(from).then((result) => {
7705
+ openTouch();
7706
+ stopRecorder && publisher.record && publisher.record.resumeRecord();
7707
+ resolve(result);
7708
+ }).catch(() => {
7709
+ openTouch();
7710
+ stopRecorder && publisher.record && publisher.record.resumeRecord();
7711
+ resolve(false);
7712
+ });
7713
+ });
7714
+ }
7715
+ /**
7716
+ * 分享录屏视频
7717
+ * @param analyticsName 玩法发起分享的动作来源,用于统计。
7718
+ * @param title 视频标题
7719
+ * @param topics 视频话题列表
7720
+ */
7721
+ shareRecord(analyticsName, title, topics) {
7722
+ let path = publisher.record.videoPath;
7723
+ if (path) {
7724
+ return publisher.share.shareVideo(analyticsName, { "video_title": title, "videoTopics": topics, "videoPath": path });
7503
7725
  }
7504
- else if (typeStr == "boolean") {
7505
- return "Z";
7506
- }
7507
- else if (typeStr == "string") {
7508
- return "Ljava/lang/String;";
7726
+ else {
7727
+ return new Promise((resolve) => { resolve(false); });
7509
7728
  }
7510
7729
  }
7511
- }
7512
-
7513
- /*
7514
- * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
7515
- * Digest Algorithm, as defined in RFC 1321.
7516
- * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
7517
- * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
7518
- * Distributed under the BSD License
7519
- * See http://pajhome.org.uk/crypt/md5 for more info.
7520
- */
7521
- /*
7522
- * Configurable variables. You may need to tweak these to be compatible with
7523
- * the server-side, but the defaults work in most cases.
7524
- */
7525
- var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
7526
- /*
7527
- * These are the functions you'll usually want to call
7528
- * They take string arguments and return either hex or base-64 encoded strings
7529
- */
7530
- function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
7531
- /*
7532
- * Calculate the MD5 of a raw string
7533
- */
7534
- function rstr_md5(s) {
7535
- return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
7536
- }
7537
- /*
7538
- * Convert a raw string to a hex string
7539
- */
7540
- function rstr2hex(input) {
7541
- try {
7542
- hexcase;
7730
+ /**
7731
+ * 子项重写时,必须要调用super.onDestroy()。
7732
+ *
7733
+ */
7734
+ onDestroy() {
7735
+ this.config.cache && viewManager.cancelCache(this);
7543
7736
  }
7544
- catch (e) {
7545
- hexcase = 0;
7737
+ /**
7738
+ * 父级视图
7739
+ */
7740
+ get parentView() {
7741
+ if (this.node.parent) {
7742
+ return this.node.parent.getComponent(View_1);
7743
+ }
7744
+ return null;
7745
+ }
7746
+ /**
7747
+ * 关闭视图,根据视图是否缓存选择是否销毁视图
7748
+ * @param closeEventParams 视图close事件的参数
7749
+ */
7750
+ close(...closeEventParams) {
7751
+ this.removeFromParent(!this.config.cache, ...closeEventParams);
7546
7752
  }
7547
- var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
7548
- var output = "";
7549
- var x;
7550
- for (var i = 0; i < input.length; i++) {
7551
- x = input.charCodeAt(i);
7552
- output += hex_tab.charAt((x >>> 4) & 0x0F)
7553
- + hex_tab.charAt(x & 0x0F);
7753
+ /**
7754
+ * 从父级移除视图
7755
+ * @param destroy 是否销毁,默认为true
7756
+ * @param closeEventParams 视图close事件的参数
7757
+ */
7758
+ removeFromParent(destroy = true, ...closeEventParams) {
7759
+ if (this.parentView) {
7760
+ this.parentView.removeView(this, destroy, ...closeEventParams);
7761
+ }
7554
7762
  }
7555
- return output;
7556
- }
7557
- /*
7558
- * Encode a string as utf-8.
7559
- * For efficiency, this assumes the input is valid utf-16.
7560
- */
7561
- function str2rstr_utf8(input) {
7562
- var output = "";
7563
- var i = -1;
7564
- var x, y;
7565
- while (++i < input.length) {
7566
- /* Decode utf-16 surrogate pairs */
7567
- x = input.charCodeAt(i);
7568
- y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
7569
- if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
7570
- x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
7571
- i++;
7763
+ /**
7764
+ * 直接销毁
7765
+ */
7766
+ allDestroy() {
7767
+ if (this.node && cc.isValid(this.node)) {
7768
+ this.node.parent = null;
7769
+ this.node.destroy();
7572
7770
  }
7573
- /* Encode output as utf-8 */
7574
- if (x <= 0x7F)
7575
- output += String.fromCharCode(x);
7576
- else if (x <= 0x7FF)
7577
- output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F), 0x80 | (x & 0x3F));
7578
- else if (x <= 0xFFFF)
7579
- output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), 0x80 | ((x >>> 6) & 0x3F), 0x80 | (x & 0x3F));
7580
- else if (x <= 0x1FFFFF)
7581
- output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), 0x80 | ((x >>> 12) & 0x3F), 0x80 | ((x >>> 6) & 0x3F), 0x80 | (x & 0x3F));
7582
7771
  }
7583
- return output;
7584
- }
7585
- /*
7586
- * Convert a raw string to an array of little-endian words
7587
- * Characters >255 have their high-byte silently ignored.
7588
- */
7589
- function rstr2binl(input) {
7590
- var output = Array(input.length >> 2);
7591
- for (var i = 0; i < output.length; i++)
7592
- output[i] = 0;
7593
- for (var i = 0; i < input.length * 8; i += 8)
7594
- output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
7595
- return output;
7596
- }
7597
- /*
7598
- * Convert an array of little-endian words to a string
7599
- */
7600
- function binl2rstr(input) {
7601
- var output = "";
7602
- for (var i = 0; i < input.length * 32; i += 8)
7603
- output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
7604
- return output;
7605
- }
7606
- /*
7607
- * Calculate the MD5 of an array of little-endian words, and a bit length.
7608
- */
7609
- function binl_md5(x, len) {
7610
- /* append padding */
7611
- x[len >> 5] |= 0x80 << ((len) % 32);
7612
- x[(((len + 64) >>> 9) << 4) + 14] = len;
7613
- var a = 1732584193;
7614
- var b = -271733879;
7615
- var c = -1732584194;
7616
- var d = 271733878;
7617
- for (var i = 0; i < x.length; i += 16) {
7618
- var olda = a;
7619
- var oldb = b;
7620
- var oldc = c;
7621
- var oldd = d;
7622
- a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
7623
- d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
7624
- c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
7625
- b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
7626
- a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
7627
- d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
7628
- c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
7629
- b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
7630
- a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
7631
- d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
7632
- c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
7633
- b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
7634
- a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
7635
- d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
7636
- c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
7637
- b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
7638
- a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
7639
- d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
7640
- c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
7641
- b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
7642
- a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
7643
- d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
7644
- c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
7645
- b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
7646
- a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
7647
- d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
7648
- c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
7649
- b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
7650
- a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
7651
- d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
7652
- c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
7653
- b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
7654
- a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
7655
- d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
7656
- c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
7657
- b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
7658
- a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
7659
- d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
7660
- c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
7661
- b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
7662
- a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
7663
- d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
7664
- c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
7665
- b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
7666
- a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
7667
- d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
7668
- c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
7669
- b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
7670
- a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
7671
- d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
7672
- c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
7673
- b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
7674
- a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
7675
- d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
7676
- c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
7677
- b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
7678
- a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
7679
- d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
7680
- c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
7681
- b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
7682
- a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
7683
- d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
7684
- c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
7685
- b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
7686
- a = safe_add(a, olda);
7687
- b = safe_add(b, oldb);
7688
- c = safe_add(c, oldc);
7689
- d = safe_add(d, oldd);
7772
+ getAnalyticsDataOnViewEvent(event) {
7773
+ return {};
7690
7774
  }
7691
- return Array(a, b, c, d);
7692
- }
7693
- /*
7694
- * These functions implement the four basic operations the algorithm uses.
7695
- */
7696
- function md5_cmn(q, a, b, x, s, t) {
7697
- return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
7698
- }
7699
- function md5_ff(a, b, c, d, x, s, t) {
7700
- return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
7701
- }
7702
- function md5_gg(a, b, c, d, x, s, t) {
7703
- return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
7704
- }
7705
- function md5_hh(a, b, c, d, x, s, t) {
7706
- return md5_cmn(b ^ c ^ d, a, b, x, s, t);
7707
- }
7708
- function md5_ii(a, b, c, d, x, s, t) {
7709
- return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
7710
- }
7711
- /*
7712
- * Add integers, wrapping at 2^32. This uses 16-bit operations internally
7713
- * to work around bugs in some JS interpreters.
7714
- */
7715
- function safe_add(x, y) {
7716
- var lsw = (x & 0xFFFF) + (y & 0xFFFF);
7717
- var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
7718
- return (msw << 16) | (lsw & 0xFFFF);
7719
- }
7720
- /*
7721
- * Bitwise rotate a 32-bit number to the left.
7722
- */
7723
- function bit_rol(num, cnt) {
7724
- return (num << cnt) | (num >>> (32 - cnt));
7725
- }
7726
- const md5 = hex_md5;
7775
+ };
7776
+ /**
7777
+ * View类的Class名称
7778
+ */
7779
+ View.type = "View";
7780
+ View = View_1 = __decorate([
7781
+ ccclass$2("View"),
7782
+ menu$2("基础视图/View")
7783
+ /**
7784
+ * cocos引擎下的视图管理类
7785
+ */
7786
+ ], View);
7727
7787
 
7728
7788
  /**
7729
- * cocos下的本地持久化实现类
7789
+ * 注册进入视图时,上报的事件名称,不注册则上报视图配置的name属性
7790
+ * @param analyticsName 可选参数,默认为view的name,可以指定为上报的中文名称
7791
+ * @param group 分组,默认为default,方便分类统计
7792
+ * @returns
7730
7793
  */
7731
- class CocosStorageUtils {
7732
- removeValue(key) {
7733
- if (!window['CC_DEBUG']) {
7734
- key = md5(key);
7735
- }
7736
- sys.localStorage.removeItem(key);
7737
- }
7738
- setValue(key, value) {
7739
- if (!window['CC_DEBUG']) {
7740
- key = md5(key);
7794
+ function viewAnalytics(analyticsName, group = "default") {
7795
+ return function (target, propertyKey) {
7796
+ viewManager.registerAnalytics(target, analyticsName, group);
7797
+ };
7798
+ }
7799
+ /**
7800
+ * 视图管理类
7801
+ */
7802
+ class ViewManager {
7803
+ /**
7804
+ * 注册视图上报事件的视图名称,一般为中文方便数据分辨
7805
+ * @param viewClass
7806
+ * @param analyticsName 可选参数,默认为view的name,可以指定为上报的中文名称
7807
+ * @param group 分组,可选参数,默认为default,方便分类统计
7808
+ */
7809
+ registerAnalytics(viewClass, analyticsName, group = "default") {
7810
+ let config = this._getViewConfig(viewClass);
7811
+ if (config) {
7812
+ this._viewAnalyticsMap.set(config.name, { name: analyticsName || config.name, group });
7741
7813
  }
7742
- try {
7743
- sys.localStorage.setItem(key, value);
7814
+ else {
7815
+ throw new Error(`未获取到视图${viewClass}的配置`);
7744
7816
  }
7745
- catch (error) {
7746
- console.error('Failed to set storage value:', "key:", key, "value:", value, "length:", String(value).length, "error:", error);
7817
+ }
7818
+ /**
7819
+ * 注册视图类对应的视图配置
7820
+ * @param viewName 视图名称
7821
+ * @param config 视图配置
7822
+ */
7823
+ registerView(viewName, config) {
7824
+ if (this._viewConfigMap.has(viewName)) {
7825
+ throw new Error(`已经存在名称为${viewName}的View`);
7747
7826
  }
7827
+ this._viewConfigMap.set(viewName, config);
7748
7828
  }
7749
- getValue(key) {
7750
- if (!window['CC_DEBUG']) {
7751
- key = md5(key);
7829
+ /**
7830
+ * 注册closeTouch默认遮罩视图
7831
+ * @param config 视图配置|Class|名称
7832
+ */
7833
+ registerMaskView(config) {
7834
+ let viewConfig = this._getViewConfig(config);
7835
+ if (!viewConfig) {
7836
+ throw new Error(`未获取到默认遮罩视图${config}的配置`);
7752
7837
  }
7753
- return sys.localStorage.getItem(key);
7754
- }
7755
- clear() {
7756
- sys.localStorage.clear();
7757
- }
7758
- }
7759
-
7760
- /**
7761
- * 任务队列
7762
- */
7763
- class TaskSequence extends Task {
7764
- constructor() {
7765
- super();
7766
- this._taskMap = new Map();
7767
- this._index = 0;
7838
+ viewConfig.cache = true;
7839
+ viewConfig.zIndex = ViewLevel.TOPUP;
7840
+ this._defaultMaskViewConfig = viewConfig;
7768
7841
  }
7769
- addQuickly(taskCaller, taskFun, ...taskData) {
7770
- let task = new Task();
7771
- taskData.unshift(task);
7772
- task.start = (data) => {
7773
- taskFun.apply(taskCaller, taskData);
7774
- };
7775
- this.addTask(task);
7776
- return task;
7842
+ getViewConfig(config) {
7843
+ return Object.assign({}, this._getViewConfig(config));
7777
7844
  }
7778
- addTask(value, ...data) {
7779
- if (this._taskMap.has(value)) {
7780
- throw new Error("重复添加!");
7845
+ /**
7846
+ * [内部直接获取]获取视图配置
7847
+ * @param config
7848
+ * @returns
7849
+ */
7850
+ _getViewConfig(config) {
7851
+ if (config == null) {
7852
+ console.error(`[view] 获取视图配置,参数不能为空`);
7853
+ return null;
7781
7854
  }
7782
- this._taskMap.set(value, data);
7783
- }
7784
- removeTask(value) {
7785
- return this._taskMap.delete(value);
7786
- }
7787
- start(...data) {
7788
- this._keys = this._taskMap.keys();
7789
- this._index = 0;
7790
- this._tryNext();
7791
- }
7792
- _tryNext() {
7793
- let next = this._keys.next();
7794
- if (!next.done) {
7795
- let task = next.value;
7796
- task.on(Task.Event.COMPLETE, this, this._subTaskEventHandler);
7797
- task.on(Task.Event.PROGRESS, this, this._subTaskEventHandler);
7798
- task.on(Task.Event.ERROR, this, this._subTaskEventHandler);
7799
- task.start(this._taskMap.get(task));
7855
+ if (typeof config == "string") {
7856
+ if (!this._viewConfigMap.has(config)) {
7857
+ console.error(`[view]${config}视图配置未注册`);
7858
+ return null;
7859
+ }
7860
+ return this._viewConfigMap.get(config);
7800
7861
  }
7801
- else {
7802
- //结束
7803
- this.onComplete();
7862
+ if ("path" in config) {
7863
+ return config;
7804
7864
  }
7805
- }
7806
- _subTaskEventHandler(key, target, data) {
7807
- if (key == Task.Event.ERROR) {
7808
- this.onError(data.code, data.msg);
7809
- return;
7865
+ let values = this._viewConfigMap.values();
7866
+ while (true) {
7867
+ let item = values.next();
7868
+ if (!item || item.done) {
7869
+ return null;
7870
+ }
7871
+ if (item.value['viewClass'] == config) {
7872
+ return item.value;
7873
+ }
7810
7874
  }
7811
- if (key == Task.Event.COMPLETE) {
7812
- target.offAllEvent();
7813
- target.destroy();
7814
- this._index++;
7815
- this.onProgress(this._index / this._taskMap.size);
7816
- this._tryNext();
7875
+ }
7876
+ constructor() {
7877
+ this._viewConfigMap = new Map();
7878
+ this._viewAnalyticsMap = new Map();
7879
+ this._currentStack = [];
7880
+ this._viewCache = new Map();
7881
+ this._touchLocks = new Set();
7882
+ if (ViewManager.created) {
7883
+ throw new Error("ViewManager 是单例");
7817
7884
  }
7885
+ ViewManager.created = true;
7818
7886
  }
7819
- reset() {
7820
- this.offAllEvent();
7821
- this._taskMap.forEach((data, task) => {
7822
- task.reset();
7887
+ /**
7888
+ * 场景启动后设置场景,不建议手动调用
7889
+ * @param root
7890
+ */
7891
+ setRoot(root) {
7892
+ this._viewCache.forEach((views) => {
7893
+ for (const view of views) {
7894
+ view.allDestroy();
7895
+ }
7823
7896
  });
7824
- this._taskMap.clear();
7825
- this._keys = null;
7826
- this._index = 0;
7897
+ this._viewCache.clear();
7898
+ this._currentStack.length = 0;
7899
+ this.event("open", root);
7900
+ this.reportViewAnalytics("open", root);
7901
+ this._scene = root;
7902
+ this._currentView = null;
7903
+ businessCenter && businessCenter.start(RewardVideoMaskBusiness);
7827
7904
  }
7828
- destroy() {
7829
- super.destroy();
7830
- this._taskMap.forEach((data, task) => {
7831
- task.reset();
7905
+ /**
7906
+ * 切换场景
7907
+ * @param config 目标场景的配置|Class|名称
7908
+ * @param data
7909
+ * @returns
7910
+ */
7911
+ switchScene(config, ...data) {
7912
+ return __awaiter(this, void 0, void 0, function* () {
7913
+ config = this._getViewConfig(config);
7914
+ let view = this.getCacheView(config);
7915
+ if (view) {
7916
+ view = yield this._switchView(view, ...data);
7917
+ }
7918
+ else {
7919
+ view = yield this._switchViewByConfig(config, ...data);
7920
+ }
7921
+ // this.cacheView(view);
7922
+ // this._currentStack.push(config);
7923
+ return view;
7832
7924
  });
7833
- this._taskMap.clear();
7834
- this._keys = null;
7835
- this._index = 0;
7836
7925
  }
7837
- }
7838
-
7839
- /**
7840
- * 视图加载器
7841
- */
7842
- class IViewLoader extends EventDispatcher {
7843
- constructor(pool) {
7844
- super();
7845
- this._initializer = new TaskSequence();
7846
- this._pool = pool;
7926
+ /**
7927
+ * 当前场景
7928
+ * @returns
7929
+ */
7930
+ scene() {
7931
+ return this._scene;
7847
7932
  }
7848
- load(task) {
7849
- if (this._asset) {
7850
- task && task.onComplete();
7851
- return;
7933
+ /**
7934
+ * 开启当前场景的可交互性
7935
+ * @param token closeTouch返回的触摸锁令牌。传入时仅释放该锁,所有锁释放后才会真正开启触摸;不传则清空全部触摸锁并开启触摸。
7936
+ */
7937
+ openTouch(token) {
7938
+ if (token) {
7939
+ this._touchLocks.delete(token);
7852
7940
  }
7853
- if (task) {
7854
- this._initializer.once(Task.Event.ERROR, this, (type, a, error) => {
7855
- task.onError(error.code, error.msg);
7856
- });
7857
- this._initializer.on(Task.Event.PROGRESS, this, (type, a, percent) => {
7858
- task.onProgress(percent);
7859
- });
7941
+ else {
7942
+ this._touchLocks.clear();
7860
7943
  }
7861
- this._initializer.once(Task.Event.COMPLETE, this, () => {
7862
- this._initializer.reset();
7863
- task && task.onComplete();
7864
- });
7865
- this._initializer.start();
7866
- }
7867
- destroy() {
7868
- this.offAll();
7869
- this._initializer.reset();
7870
- this._initializer = null;
7871
- this._asset = null;
7872
- this._pool = null;
7873
- }
7874
- reset() {
7875
- this._initializer.reset();
7876
- this.offAll();
7877
- this._asset = null;
7878
- }
7879
- recover() {
7880
- this._pool.recover(this);
7881
- }
7882
- }
7883
-
7884
- const GC_CD = 60 * 1000;
7885
- /**
7886
- * 资源管理
7887
- */
7888
- class ResourceManager {
7889
- constructor() {
7890
- this._loadPromiseMap = new Map();
7891
- this._loadBunldePromiseMap = new Map();
7892
- this._waitToReleaseBundles = new Map();
7893
- this._startedGC = false;
7944
+ this._applyTouchState();
7894
7945
  }
7895
- preload(path, task) {
7946
+ /**
7947
+ * 关闭当前场景的可交互性
7948
+ * @param delay 可选参数,默认200毫秒,显示maskView的延迟时间。
7949
+ * @param maskViewConfig 可选参数,默认为空白,要显示的遮罩试图。
7950
+ * @returns 当前触摸锁令牌,可传给openTouch精确释放本次锁。
7951
+ */
7952
+ closeTouch(delay = 200, maskViewConfig = null) {
7896
7953
  return __awaiter(this, void 0, void 0, function* () {
7897
- let paths = typeof path === "string" ? [path] : path;
7898
- let pathInfoList = paths.map((value) => {
7899
- return this.parsePath(value);
7900
- });
7901
- let loadPromiseList = pathInfoList.map((info) => {
7902
- return !info.isRemote ? this._preLoadFromBundle(info, task) : this._preLoadFromRemote(info, task);
7903
- });
7904
- return Promise.all(loadPromiseList).then((value) => {
7905
- return value.length == 1 ? value[0] : value;
7906
- });
7954
+ const token = this._lockTouch();
7955
+ let config = maskViewConfig == null ? this._defaultMaskViewConfig : this._getViewConfig(maskViewConfig);
7956
+ if (!config) {
7957
+ return token;
7958
+ }
7959
+ if (delay <= 0) {
7960
+ yield this._showMaskView(config, token);
7961
+ return token;
7962
+ }
7963
+ timer.once(delay, this, this._showMaskView, [config, token]);
7964
+ return token;
7907
7965
  });
7908
7966
  }
7909
- preLoadScene(path, task) {
7967
+ _lockTouch() {
7968
+ const token = Symbol("touch-lock");
7969
+ this._touchLocks.add(token);
7970
+ this._applyTouchState();
7971
+ return token;
7972
+ }
7973
+ _applyTouchState() {
7974
+ const locked = this._touchLocks.size > 0;
7975
+ if (!locked) {
7976
+ timer.clear(this, this._showMaskView);
7977
+ if (this._currentMaskView) {
7978
+ this._currentMaskView.removeFromParent(true);
7979
+ this._currentMaskView = null;
7980
+ }
7981
+ }
7982
+ if (this._scene) {
7983
+ this._scene.touchEnabled = !locked;
7984
+ }
7985
+ }
7986
+ _showMaskView(maskViewConfig, token) {
7910
7987
  return __awaiter(this, void 0, void 0, function* () {
7911
- let paths = typeof path === "string" ? [path] : path;
7912
- let pathInfoList = paths.map((value) => {
7913
- let result = this.parsePath(value);
7914
- if (result.isRemote) {
7915
- throw new Error(`不支持从远程预加载场景${value}`);
7988
+ if (!this._scene || !this._touchLocks.has(token) || this._currentMaskView) {
7989
+ return;
7990
+ }
7991
+ let view = this.getCacheView(maskViewConfig);
7992
+ if (view) {
7993
+ view = yield this._addView(view, this._scene);
7994
+ }
7995
+ else {
7996
+ view = yield this._loadViewByConfig(maskViewConfig, this._scene, "显示遮罩视图错误");
7997
+ this.cacheView(view);
7998
+ }
7999
+ if (!this._touchLocks.has(token)) {
8000
+ view.removeFromParent(true);
8001
+ return;
8002
+ }
8003
+ this._currentMaskView = view;
8004
+ timer.frameNext(this, () => {
8005
+ if (this._currentMaskView == view && this._touchLocks.has(token)) {
8006
+ view.setData();
7916
8007
  }
7917
- return result;
7918
- });
7919
- let loadPromiseList = pathInfoList.map((info) => __awaiter(this, void 0, void 0, function* () {
7920
- let bundle = yield this.getBundle(info.bundle);
7921
- return new Promise((resolve) => {
7922
- if (!bundle) {
7923
- resolve(null);
7924
- task && task.onError("preLoadScene", `加载${info.fullPath}时 bundle${info.bundle}加载失败`);
7925
- }
7926
- bundle.preloadScene(info.path, (error) => {
7927
- if (error) {
7928
- resolve(null);
7929
- task && task.onError(error.name, error.message);
7930
- }
7931
- resolve(info.fullPath);
7932
- task && task.onComplete();
7933
- });
7934
- });
7935
- }));
7936
- return Promise.all(loadPromiseList).then((value) => {
7937
- return value.length > 0 ? (value.length == 1 ? value[0] : value) : null;
7938
8008
  });
7939
8009
  });
7940
8010
  }
7941
- _preLoadFromRemote(info, task) {
8011
+ /**
8012
+ * 当前主视图
8013
+ * @returns
8014
+ */
8015
+ view() {
8016
+ return this._currentView;
8017
+ }
8018
+ /**
8019
+ * 切换主视图到目标视图
8020
+ * @param target 目标视图的配置|Class|名称
8021
+ * @param datas 目标视图初始化参数
8022
+ */
8023
+ switchTo(config, ...data) {
7942
8024
  return __awaiter(this, void 0, void 0, function* () {
7943
- if (!info.isRemote) {
7944
- throw new Error(`${info.fullPath}不是远程资源地址`);
8025
+ config = this._getViewConfig(config);
8026
+ if (!this._scene) {
8027
+ throw new Error("根View不存在");
7945
8028
  }
7946
- if (info.isDir) {
7947
- throw new Error(`不支持对远程Dir的加载`);
8029
+ let view = this.getCacheView(config);
8030
+ if (view) {
8031
+ view = yield this._switchView(view, ...data);
7948
8032
  }
7949
- return new Promise((resolve, reject) => {
7950
- cc.assetManager.loadRemote(info.fullPath, (error, asset) => {
7951
- if (error) {
7952
- resolve(null);
7953
- task && task.onError(error.name, error.message);
7954
- }
7955
- else {
7956
- resolve(info.fullPath);
7957
- task && task.onComplete();
7958
- }
7959
- });
7960
- });
8033
+ else {
8034
+ view = yield this._switchViewByConfig(config, ...data);
8035
+ }
8036
+ this.cacheView(view);
8037
+ this._currentStack.push(config);
8038
+ return view;
7961
8039
  });
7962
8040
  }
7963
- _preLoadFromBundle(info, task) {
8041
+ /**
8042
+ * 切回当前主视图到上一个主视图。
8043
+ * @param data
8044
+ * @returns
8045
+ */
8046
+ switchBack(...data) {
7964
8047
  return __awaiter(this, void 0, void 0, function* () {
7965
- let bundle = yield this.getBundle(info.bundle);
7966
- if (!bundle) {
7967
- task && task.onError("_preLoadFromBundle", `加载${info.fullPath}时 bundle${info.bundle}加载失败`);
8048
+ if (this._currentStack.length == 0) {
8049
+ console.warn("上一个视图不存在");
7968
8050
  return null;
7969
8051
  }
7970
- return new Promise((resolve) => {
7971
- let onProgress = (finish, total) => {
7972
- task && task.onProgress(finish / total);
7973
- };
7974
- let onComplete = (error) => {
7975
- if (error) {
7976
- resolve(null);
7977
- task && task.onError(error.name, error.message);
7978
- }
7979
- else {
7980
- resolve(info.fullPath);
7981
- task && task.onComplete();
7982
- }
7983
- };
7984
- if (info.path == "") {
7985
- onComplete(null);
7986
- }
7987
- else if (!info.isDir) {
7988
- bundle.preload(info.path, onProgress, onComplete);
7989
- }
7990
- else {
7991
- bundle.preloadDir(info.path, onProgress, onComplete);
7992
- }
7993
- });
8052
+ //移除当前视图config
8053
+ this._currentStack.pop();
8054
+ //获取之前视图config
8055
+ let lastViewConfig = this._currentStack.pop();
8056
+ if (!lastViewConfig) {
8057
+ console.warn("上个主视图为空,");
8058
+ return null;
8059
+ }
8060
+ return yield this.switchTo(lastViewConfig, ...data);
7994
8061
  });
7995
8062
  }
7996
- load(path, assetType, task) {
8063
+ _switchView(view, ...datas) {
7997
8064
  return __awaiter(this, void 0, void 0, function* () {
7998
- let paths = typeof path === "string" ? [path] : path;
7999
- let pathInfoList = paths.map((value) => {
8000
- return this.parsePath(value);
8001
- });
8002
- let result = [];
8003
- for (const info of pathInfoList) {
8004
- if (!info.isRemote) {
8005
- let assets = yield this._loadFromBundle(info, assetType, task);
8006
- if (assets instanceof cc.Asset) {
8007
- result.push(assets);
8008
- }
8009
- else {
8010
- result.push(...assets);
8011
- }
8012
- continue;
8013
- }
8014
- let asset = yield this._loadfromRemote(info, task);
8015
- if (assetType === cc.SpriteFrame) {
8016
- asset = cc.SpriteFrame.createWithImage(asset);
8017
- }
8018
- result.push(asset);
8019
- }
8020
- return typeof path === "string" ? result[0] : result;
8065
+ this._currentView && this._currentView.removeFromParent(!this._currentView.config.cache);
8066
+ this._currentView = null;
8067
+ this._currentView = view;
8068
+ this._scene.addView(this._currentView, view.config.zIndex);
8069
+ this._currentView.setData(...datas);
8070
+ return this._currentView;
8021
8071
  });
8022
8072
  }
8023
- _loadFromBundle(info, type, task) {
8073
+ _switchViewByConfig(viewConfig, ...datas) {
8024
8074
  return __awaiter(this, void 0, void 0, function* () {
8025
- let bundle = yield this.getBundle(info.bundle);
8026
- if (!bundle) {
8027
- task && task.onError("_loadFromBundle", `加载${info.fullPath}时 bundle${info.bundle}加载失败`);
8028
- return null;
8075
+ const touchToken = this._lockTouch();
8076
+ let loader;
8077
+ try {
8078
+ loader = yield this.loadView(viewConfig);
8029
8079
  }
8030
- if (this._loadPromiseMap.has(info.fullPath)) {
8031
- return this._loadPromiseMap.get(info.fullPath).then((value) => {
8032
- task && task.onComplete();
8033
- return value;
8034
- });
8080
+ catch (error) {
8081
+ this.openTouch(touchToken);
8082
+ console.error(`切换视图错误 code:${error.code}, msg:${error.msg || error.message}`);
8083
+ throw new Error(`切换视图错误 code:${error.code}, msg:${error.msg || error.message}`);
8035
8084
  }
8036
- let promise = new Promise((resolve) => {
8037
- let onProgress = (finish, total) => {
8038
- task && task.onProgress(finish / total);
8039
- };
8040
- let onComplete = (error, assets) => {
8041
- if (error) {
8042
- console.error("加载资源发生错误", info, error);
8043
- resolve(null);
8044
- task && task.onError(error.name, error.message);
8045
- }
8046
- else {
8047
- resolve(assets);
8048
- task && task.onComplete();
8049
- }
8050
- };
8051
- if (info.path == "") {
8052
- onComplete(null, null);
8053
- }
8054
- else if (!info.isDir) {
8055
- bundle.load(info.path, type, onProgress, onComplete);
8056
- }
8057
- else {
8058
- bundle.loadDir(info.path, type, onProgress, onComplete);
8059
- }
8060
- });
8061
- this._loadPromiseMap.set(info.fullPath, promise);
8062
- return promise;
8063
- });
8064
- }
8065
- _loadfromRemote(info, task) {
8066
- if (!info.isRemote) {
8067
- throw new Error(`${info.fullPath}不是远程资源地址`);
8068
- }
8069
- if (info.isDir) {
8070
- throw new Error(`不支持对远程Dir的加载`);
8071
- }
8072
- if (this._loadPromiseMap.has(info.fullPath)) {
8073
- return this._loadPromiseMap.get(info.fullPath);
8074
- }
8075
- let promise = new Promise((resolve) => {
8076
- cc.assetManager.loadRemote(info.fullPath, (error, asset) => {
8077
- if (error) {
8078
- resolve(null);
8079
- task && task.onError(error.name, error.message);
8080
- }
8081
- else {
8082
- resolve(asset);
8083
- task && task.onComplete();
8084
- }
8085
+ let name = viewConfig.name || viewConfig.path.substring(viewConfig.path.lastIndexOf("/") + 1);
8086
+ this._currentView && this._currentView.removeFromParent(!this._currentView.config.cache);
8087
+ this._currentView = null;
8088
+ let view = loader.initView(name, true);
8089
+ view.name = name;
8090
+ view.config = viewConfig;
8091
+ view.analyticsInfo = this._viewAnalyticsMap.get(viewConfig.name);
8092
+ if (view['addToBG']) {
8093
+ this.setRoot(view);
8094
+ }
8095
+ else {
8096
+ this._currentView = view;
8097
+ this._scene.addView(view, viewConfig.zIndex);
8098
+ }
8099
+ timer.frameNext(this, () => {
8100
+ this.openTouch(touchToken);
8101
+ view.setData(...datas);
8085
8102
  });
8103
+ return view;
8086
8104
  });
8087
- this._loadPromiseMap.set(info.fullPath, promise);
8088
- return promise;
8089
- }
8090
- /**
8091
- * 解析资源路径成PathInfo
8092
- * @param fullPath - 资源路径应该符合bundle://cc.path/to/resource格式
8093
- * @returns - `PathInfo` 资源信息
8094
- */
8095
- parsePath(fullPath) {
8096
- let tempPath = fullPath.split("://");
8097
- if (tempPath.length != 2) {
8098
- throw new Error(`资源地址${fullPath}格式错误,应该符合bundle://cc.path/to/resource格式`); //.suffix
8099
- }
8100
- let isDir = fullPath.charAt(fullPath.length - 1) == "/";
8101
- let bundle = tempPath[0];
8102
- let isRemote = bundle === "https" || bundle === "http";
8103
- let suffix = cc.path.extname(fullPath).toLowerCase();
8104
- let simplePath = suffix == "" ? tempPath[1] : tempPath[1].replace(suffix, "");
8105
- return { bundle, path: simplePath, isRemote, isDir, fullPath };
8106
- }
8107
- /**
8108
- * 获取目标bundle的资源的完整路径
8109
- * @param bundleName - 资源所在bundle名称
8110
- * @param subPath - 可选参数, 相对子路径
8111
- * @returns
8112
- */
8113
- getPath(bundleName, subPath = "") {
8114
- if (subPath.includes("://")) {
8115
- return subPath;
8116
- }
8117
- return `${bundleName}://${subPath}`;
8118
8105
  }
8119
8106
  /**
8120
- * 获取主包下资源的完整路径
8121
- * @param subPath 资源子路径
8122
- * @returns
8107
+ * 通过视图配置添加视图
8108
+ * @param viewConfig 要添加的视图配置|Class|名称
8109
+ * @param parent 父级视图,默认为当前主视图,即viewMananger.current()
8110
+ * @param datas 传入setData的数据
8123
8111
  */
8124
- getPathInMain(subPath) {
8125
- return this.getPath("main", subPath);
8112
+ addView(config, parent, ...datas) {
8113
+ return __awaiter(this, void 0, void 0, function* () {
8114
+ config = this._getViewConfig(config);
8115
+ parent = parent || this._currentView;
8116
+ if (!parent) {
8117
+ throw new Error("当前View不存在, 且未传入父级视图");
8118
+ }
8119
+ let view = this.getCacheView(config);
8120
+ if (view) {
8121
+ view = yield this._addView(view, parent, ...datas);
8122
+ }
8123
+ else {
8124
+ view = yield this._addViewbyConfig(config, parent, ...datas);
8125
+ }
8126
+ this.cacheView(view);
8127
+ return view;
8128
+ });
8126
8129
  }
8127
- /**
8128
- * 获取动态包下资源的完整路径
8129
- * @param subPath 资源子路径
8130
- * @returns
8131
- */
8132
- getPathInResources(subPath) {
8133
- return this.getPath("resources", subPath);
8130
+ _addView(view, parent, ...datas) {
8131
+ return __awaiter(this, void 0, void 0, function* () {
8132
+ parent.addView(view, view.config.zIndex);
8133
+ view.setData(...datas);
8134
+ return view;
8135
+ });
8134
8136
  }
8135
- /**
8136
- * 加载Bundle
8137
- * @param bundleName Bundle名称
8138
- * @returns `Promise<cc.AssetManager.Bundle>`
8139
- */
8140
- getBundle(bundleName) {
8141
- this._removeBundleFromReleaseMap(bundleName);
8142
- this._startGC();
8143
- if (this._loadBunldePromiseMap.has(bundleName)) {
8144
- return this._loadBunldePromiseMap.get(bundleName);
8145
- }
8146
- let promise = new Promise((resolve) => {
8147
- let bundle = cc.assetManager.getBundle(bundleName);
8148
- if (!!bundle) {
8149
- resolve(bundle);
8150
- return;
8137
+ _addViewbyConfig(config, parent, ...datas) {
8138
+ return __awaiter(this, void 0, void 0, function* () {
8139
+ const touchToken = this._lockTouch();
8140
+ let view;
8141
+ try {
8142
+ view = yield this._loadViewByConfig(config, parent, "添加视图错误");
8151
8143
  }
8152
- let version = this._getBundleVersion(bundleName);
8153
- cc.assetManager.loadBundle(bundleName, version ? { version: version } : null, (error, bundle) => {
8154
- if (error) {
8155
- console.error(`LoadBundle ${bundleName} Error:`, error);
8156
- resolve(null);
8157
- }
8158
- else {
8159
- resolve(bundle);
8160
- }
8144
+ catch (error) {
8145
+ this.openTouch(touchToken);
8146
+ throw error;
8147
+ }
8148
+ timer.frameNext(this, () => {
8149
+ this.openTouch(touchToken);
8150
+ view.setData(...datas);
8161
8151
  });
8152
+ return view;
8162
8153
  });
8163
- this._loadBunldePromiseMap.set(bundleName, promise);
8164
- return promise;
8165
8154
  }
8166
- /**
8167
- * bundle是否被加载过,且有效
8168
- * @param bundleName
8169
- * @returns
8170
- */
8171
- isBundleValid(bundleName) {
8155
+ _loadViewByConfig(config, parent, errorPrefix) {
8172
8156
  return __awaiter(this, void 0, void 0, function* () {
8173
- if (this._loadBunldePromiseMap.has(bundleName)) {
8174
- let bundle = yield this._loadBunldePromiseMap.get(bundleName);
8175
- return bundle && cc.isValid(bundle);
8157
+ let loader;
8158
+ try {
8159
+ loader = yield this.loadView(config);
8176
8160
  }
8177
- return false;
8161
+ catch (error) {
8162
+ console.error(`${errorPrefix} code:${error.code}, msg:${error.msg || error.message}`);
8163
+ throw new Error(`${errorPrefix} code:${error.code}, msg:${error.msg || error.message}`);
8164
+ }
8165
+ let name = config.name || config.path.substring(config.path.lastIndexOf("/") + 1);
8166
+ let view = loader.initView(name, true);
8167
+ view.name = name;
8168
+ view.config = config;
8169
+ view.analyticsInfo = this._viewAnalyticsMap.get(config.name);
8170
+ parent.addView(view, config.zIndex);
8171
+ return view;
8178
8172
  });
8179
8173
  }
8180
8174
  /**
8181
- * 移除并销毁bundle,以及bundle下所有资源。
8182
- * @param bundleName bundle名称
8183
- * @param delay 是否延后销毁,默认为true
8184
- * @returns
8175
+ * 加载视图到内存,之后还需要调用loader.initView接口获取view
8176
+ * @param config 要加载的视图配置|Class|名称
8177
+ * @param task 任务载体
8185
8178
  */
8186
- removeBundle(bundleName, delay = true) {
8187
- return __awaiter(this, void 0, void 0, function* () {
8188
- if (this.isBundleValid(bundleName)) {
8189
- let bundle = yield this._loadBunldePromiseMap.get(bundleName);
8190
- if (delay) {
8191
- this._pushBundleToReleaseMap(bundle);
8192
- return true;
8193
- }
8194
- return this._onRemoveBundle(bundle);
8195
- }
8196
- return false;
8179
+ loadView(config, task) {
8180
+ return new Promise((resolve, reject) => {
8181
+ config = this._getViewConfig(config);
8182
+ let loader = this.impl.getLoader(config).init(config);
8183
+ task = task || new Task();
8184
+ task.once(Task.Event.COMPLETE, this, () => {
8185
+ resolve(loader);
8186
+ });
8187
+ task.once(Task.Event.ERROR, this, (type, task, reason) => {
8188
+ reject(reason);
8189
+ });
8190
+ loader.load(task);
8197
8191
  });
8198
8192
  }
8199
8193
  /**
8200
- * 推送bundle到GC队列
8201
- * @param bundle
8194
+ * 获取缓存视图
8195
+ * @param config
8196
+ * @returns
8202
8197
  */
8203
- _pushBundleToReleaseMap(bundle) {
8204
- if (bundle && cc.isValid(bundle)) {
8205
- console.log(`[GCBundle] Pre Remove Bundle:${bundle.name}`);
8206
- this._waitToReleaseBundles.set(bundle.name, bundle);
8198
+ getCacheView(config) {
8199
+ config = this._getViewConfig(config);
8200
+ let views = this._viewCache.get(config.path);
8201
+ if (!views || views.length == 0) {
8202
+ return null;
8203
+ }
8204
+ for (const view of views) {
8205
+ if (!view.inStage) {
8206
+ return view;
8207
+ }
8207
8208
  }
8209
+ return null;
8208
8210
  }
8209
8211
  /**
8210
- * 删除等待销毁的bundle,如果有
8211
- * @param bundleName
8212
+ * 缓存视图
8213
+ * @param view
8214
+ * @param force 默认为false,不考虑view.config.cache的值,强制增加到缓存
8212
8215
  * @returns
8213
8216
  */
8214
- _removeBundleFromReleaseMap(bundleName) {
8215
- if (this._waitToReleaseBundles.has(bundleName)) {
8216
- console.log(`[GCBundle] Cancel Pre Remove Bundle:${bundleName}`);
8217
+ cacheView(view, force = false) {
8218
+ if (!view || !view.config || (!view.config.cache && !force)) {
8219
+ return false;
8217
8220
  }
8218
- return this._waitToReleaseBundles.delete(bundleName);
8221
+ let views = this._viewCache.get(view.config.path);
8222
+ if (!views) {
8223
+ views = [view];
8224
+ this._viewCache.set(view.config.path, views);
8225
+ return true;
8226
+ }
8227
+ else if (!views.includes(view)) {
8228
+ views.push(view);
8229
+ return true;
8230
+ }
8231
+ return false;
8219
8232
  }
8220
8233
  /**
8221
- * 真正移除bundle
8222
- * @param bundle 目标bundle
8234
+ * 从缓存列表中移除视图。
8235
+ * @param view
8223
8236
  * @returns
8224
8237
  */
8225
- _onRemoveBundle(bundle) {
8226
- if (bundle && bundle.name) {
8227
- //删除bundle的加载promise
8228
- this._loadBunldePromiseMap.delete(bundle.name);
8229
- //删除bundle对应的资源缓存
8230
- this._loadPromiseMap.forEach((value, fullPath) => {
8231
- if (this.parsePath(fullPath).bundle == bundle.name) {
8232
- this._loadPromiseMap.delete(fullPath);
8233
- }
8234
- });
8235
- if (cc.isValid(bundle)) {
8236
- bundle.releaseAll();
8237
- cc.assetManager.removeBundle(bundle);
8238
- }
8239
- //删除等待移除的bundle
8240
- this._waitToReleaseBundles.delete(bundle.name);
8238
+ cancelCache(view) {
8239
+ if (!view || !view.config || !view.config.path) {
8240
+ return false;
8241
+ }
8242
+ let views = this._viewCache.get(view.config.path);
8243
+ if (!views || views.length == 0) {
8244
+ return false;
8245
+ }
8246
+ const index = views.indexOf(view);
8247
+ if (index != -1) {
8248
+ views.splice(index, 1);
8241
8249
  return true;
8242
8250
  }
8243
8251
  return false;
8244
8252
  }
8245
8253
  /**
8246
- * 开始Bundle GC,只执行一次
8247
- * @returns
8254
+ * [快捷方式]增加视图打开的事件监听
8255
+ * @param targetView 目标视图Class|名称
8256
+ * @param listener 响应回调
8257
+ * @param caller 回调this
8258
+ * @param once 是否只监听对应视图打开一次。
8259
+ * @param args 其他参数
8248
8260
  */
8249
- _startGC() {
8250
- if (this._startedGC) {
8251
- return;
8252
- }
8253
- this._startedGC = true;
8254
- timer.loop(GC_CD, this, this._onGC);
8261
+ onViewOpen(targetView, caller, listener, once = false, ...args) {
8262
+ this._viewOpenEventMap = this._viewOpenEventMap || new Map();
8263
+ this._viewOpenEventMap.set(listener, { event: "open", viewConfig: this._getViewConfig(targetView), caller, listener, once, args });
8264
+ this.offViewEvent("open", this, this._onViewOpen);
8265
+ this.onViewEvent("open", this, this._onViewOpen);
8266
+ }
8267
+ _onViewOpen(viewName, ...args) {
8268
+ this._viewOpenEventMap.forEach((value, key) => {
8269
+ if (value.viewConfig.name == viewName) {
8270
+ value.listener.apply(value.caller, value.args);
8271
+ value.once && this._viewOpenEventMap.delete(key);
8272
+ }
8273
+ });
8255
8274
  }
8256
8275
  /**
8257
- * GC Bundle
8276
+ * [快捷方式]移除视图打开的事件监听
8277
+ * @param listener
8258
8278
  * @returns
8259
8279
  */
8260
- _onGC() {
8261
- const count = this._waitToReleaseBundles.size;
8262
- if (count == 0) {
8263
- return;
8264
- }
8265
- const now = Date.now();
8266
- this._waitToReleaseBundles.forEach((bundle) => {
8267
- console.log(`[GCBundle] Remove Bundle:${bundle.name}`);
8268
- this._onRemoveBundle(bundle);
8269
- });
8270
- this._waitToReleaseBundles.clear();
8271
- console.log(`[GCBundle] [${count}] cost:${Date.now() - now} milliseconds`);
8280
+ offViewOpen(listener) {
8281
+ return this._viewOpenEventMap && this._viewOpenEventMap.delete(listener);
8272
8282
  }
8273
8283
  /**
8274
- * 手动设置bundle的版本,可新增可以覆盖。
8275
- * @param map
8284
+ * [快捷方式]增加视图关闭的事件监听
8285
+ * @param targetView 目标视图Class|名称
8286
+ * @param listener 响应回调
8287
+ * @param caller 回调this
8288
+ * @param once 是否只监听对应视图关闭一次。
8289
+ * @param args 其他参数
8276
8290
  */
8277
- setBundleVersion(map) {
8278
- this._bundleVersionMap = this._bundleVersionMap || new Map();
8279
- map.forEach((value, key) => {
8280
- this._bundleVersionMap.set(value, key);
8281
- });
8291
+ onViewClose(targetView, caller, listener, once = false, ...args) {
8292
+ this._viewCloseEventMap = this._viewCloseEventMap || new Map();
8293
+ this._viewCloseEventMap.set(listener, { event: "close", viewConfig: this._getViewConfig(targetView), caller, listener, once, args });
8294
+ this.offViewEvent("close", this, this._onViewClose);
8295
+ this.onViewEvent("close", this, this._onViewClose);
8282
8296
  }
8283
8297
  /**
8284
- * 获取bundle的版本
8285
- * @param bundleName
8298
+ * [快捷方式]移除视图关闭的事件监听
8299
+ * @param listener
8286
8300
  * @returns
8287
8301
  */
8288
- _getBundleVersion(bundleName) {
8289
- return this._bundleVersionMap && this._bundleVersionMap.get(bundleName);
8302
+ offViewClose(listener) {
8303
+ return this._viewCloseEventMap && this._viewCloseEventMap.delete(listener);
8290
8304
  }
8291
- }
8292
- /**
8293
- * cocos资源加载和管理
8294
- */
8295
- const res = new ResourceManager();
8296
-
8297
- class EffectAudioSourceProxy {
8298
- constructor() {
8299
- this._audioNode = null;
8300
- this._audioSource = null;
8301
- this._onFinishCallBack = null;
8302
- this._audioNode = cc.find("__audioNode__");
8303
- if (!this._audioNode) {
8304
- this._audioNode = new cc.Node();
8305
- this._audioNode.name = '__audioNode__';
8306
- cc.director.getScene().addChild(this._audioNode);
8307
- cc.director.addPersistRootNode(this._audioNode);
8308
- }
8309
- this._audioSource = this._audioNode.addComponent(cc.AudioSource);
8305
+ _onViewClose(viewName, ...args) {
8306
+ this._viewCloseEventMap.forEach((value, key) => {
8307
+ if (value.viewConfig.name == viewName) {
8308
+ value.listener.apply(value.caller, value.args.concat(args));
8309
+ value.once && this._viewCloseEventMap.delete(key);
8310
+ }
8311
+ });
8310
8312
  }
8311
8313
  /**
8312
- * 声音大小
8314
+ * 增加视图事件监听
8315
+ * @param event 视图事件名称
8316
+ * @param caller 回调this
8317
+ * @param listener 响应回调
8318
+ * @param once 是否只监听对应视图关闭一次。
8319
+ * @param args 其他参数
8313
8320
  */
8314
- set volume(value) {
8315
- if (!this._audioNode || !this._audioSource) {
8316
- return;
8321
+ onViewEvent(event, caller, listener, once = false, ...args) {
8322
+ if (!this._viewEvent) {
8323
+ this._viewEvent = new EventDispatcher();
8317
8324
  }
8318
- this._audioSource.volume = value;
8319
- }
8320
- /**
8321
- * 声音大小
8322
- */
8323
- get volume() {
8324
- if (!this._audioNode || !this._audioSource) {
8325
- return 1;
8325
+ if (once) {
8326
+ this._viewEvent.once(event, caller, listener, args);
8327
+ }
8328
+ else {
8329
+ this._viewEvent.on(event, caller, listener, args);
8326
8330
  }
8327
- return this._audioSource.volume;
8328
8331
  }
8329
8332
  /**
8330
- * 渐进式播放
8331
- * @param clip
8332
- * @param volume
8333
- * @param loop
8334
- * @param onFinishCallBack
8333
+ * 移除视图事件监听
8334
+ * @param event 事件类型
8335
+ * @param caller 事件侦听函数的执行域。
8336
+ * @param listener 事件侦听函数。
8335
8337
  * @returns
8336
8338
  */
8337
- playfade(clip, volume, loop = false, onFinishCallBack) {
8338
- this.play(clip, volume, loop, onFinishCallBack);
8339
- return this.fadeIn();
8339
+ offViewEvent(event, caller, listener) {
8340
+ if (!this._viewEvent) {
8341
+ return;
8342
+ }
8343
+ this._viewEvent.off(event, caller, listener);
8340
8344
  }
8341
8345
  /**
8342
- * 播放
8343
- * @param clip
8344
- * @param volume
8345
- * @param loop
8346
- * @param onFinishCallBack
8347
- * @returns
8346
+ * 广播视图事件
8347
+ * @param event 视图事件
8348
+ * @param view 视图
8348
8349
  */
8349
- play(clip, volume, loop = false, onFinishCallBack) {
8350
- this._audioSource.clip = clip;
8351
- this._audioSource.loop = loop;
8352
- this._audioSource.volume = volume;
8353
- this._audioSource.playOnAwake = false;
8354
- this._onFinishCallBack = onFinishCallBack;
8355
- this._audioNode.on(cc.AudioSource.EventType.ENDED, this._onAudioEnded, this);
8356
- this._audioSource.play();
8357
- return this;
8350
+ event(event, view, ...args) {
8351
+ if (this._viewEvent) {
8352
+ args.unshift(view.name);
8353
+ this._viewEvent.event(event, args);
8354
+ }
8358
8355
  }
8359
8356
  /**
8360
- * 渐进
8361
- * @returns
8357
+ * 上报视图统计数据(open\close\...)
8358
+ * @param event 事件
8359
+ * @param view 视图
8360
+ * @param data 上报附带信息
8362
8361
  */
8363
- fadeIn() {
8364
- return new Promise((resolve) => {
8365
- const targetVolume = this.volume;
8366
- cc.tween(this).set({ volume: 0 }).to(0.2, { volume: targetVolume }).call(() => {
8367
- resolve(this);
8368
- }).start();
8369
- });
8362
+ reportViewAnalytics(event, view, data) {
8363
+ let maskViewconfig = this._currentMaskView && this._currentMaskView.config;
8364
+ if (maskViewconfig && view.name == maskViewconfig.name) {
8365
+ return;
8366
+ }
8367
+ let analyticsInfo = this._viewAnalyticsMap.get(view.name);
8368
+ if (analyticsInfo) {
8369
+ data = data || (view.getAnalyticsDataOnViewEvent && view.getAnalyticsDataOnViewEvent(event)) || {};
8370
+ data.action = event;
8371
+ data.name = analyticsInfo.name;
8372
+ data.group = analyticsInfo.group || "default";
8373
+ //open:进入时刻, close:停留时长
8374
+ data.stay = Math.floor((App.durationOfLaunch - (analyticsInfo.lastOpenTime || 0)) / 1000);
8375
+ analytics.base.report("view", data);
8376
+ analyticsInfo.lastOpenTime = event == "open" ? App.durationOfLaunch : 0;
8377
+ }
8370
8378
  }
8371
- /**
8372
- * 渐出
8373
- * @param stop
8374
- * @returns
8375
- */
8376
- fedeOut(stop = true) {
8377
- return new Promise((resolve) => {
8378
- cc.tween(this).to(0.2, { volume: 0 }).call(() => {
8379
- stop && this.stop();
8380
- resolve(this);
8381
- }).start();
8382
- });
8379
+ get impl() {
8380
+ if (this._impl == null) {
8381
+ this._impl = Injector.getInject(ViewManager.KEY);
8382
+ }
8383
+ if (this._impl == null) {
8384
+ throw new Error(ViewManager.KEY + "未注入!");
8385
+ }
8386
+ return this._impl;
8383
8387
  }
8384
- /**
8385
- * 暂停
8386
- * @returns
8387
- */
8388
- pause() {
8389
- if (!this._audioNode || !this._audioSource) {
8388
+ }
8389
+ ViewManager.KEY = "ViewManager";
8390
+ ViewManager.created = false;
8391
+ /**
8392
+ * 视图管理器
8393
+ */
8394
+ const viewManager = new ViewManager();
8395
+
8396
+ class INativeHelper {
8397
+ constructor() {
8398
+ this._callbackCount = 0;
8399
+ }
8400
+ call(className, methodName, ...args) {
8401
+ this.callWithReturnType(className, methodName, null, ...args);
8402
+ }
8403
+ registerCallback(caller, method, times, ...args) {
8404
+ if (caller == null || method == null) {
8405
+ return "";
8406
+ }
8407
+ ++this._callbackCount;
8408
+ let callbackName = 'NativeHelper.callback' + this._callbackCount;
8409
+ window[callbackName] = () => {
8410
+ method.apply(caller, args);
8411
+ if (--times <= 0) {
8412
+ window[callbackName] = null;
8413
+ }
8414
+ };
8415
+ return `window['${callbackName}']()`;
8416
+ }
8417
+ }
8418
+
8419
+ /**
8420
+ @name: NativeHelper
8421
+ @desc: cocos 2.4.x 下nativeHelper
8422
+ @author: timoo
8423
+ @date: 2022/12/02
8424
+ */
8425
+ class CocosNativeHelper extends INativeHelper {
8426
+ callWithReturnType(className, methodName, returnType, ...args) {
8427
+ if (!className) {
8390
8428
  return;
8391
8429
  }
8392
- this._audioSource.pause();
8393
- }
8394
- /**
8395
- * 恢复
8396
- * @returns
8397
- */
8398
- resume() {
8399
- if (!this._audioNode || !this._audioSource) {
8400
- return;
8430
+ if (cc.sys.os == cc.sys.OS.ANDROID) {
8431
+ let argsSig = this.getArgsSig(args, returnType);
8432
+ console.log("callWithReturnType:", className, methodName, argsSig, args.join(","));
8433
+ return cc.native.reflection.callStaticMethod(className, methodName, argsSig, ...args);
8401
8434
  }
8402
- this._audioSource.play();
8403
- }
8404
- /**
8405
- * 渐进停止
8406
- * @returns
8407
- */
8408
- stopFade() {
8409
- return this.fedeOut(true).then(() => { });
8435
+ else if (cc.sys.os == cc.sys.OS.IOS) ;
8410
8436
  }
8411
- /**
8412
- * 停止
8413
- * @returns
8414
- */
8415
- stop() {
8416
- if (!this._audioNode || !this._audioSource) {
8417
- return;
8437
+ getArgsSig(args, returnType) {
8438
+ let sig = ["("];
8439
+ for (let i = 0; i < args.length; i++) {
8440
+ const element = args[i];
8441
+ sig.push(this.getValueTypeStr(element));
8418
8442
  }
8419
- this._audioSource.stop();
8420
- this._audioNode.off(cc.AudioSource.EventType.ENDED, this._onAudioEnded, this);
8443
+ sig.push(")", this.getValueTypeStr(returnType));
8444
+ return sig.join("");
8421
8445
  }
8422
- _onAudioEnded(audioSource) {
8423
- if (audioSource == this._audioSource) {
8424
- this._onFinishCallBack && this._onFinishCallBack();
8425
- this._audioNode.off(cc.AudioSource.EventType.ENDED, this._onAudioEnded, this);
8446
+ getValueTypeStr(value) {
8447
+ if (value == null || value == undefined) {
8448
+ return "V";
8449
+ }
8450
+ let typeStr = typeof value;
8451
+ if (typeStr == "number") {
8452
+ if (value % 1 != 0) { //float
8453
+ return "F";
8454
+ }
8455
+ else {
8456
+ return "I";
8457
+ }
8458
+ }
8459
+ else if (typeStr == "boolean") {
8460
+ return "Z";
8461
+ }
8462
+ else if (typeStr == "string") {
8463
+ return "Ljava/lang/String;";
8426
8464
  }
8427
8465
  }
8428
- /**
8429
- * 是否循环
8430
- */
8431
- get loop() {
8432
- return this._audioSource ? this._audioSource.loop : false;
8466
+ }
8467
+
8468
+ /*
8469
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
8470
+ * Digest Algorithm, as defined in RFC 1321.
8471
+ * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
8472
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
8473
+ * Distributed under the BSD License
8474
+ * See http://pajhome.org.uk/crypt/md5 for more info.
8475
+ */
8476
+ /*
8477
+ * Configurable variables. You may need to tweak these to be compatible with
8478
+ * the server-side, but the defaults work in most cases.
8479
+ */
8480
+ var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
8481
+ /*
8482
+ * These are the functions you'll usually want to call
8483
+ * They take string arguments and return either hex or base-64 encoded strings
8484
+ */
8485
+ function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
8486
+ /*
8487
+ * Calculate the MD5 of a raw string
8488
+ */
8489
+ function rstr_md5(s) {
8490
+ return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
8491
+ }
8492
+ /*
8493
+ * Convert a raw string to a hex string
8494
+ */
8495
+ function rstr2hex(input) {
8496
+ try {
8497
+ hexcase;
8433
8498
  }
8434
- /**
8435
- * 是否播放中
8436
- */
8437
- get playing() {
8438
- return this._audioSource ? this._audioSource.playing : false;
8499
+ catch (e) {
8500
+ hexcase = 0;
8439
8501
  }
8440
- reset() {
8441
- this.stop();
8442
- cc.Tween.stopAllByTarget(this);
8443
- this._onFinishCallBack = null;
8502
+ var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
8503
+ var output = "";
8504
+ var x;
8505
+ for (var i = 0; i < input.length; i++) {
8506
+ x = input.charCodeAt(i);
8507
+ output += hex_tab.charAt((x >>> 4) & 0x0F)
8508
+ + hex_tab.charAt(x & 0x0F);
8444
8509
  }
8445
- destroy() {
8446
- this._audioSource.destroy();
8447
- this._audioSource = null;
8448
- this._audioNode = null;
8449
- this._onFinishCallBack = null;
8510
+ return output;
8511
+ }
8512
+ /*
8513
+ * Encode a string as utf-8.
8514
+ * For efficiency, this assumes the input is valid utf-16.
8515
+ */
8516
+ function str2rstr_utf8(input) {
8517
+ var output = "";
8518
+ var i = -1;
8519
+ var x, y;
8520
+ while (++i < input.length) {
8521
+ /* Decode utf-16 surrogate pairs */
8522
+ x = input.charCodeAt(i);
8523
+ y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
8524
+ if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
8525
+ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
8526
+ i++;
8527
+ }
8528
+ /* Encode output as utf-8 */
8529
+ if (x <= 0x7F)
8530
+ output += String.fromCharCode(x);
8531
+ else if (x <= 0x7FF)
8532
+ output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F), 0x80 | (x & 0x3F));
8533
+ else if (x <= 0xFFFF)
8534
+ output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), 0x80 | ((x >>> 6) & 0x3F), 0x80 | (x & 0x3F));
8535
+ else if (x <= 0x1FFFFF)
8536
+ output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), 0x80 | ((x >>> 12) & 0x3F), 0x80 | ((x >>> 6) & 0x3F), 0x80 | (x & 0x3F));
8537
+ }
8538
+ return output;
8539
+ }
8540
+ /*
8541
+ * Convert a raw string to an array of little-endian words
8542
+ * Characters >255 have their high-byte silently ignored.
8543
+ */
8544
+ function rstr2binl(input) {
8545
+ var output = Array(input.length >> 2);
8546
+ for (var i = 0; i < output.length; i++)
8547
+ output[i] = 0;
8548
+ for (var i = 0; i < input.length * 8; i += 8)
8549
+ output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
8550
+ return output;
8551
+ }
8552
+ /*
8553
+ * Convert an array of little-endian words to a string
8554
+ */
8555
+ function binl2rstr(input) {
8556
+ var output = "";
8557
+ for (var i = 0; i < input.length * 32; i += 8)
8558
+ output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
8559
+ return output;
8560
+ }
8561
+ /*
8562
+ * Calculate the MD5 of an array of little-endian words, and a bit length.
8563
+ */
8564
+ function binl_md5(x, len) {
8565
+ /* append padding */
8566
+ x[len >> 5] |= 0x80 << ((len) % 32);
8567
+ x[(((len + 64) >>> 9) << 4) + 14] = len;
8568
+ var a = 1732584193;
8569
+ var b = -271733879;
8570
+ var c = -1732584194;
8571
+ var d = 271733878;
8572
+ for (var i = 0; i < x.length; i += 16) {
8573
+ var olda = a;
8574
+ var oldb = b;
8575
+ var oldc = c;
8576
+ var oldd = d;
8577
+ a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
8578
+ d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
8579
+ c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
8580
+ b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
8581
+ a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
8582
+ d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
8583
+ c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
8584
+ b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
8585
+ a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
8586
+ d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
8587
+ c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
8588
+ b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
8589
+ a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
8590
+ d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
8591
+ c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
8592
+ b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
8593
+ a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
8594
+ d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
8595
+ c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
8596
+ b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
8597
+ a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
8598
+ d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
8599
+ c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
8600
+ b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
8601
+ a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
8602
+ d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
8603
+ c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
8604
+ b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
8605
+ a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
8606
+ d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
8607
+ c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
8608
+ b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
8609
+ a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
8610
+ d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
8611
+ c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
8612
+ b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
8613
+ a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
8614
+ d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
8615
+ c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
8616
+ b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
8617
+ a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
8618
+ d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
8619
+ c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
8620
+ b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
8621
+ a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
8622
+ d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
8623
+ c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
8624
+ b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
8625
+ a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
8626
+ d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
8627
+ c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
8628
+ b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
8629
+ a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
8630
+ d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
8631
+ c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
8632
+ b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
8633
+ a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
8634
+ d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
8635
+ c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
8636
+ b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
8637
+ a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
8638
+ d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
8639
+ c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
8640
+ b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
8641
+ a = safe_add(a, olda);
8642
+ b = safe_add(b, oldb);
8643
+ c = safe_add(c, oldc);
8644
+ d = safe_add(d, oldd);
8450
8645
  }
8646
+ return Array(a, b, c, d);
8451
8647
  }
8452
- class AudioManager {
8453
- constructor() {
8454
- this._musicVolume = null;
8455
- this._effectVolume = null;
8456
- this._effectPool = new Pool(EffectAudioSourceProxy); //cc.AudioSource.maxAudioChannel - 1);
8457
- }
8458
- /**
8459
- * 音效音量大小
8460
- */
8461
- get effectVolume() {
8462
- if (this._effectVolume == null) {
8463
- this._effectVolume = storage.effectsVolume;
8464
- }
8465
- return this._effectVolume;
8466
- }
8467
- /**
8468
- * 音效音量大小
8469
- */
8470
- set effectVolume(value) {
8471
- storage.effectsVolume = this._effectVolume = value;
8472
- let usingEffect = this._effectPool['_usingArray'];
8473
- usingEffect = usingEffect.concat();
8474
- for (let i = 0; i < usingEffect.length; i++) {
8475
- const effectProxy = usingEffect[i];
8476
- effectProxy.volume = value;
8477
- }
8478
- }
8479
- /**
8480
- * BGM音量大小
8481
- */
8482
- get musicVolume() {
8483
- if (this._musicVolume == null) {
8484
- this._musicVolume = storage.musicVolume;
8648
+ /*
8649
+ * These functions implement the four basic operations the algorithm uses.
8650
+ */
8651
+ function md5_cmn(q, a, b, x, s, t) {
8652
+ return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
8653
+ }
8654
+ function md5_ff(a, b, c, d, x, s, t) {
8655
+ return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
8656
+ }
8657
+ function md5_gg(a, b, c, d, x, s, t) {
8658
+ return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
8659
+ }
8660
+ function md5_hh(a, b, c, d, x, s, t) {
8661
+ return md5_cmn(b ^ c ^ d, a, b, x, s, t);
8662
+ }
8663
+ function md5_ii(a, b, c, d, x, s, t) {
8664
+ return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
8665
+ }
8666
+ /*
8667
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
8668
+ * to work around bugs in some JS interpreters.
8669
+ */
8670
+ function safe_add(x, y) {
8671
+ var lsw = (x & 0xFFFF) + (y & 0xFFFF);
8672
+ var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
8673
+ return (msw << 16) | (lsw & 0xFFFF);
8674
+ }
8675
+ /*
8676
+ * Bitwise rotate a 32-bit number to the left.
8677
+ */
8678
+ function bit_rol(num, cnt) {
8679
+ return (num << cnt) | (num >>> (32 - cnt));
8680
+ }
8681
+ const md5 = hex_md5;
8682
+
8683
+ /**
8684
+ * cocos下的本地持久化实现类
8685
+ */
8686
+ class CocosStorageUtils {
8687
+ removeValue(key) {
8688
+ if (!window['CC_DEBUG']) {
8689
+ key = md5(key);
8485
8690
  }
8486
- return this._musicVolume;
8487
- }
8488
- /**
8489
- * BGM音量大小
8490
- */
8491
- set musicVolume(value) {
8492
- storage.musicVolume = this._musicVolume = value;
8493
- this._music && (this._music.volume = value);
8494
- }
8495
- /**
8496
- * 播放音效
8497
- * @param clip
8498
- * @param loop 是否循环,默认为false。传入true,需要手动调用recoverEffect进行回收
8499
- * @param onFinishCallBack 播放完回调
8500
- * @param volume 当此播放的声音大小,默认为统一effect的大小
8501
- */
8502
- playEffect(clip, loop = false, onFinishCallBack, volume = null) {
8503
- const effectProxy = this._effectPool.allocate();
8504
- effectProxy.play(clip, volume == null ? this.effectVolume : volume, loop, () => {
8505
- if (!loop) {
8506
- this.recoverEffect(effectProxy);
8507
- }
8508
- else {
8509
- console.warn("需要手动回收音效播放器");
8510
- }
8511
- onFinishCallBack && onFinishCallBack();
8512
- });
8513
- return effectProxy;
8514
- }
8515
- /**
8516
- * 回收音效播放器,用于effect多次复用后的回收
8517
- * @param proxy
8518
- */
8519
- recoverEffect(proxy) {
8520
- this._effectPool.recover(proxy);
8691
+ sys.localStorage.removeItem(key);
8521
8692
  }
8522
- /**
8523
- * 停止所有音效
8524
- */
8525
- stopAllEffect() {
8526
- let usingEffect = this._effectPool['_usingArray'];
8527
- usingEffect = usingEffect.concat();
8528
- for (let i = 0; i < usingEffect.length; i++) {
8529
- const effectProxy = usingEffect[i];
8530
- effectProxy.stop();
8531
- this.recoverEffect(effectProxy);
8693
+ setValue(key, value) {
8694
+ if (!window['CC_DEBUG']) {
8695
+ key = md5(key);
8532
8696
  }
8533
- }
8534
- /**
8535
- * 播放背景音乐
8536
- * @param clip
8537
- * @param fade 是否渐进式播放,默认为true
8538
- * @param loop 是否循环,默认为true
8539
- * @param onFinishCallBack 播放完回调
8540
- * @param volume 当此播放的声音大小,默认为统一music的大小
8541
- */
8542
- playMusic(clip, fade = true, loop = true, onFinishCallBack, volume = null) {
8543
- if (!this._music) {
8544
- this._music = new EffectAudioSourceProxy();
8697
+ try {
8698
+ sys.localStorage.setItem(key, value);
8545
8699
  }
8546
- this._music.playing && this._music.stop();
8547
- volume = volume == null ? this.musicVolume : volume;
8548
- fade ? this._music.playfade(clip, volume, loop, onFinishCallBack) : this._music.play(clip, volume, loop, onFinishCallBack);
8549
- }
8550
- /**
8551
- * 暂停播放背景音乐
8552
- * @returns
8553
- */
8554
- pauseMusic() {
8555
- if (!this._music) {
8556
- return;
8700
+ catch (error) {
8701
+ console.error('Failed to set storage value:', "key:", key, "value:", value, "length:", String(value).length, "error:", error);
8557
8702
  }
8558
- this._music.pause();
8559
8703
  }
8560
- /**
8561
- * 恢复播放背景音乐
8562
- * @returns
8563
- */
8564
- resumeMusic() {
8565
- if (!this._music) {
8566
- return;
8704
+ getValue(key) {
8705
+ if (!window['CC_DEBUG']) {
8706
+ key = md5(key);
8567
8707
  }
8568
- this._music.resume();
8708
+ return sys.localStorage.getItem(key);
8569
8709
  }
8570
- /**
8571
- * 停止背景音乐
8572
- * @param fade 是否渐出
8573
- * @returns
8574
- */
8575
- stopMusic(fade = true) {
8576
- return __awaiter(this, void 0, void 0, function* () {
8577
- if (!this._music) {
8578
- return;
8579
- }
8580
- return fade ? yield this._music.stopFade() : this._music.stop();
8581
- });
8710
+ clear() {
8711
+ sys.localStorage.clear();
8582
8712
  }
8583
8713
  }
8714
+
8584
8715
  /**
8585
- * 音效管理
8716
+ * 任务队列
8586
8717
  */
8587
- const audio = new AudioManager();
8588
-
8589
- var View_1;
8590
- const { ccclass: ccclass$2, property: property$2, menu: menu$2 } = cc._decorator;
8591
- var ViewLevel;
8592
- (function (ViewLevel) {
8593
- ViewLevel[ViewLevel["TOPUP"] = 500] = "TOPUP";
8594
- ViewLevel[ViewLevel["NET"] = 400] = "NET";
8595
- ViewLevel[ViewLevel["TUTORIAL"] = 300] = "TUTORIAL";
8596
- ViewLevel[ViewLevel["ALERT"] = 200] = "ALERT";
8597
- ViewLevel[ViewLevel["UI"] = 100] = "UI";
8598
- ViewLevel[ViewLevel["BG"] = 1] = "BG";
8599
- })(ViewLevel || (ViewLevel = {}));
8600
- let View = View_1 = class View extends cc.Component {
8718
+ class TaskSequence extends Task {
8601
8719
  constructor() {
8602
- super(...arguments);
8603
- /**
8604
- * 是否可以交互
8605
- */
8606
- this._touchEnabled = true;
8607
- }
8608
- /**
8609
- * 是否在舞台中显示着
8610
- */
8611
- get inStage() {
8612
- return cc.isValid(this.node) && this.node.activeInHierarchy;
8613
- }
8614
- /**
8615
- * 视图是否响应交互
8616
- */
8617
- get touchEnabled() {
8618
- return this._touchEnabled;
8619
- }
8620
- /**
8621
- * 视图是否响应交互
8622
- */
8623
- set touchEnabled(value) {
8624
- this._touchEnabled = value;
8625
- if (value && !this._mask) {
8626
- return;
8627
- }
8628
- if (!this._mask) {
8629
- this._mask = new cc.Node();
8630
- this._mask.name = "mask";
8631
- let transform = this._mask.addComponent(cc.UITransform);
8632
- const viewSize = cc.view.getVisibleSize();
8633
- transform.setContentSize(viewSize.width, viewSize.height);
8634
- this._mask.addComponent(cc.BlockInputEvents);
8635
- // this.node.addChild(this.mask);
8636
- this.node.addChild(this._mask);
8637
- transform.priority = ViewLevel.TOPUP;
8638
- this._mask.layer = this.node.layer;
8639
- }
8640
- this._mask.active = !value;
8720
+ super();
8721
+ this._taskMap = new Map();
8722
+ this._index = 0;
8641
8723
  }
8642
- /**
8643
- * 添加其他视图
8644
- * @param view 其他视图
8645
- * @param index 视图索引
8646
- */
8647
- addView(view, index) {
8648
- view.setControl(this._control);
8649
- view.node.parent = this.node;
8650
- (view.node.getComponent(cc.UITransform) || view.node.addComponent(cc.UITransform)).priority = index;
8651
- viewManager.event("open", view);
8652
- viewManager.reportViewAnalytics("open", view);
8653
- analytics.session.updateSessionDuration();
8724
+ addQuickly(taskCaller, taskFun, ...taskData) {
8725
+ let task = new Task();
8726
+ taskData.unshift(task);
8727
+ task.start = (data) => {
8728
+ taskFun.apply(taskCaller, taskData);
8729
+ };
8730
+ this.addTask(task);
8731
+ return task;
8654
8732
  }
8655
- /**
8656
- * 移除子视图
8657
- * @param view 子视图
8658
- * @param destroy 是否销毁,默认为true
8659
- * @param closeEventParams 视图close事件的参数
8660
- */
8661
- removeView(view, destroy = true, ...closeEventParams) {
8662
- if (view.parentView == this) {
8663
- destroy && view.node.destroyAllChildren();
8664
- view.node.removeFromParent();
8665
- viewManager.event("close", view, ...closeEventParams);
8666
- viewManager.reportViewAnalytics("close", view);
8667
- analytics.session.updateSessionDuration();
8733
+ addTask(value, ...data) {
8734
+ if (this._taskMap.has(value)) {
8735
+ throw new Error("重复添加!");
8668
8736
  }
8737
+ this._taskMap.set(value, data);
8669
8738
  }
8670
- /**
8671
- * 设置主场景所创建的Control
8672
- * @param control
8673
- */
8674
- setControl(control) {
8675
- this._control = control;
8739
+ removeTask(value) {
8740
+ return this._taskMap.delete(value);
8676
8741
  }
8677
- control() {
8678
- return this._control;
8742
+ start(...data) {
8743
+ this._keys = this._taskMap.keys();
8744
+ this._index = 0;
8745
+ this._tryNext();
8679
8746
  }
8680
- /**
8681
- * 实例化后显示到舞台之后调用,缓存视图重新显示时也会调用。
8682
- * @param data
8683
- */
8684
- setData(...data) {
8747
+ _tryNext() {
8748
+ let next = this._keys.next();
8749
+ if (!next.done) {
8750
+ let task = next.value;
8751
+ task.on(Task.Event.COMPLETE, this, this._subTaskEventHandler);
8752
+ task.on(Task.Event.PROGRESS, this, this._subTaskEventHandler);
8753
+ task.on(Task.Event.ERROR, this, this._subTaskEventHandler);
8754
+ task.start(this._taskMap.get(task));
8755
+ }
8756
+ else {
8757
+ //结束
8758
+ this.onComplete();
8759
+ }
8685
8760
  }
8686
- /**
8687
- * 上报当前视图统计数据
8688
- * @param event open和close以外的统计名称,名称必须为全小写,无下划线之外的其他特殊字符。
8689
- * @param data 上报附带信息,可选参数,为空时会尝试从getAnalyticsDataOnViewEvent获取附带信息。
8690
- */
8691
- _report(event, data) {
8692
- if (event == "open" || event == "close")
8761
+ _subTaskEventHandler(key, target, data) {
8762
+ if (key == Task.Event.ERROR) {
8763
+ this.onError(data.code, data.msg);
8693
8764
  return;
8694
- viewManager.reportViewAnalytics(event, this, data);
8765
+ }
8766
+ if (key == Task.Event.COMPLETE) {
8767
+ target.offAllEvent();
8768
+ target.destroy();
8769
+ this._index++;
8770
+ this.onProgress(this._index / this._taskMap.size);
8771
+ this._tryNext();
8772
+ }
8695
8773
  }
8696
- /**
8697
- * 播放BG音乐
8698
- * @param path 路径 - `bundleName://path/to/asset` 目标音频地址。
8699
- * @param fade 是否渐进式播放,默认为true
8700
- * @param loop 是否循环 默认为true
8701
- * @param onFinishCallBack 单次播放结束后的回调箭头函数(cocos的锅)
8702
- * @returns 背景音乐的audioId
8703
- *
8704
- * @example
8705
- * _playBG("https://server.com/game/music.mp3")
8706
- * _playBG("main://path/to/music")
8707
- * _playBG("resources://path/to/music")
8708
- */
8709
- playBG(path, fade = true, loop = true, onFinishCallBack, volume = null) {
8710
- return __awaiter(this, void 0, void 0, function* () {
8711
- let clip = yield res.load(path);
8712
- if (clip) {
8713
- audio.playMusic(clip, fade, loop, onFinishCallBack, volume);
8714
- }
8774
+ reset() {
8775
+ this.offAllEvent();
8776
+ this._taskMap.forEach((data, task) => {
8777
+ task.reset();
8715
8778
  });
8779
+ this._taskMap.clear();
8780
+ this._keys = null;
8781
+ this._index = 0;
8716
8782
  }
8717
- /**
8718
- * 播放音效
8719
- * @param path 路径 - `bundleName://path/to/asset` 目标音频地址。
8720
- * @param onFinishCallBack 单次播放结束后的回调箭头函数(cocos的锅)
8721
- * @returns 音效的audioId
8722
- */
8723
- playEffect(path, onFinishCallBack, volume = null) {
8724
- return __awaiter(this, void 0, void 0, function* () {
8725
- let clip = yield res.load(path);
8726
- return new Promise((reslove) => {
8727
- if (clip) {
8728
- audio.playEffect(clip, false, () => {
8729
- onFinishCallBack && onFinishCallBack();
8730
- reslove();
8731
- }, volume);
8732
- }
8733
- });
8783
+ destroy() {
8784
+ super.destroy();
8785
+ this._taskMap.forEach((data, task) => {
8786
+ task.reset();
8734
8787
  });
8788
+ this._taskMap.clear();
8789
+ this._keys = null;
8790
+ this._index = 0;
8735
8791
  }
8736
- /**
8737
- * 播放激励视频的快捷方式。
8738
- * @param from 可选参数,可以附带广告行为的来源,以及其他需要统计的信息
8739
- * @param stopRecorder 可选参数,是否暂停录屏, 默认为true
8740
- */
8741
- showRewardVideo(from, stopRecorder = true) {
8742
- return new Promise((resolve) => {
8743
- stopRecorder && publisher.record && publisher.record.pauseRecord();
8744
- viewManager.closeTouch();
8745
- //解决部分平台(tt)拉起视频时,最小化视频播放不出来的bug。
8746
- const openTouch = () => {
8747
- viewManager.openTouch();
8748
- App.offShow(openTouch);
8749
- };
8750
- App.onShow(openTouch);
8751
- from = from || {};
8752
- // from.name = this.analyticsInfo ? this.analyticsInfo.name : this.name;
8753
- publisher.ad.showRewardVideo(from).then((result) => {
8754
- openTouch();
8755
- stopRecorder && publisher.record && publisher.record.resumeRecord();
8756
- resolve(result);
8757
- }).catch(() => {
8758
- openTouch();
8759
- stopRecorder && publisher.record && publisher.record.resumeRecord();
8760
- resolve(false);
8761
- });
8762
- });
8792
+ }
8793
+
8794
+ /**
8795
+ * 视图加载器
8796
+ */
8797
+ class IViewLoader extends EventDispatcher {
8798
+ constructor(pool) {
8799
+ super();
8800
+ this._initializer = new TaskSequence();
8801
+ this._pool = pool;
8763
8802
  }
8764
- /**
8765
- * 分享录屏视频
8766
- * @param analyticsName 玩法发起分享的动作来源,用于统计。
8767
- * @param title 视频标题
8768
- * @param topics 视频话题列表
8769
- */
8770
- shareRecord(analyticsName, title, topics) {
8771
- let path = publisher.record.videoPath;
8772
- if (path) {
8773
- return publisher.share.shareVideo(analyticsName, { "video_title": title, "videoTopics": topics, "videoPath": path });
8774
- }
8775
- else {
8776
- return new Promise((resolve) => { resolve(false); });
8803
+ load(task) {
8804
+ if (this._asset) {
8805
+ task && task.onComplete();
8806
+ return;
8777
8807
  }
8778
- }
8779
- /**
8780
- * 子项重写时,必须要调用super.onDestroy()
8781
- *
8782
- */
8783
- onDestroy() {
8784
- this.config.cache && viewManager.cancelCache(this);
8785
- }
8786
- /**
8787
- * 父级视图
8788
- */
8789
- get parentView() {
8790
- if (this.node.parent) {
8791
- return this.node.parent.getComponent(View_1);
8808
+ if (task) {
8809
+ this._initializer.once(Task.Event.ERROR, this, (type, a, error) => {
8810
+ task.onError(error.code, error.msg);
8811
+ });
8812
+ this._initializer.on(Task.Event.PROGRESS, this, (type, a, percent) => {
8813
+ task.onProgress(percent);
8814
+ });
8792
8815
  }
8793
- return null;
8794
- }
8795
- /**
8796
- * 关闭视图,根据视图是否缓存选择是否销毁视图
8797
- * @param closeEventParams 视图close事件的参数
8798
- */
8799
- close(...closeEventParams) {
8800
- this.removeFromParent(!this.config.cache, ...closeEventParams);
8816
+ this._initializer.once(Task.Event.COMPLETE, this, () => {
8817
+ this._initializer.reset();
8818
+ task && task.onComplete();
8819
+ });
8820
+ this._initializer.start();
8801
8821
  }
8802
- /**
8803
- * 从父级移除视图
8804
- * @param destroy 是否销毁,默认为true
8805
- * @param closeEventParams 视图close事件的参数
8806
- */
8807
- removeFromParent(destroy = true, ...closeEventParams) {
8808
- if (this.parentView) {
8809
- this.parentView.removeView(this, destroy, ...closeEventParams);
8810
- }
8822
+ destroy() {
8823
+ this.offAll();
8824
+ this._initializer.reset();
8825
+ this._initializer = null;
8826
+ this._asset = null;
8827
+ this._pool = null;
8811
8828
  }
8812
- /**
8813
- * 直接销毁
8814
- */
8815
- allDestroy() {
8816
- if (this.node && cc.isValid(this.node)) {
8817
- this.node.parent = null;
8818
- this.node.destroy();
8819
- }
8829
+ reset() {
8830
+ this._initializer.reset();
8831
+ this.offAll();
8832
+ this._asset = null;
8820
8833
  }
8821
- getAnalyticsDataOnViewEvent(event) {
8822
- return {};
8834
+ recover() {
8835
+ this._pool.recover(this);
8823
8836
  }
8824
- };
8825
- /**
8826
- * View类的Class名称
8827
- */
8828
- View.type = "View";
8829
- View = View_1 = __decorate([
8830
- ccclass$2("View"),
8831
- menu$2("基础视图/View")
8832
- /**
8833
- * cocos引擎下的视图管理类
8834
- */
8835
- ], View);
8837
+ }
8836
8838
 
8837
8839
  /**
8838
8840
  * 注册View配置的装饰器(CCPViewLoader)
@@ -8878,14 +8880,10 @@ function viewClass(data) {
8878
8880
  }
8879
8881
  /**
8880
8882
  * 注册closeTouch默认遮罩视图
8881
- * @param data 视图配置
8882
8883
  */
8883
- function maskView(data) {
8884
+ function maskView() {
8884
8885
  return function (target, propertyKey) {
8885
- data.cache = true;
8886
- data.zIndex = ViewLevel.TOPUP;
8887
- viewClass(data)(target, propertyKey);
8888
- viewManager.registerMaskView(data);
8886
+ viewManager.registerMaskView(target);
8889
8887
  };
8890
8888
  }
8891
8889
  /**