/******************************************************************************* * * 剧情管理 * * * * 2023.06.25 ******************************************************************************/ const BridgeController = require( "bridge.controller" ); const PDF = require( "plot.define" ); const TDefine = require( "trace.define" ); const TTT = TDefine.TraceType; const PlotManager = cc.Class( { extends: BridgeController, // 初始化配置数据 initConfig: function() { this.units = {}; // 插件 nx.plugin.add( this, [ "view" ] ); // 视图创建 this.vbuild( PDF.ViewPlot ); // 全局支持 nx.bridge.plot = this; }, // 注册监听事件 registerEvents: function() { }, // 注册协议接受事件 registerProtocals: function() { // 前端准备完毕 this.RegisterProtocal( 10371, this.onCommited.bind( this ) ); this.RegisterProtocal( 10372, this.onPlotData.bind( this ) ); }, // 从服务器初始化数据 reqBaseFromServer: function( _cb ) { // 如果当前正在引导,则不重建 if( this.isDoing() ) { nx.dt.fnInvoke( _cb, true ); return; } this.rebuild( ( _ret, _data ) => { nx.dt.fnInvoke( _cb, _ret, _data ); // 掉线重新激活 if( nx.bridge.mainui ) { nx.bridge.mainui.tryPlot(); } } ); }, // 系统重建 rebuild: function( _cb ) { // 清理 this.records = {}; this.configs = null; this.vreset(); // 开关 let open = nx.storage.getNumber( PDF.KEY_PLOT_OPEN, 1, true ); this.opened = ( open == 1 ); // 重读配置 let path = cc.path.join( "configs/plots", "catalogs" ); nx.res.loadJson( path, ( _err, _data ) => { if( _err ) { nx.error( "$Plot:配置加载失败:", path ); nx.dt.fnInvoke( _cb, false ); return; } this.configs = _data; this.records = nx.storage.getObject( PDF.KEY_PLOTS, true ); if( nx.dt.objEmpty( this.records ) ) { this.records = { ids: [], }; } this.reqBaseData( _cb ); } ); }, // 请求剧情信息 reqBaseData: function( _cb ) { this.SendProtocal( 10372, {}, _cb ); }, // 剧情信息 onPlotData: function( _data ) { if( !this.isGoodData( _data ) ) { return; } let ids = []; let group = _data.guide_group || []; group.forEach( t => { ids.push( t.id ); } ); this.records.ids = ids; }, // 上传剧情完成 reqComplete: function( _id, _cb ) { // 已经提交过了 if( this.preCommited ) { nx.warn( `$Plot:已经提前完成过了!` ); nx.dt.fnInvoke( _cb, true ); return; } this.SendProtocal( 10371, { id: _id + "", }, _cb ); // 埋点 if( nx.mTrace ) { nx.mTrace.trace( TTT.plotDone, _id ); } }, // 剧情上传 onCommited: function( _data ) { if( !this.isGoodData( _data ) ) { return; } this.preCommited = true; }, // 引导开关 openPlot: function( _open ) { this.opened = !!_open; nx.storage.set( PDF.KEY_PLOT_OPEN, _open ? 1 : 0, true ); }, // 剧情触发 fire: function( _id, _cb, _force = false ) { // 进行中 let cur = this.vget( "id" ); if( nx.dt.strNEmpty( cur ) ) { nx.error( "$Plot:进行中,播放失败:", cur, _id ); nx.dt.fnInvoke( _cb, false, "PlotFailed" ); return false; } // 获取配置 let info = this.queryCfgs( _id ); if( nx.dt.objEmpty( info ) ) { nx.dt.fnInvoke( _cb, false, "PlotFailed" ); return false; } // 剧情不跳过 if( !this.opened && info.type != "dia" ) { nx.warn( "$Plot:引导未开启" ); nx.dt.fnInvoke( _cb, false, "PlotFailed" ); return false; } // 条件判断 let ret = nx.bridge.checkConditions( info.conditions ); if( nx.dt.objNEmpty( ret ) && !_force ) { // nx.warn( "$Plot:不滿足觸發條件:", _id ); nx.dt.fnInvoke( _cb, false, "PlotNoConds" ); return false; } // 是否触发过 if( nx.dt.arrMember( this.records.ids, _id ) ) { nx.warn( "$Plot:劇情重複觸發:", _id ); nx.bridge.vset( "DailyPop", 1 ); nx.dt.fnInvoke( _cb, false, "PlotRepeat" ); return false; } // 预先标记引导中 this.vset( "id", _id, false ); // 载入剧本 let path = cc.path.join( "configs/plots/jsons", info.json ); nx.res.loadJson( path, ( _err, _data ) => { if( _err ) { this.vset( "id", "" ); nx.error( "$Plot:载入剧本失败:", path ); nx.dt.fnInvoke( _cb, false, "PlotFailed" ); return; } this.cbDone = _cb; this.setCurrent( _id, _data ); } ); return true; }, // 强制触发剧情 fireForce: function( _id, _cb ) { // 从记录删除 nx.dt.arrDelete( this.records.ids, ( m ) => { return m == _id; } ); this.fire( _id, _cb, true ); }, // 设置当前剧情 setCurrent: function( _id, _json ) { // 清理 let id = "" + _id; if( nx.dt.strEmpty( id ) ) { this.vreset(); return; } // 新设置 this.vset( "info", _json ); this.vset( "skip", _json.skip ); this.vset( "total", _json.steps.length ); this.vset( "step", -1 ); this.vset( "id", id ); this.preCommited = false; nx.debug( "$Plot:开始剧情:", id ); // 埋点 if( nx.mTrace ) { nx.mTrace.trace( TTT.plotStart, id ); } }, // 下一步 next: function() { // 剧情完成 let step = this.vget( "step" ) + 1; if( step >= this.vget( "total" ) ) { this.done(); return; } if( CC_DEBUG ) { let info = this.vget( "info" ); let data = info ? info.steps[ step ] : null; console.log( "next:", step, data ); } // 设置 this.vset( "step", step ); // 埋点 if( nx.mTrace ) { nx.mTrace.trace( TTT.plotStep, this.vget( "id" ), step ); } }, // 引导中 isDoing: function() { let id = this.vget( "id" ); return nx.dt.strNEmpty( id ); }, // 剧情完成 done: function() { let id = this.vget( "id" ); nx.debug( "$Plot:引导完成.", id ); // 关闭 this.vreset(); nx.bridge.vset( "CloseSpecial", null ); // 存档 this.records.ids.push( id ); nx.storage.setObject( PDF.KEY_PLOTS, this.records, true ); // 尝试一次弹窗 let tryPops = function() { if( nx.bridge.popups ) { nx.bridge.popups.tryPopup(); } }; // 是否有串联剧情 let self = this; let next = function() { let info = self.queryCfgs( id ); if( !info || nx.dt.strEmpty( info.next ) ) { tryPops(); return; } self.fire( info.next, ( _ret ) => { if( !_ret ) { tryPops(); } } ); }; // 上传 this.reqComplete( id, () => { nx.dt.fnInvoke( this.cbDone, true ); this.cbDone = null; next(); } ); }, // 获取当前步骤剧本 stepData: function() { let info = this.vget( "info" ); let step = this.vget( "step" ); if( step == -1 ) { return null; } let data = info ? info.steps[ step ] : null; if( nx.dt.objEmpty( data ) ) { nx.error( "$Plot:获取当前剧本失败:", this.vget( "id" ), step ); } return data; }, // 是否已经解锁 isUnlocked: function( _id ) { return nx.dt.arrMember( this.records.ids, _id ); }, // ============================================================ // 引导元素 // ============================================================ // 注册引导元素 regUnit: function( _key, _node, _cb ) { let unit = this.units[ _key ]; if( unit ) { nx.error( "$Plot:重复注册元素:", _key ); return; } this.units[ _key ] = { node: _node, // 聚焦节点 cb: _cb, // 触发回调 }; nx.debug( "$Plot:注册元素:", _key ); }, // 注销引导元素 unregUnit: function( _key ) { let unit = this.units[ _key ]; if( unit ) { nx.debug( "$Plot:注销元素:", _key ); delete this.units[ _key ]; } }, // 查询引导元素 queryUnit: function( _key ) { let unit = this.units[ _key ]; if( !unit ) { nx.error( "$Plot:查询元素失败:", _key ); return null; } return this.units[ _key ]; }, // 查询引导配置 queryCfgs: function( _id ) { let key = nx.frame.vget( "hMode" ) ? `H${ _id }` : _id; let info = this.configs[ key ]; if( nx.dt.objEmpty( info ) ) { info = this.configs[ _id ]; } if( nx.dt.objEmpty( info ) ) { nx.error( "$Plot:配置缺失:", _id ); return null; } return info; }, // ============================================================ // 剧情事件 // ============================================================ // 发送 postKey: function( _key ) { nx.debug( "$Plot:事件 ", _key ); this.vset( "key", _key ); }, } ); // 模块导出 module.exports = PlotManager;