UNPKG

@honor-minigame/cli

Version:

honor minigame pack cli

73 lines (67 loc) 3.11 kB
/** * renderflow-fix.js —— RenderFlow _assembler 空引用崩溃适配 * * 问题: * Uncaught TypeError: Cannot read properties of null (reading '_assembler') * 位于 cocos2d-runtime.js 的 _updateRenderData / _render / _postRender。 * * 根因: * Cocos Creator 2.4.x 的 RenderFlow 在渲染遍历时,若某节点仍带渲染标记 * (_renderFlag) 但其 _renderComponent 已被置为 null(节点/组件在渲染途中 * 销毁、 prefab 实例化后立即销毁、资源回调里移除节点等时序),_updateRenderData * 等步骤会执行 e._assembler.xxx(e) 而崩溃。引擎自身仅在 _color 步骤加了 * e&& 保护,_updateRenderData / _render / _postRender 三处遗漏。 * * 修复方式(不改引擎文件,仅运行时 monkey-patch): * 包裹 cc.RenderFlow.prototype 的这三个步骤。渲染组件及其 _assembler 有效时 * 完全走原函数(行为零差异);失效时跳过装配、清除对应 flag、继续 step 链, * 避免崩溃且不阻断后续渲染。由于 step 每帧经 createFlow 重建并重新绑定 * i._func = i._updateRenderData,原型方法替换后下一帧自动对全部节点生效。 */ (function () { 'use strict'; function apply() { if (typeof cc === 'undefined' || !cc.RenderFlow) return; var RF = cc.RenderFlow; var proto = RF.prototype; if (!proto || proto.__rfAsmFix) return; // 防重复 patch proto.__rfAsmFix = true; // 仅在异常路径需要清除的 flag(_render / _postRender 原本不清 flag, // 这里在失效时一并清掉,避免失效节点每帧反复进入兜底空转) var F_URD = RF.FLAG_UPDATE_RENDER_DATA; var F_RENDER = RF.FLAG_RENDER; var F_POST = RF.FLAG_POST_RENDER; /** * 包裹一个 RenderFlow 步骤方法。 * @param orig 原始步骤方法 * @param flag 该步骤对应的 RenderFlow flag 位(用于异常时清除) */ function wrap(orig, flag) { return function (t) { var e = t && t._renderComponent; if (e && e._assembler) { // 正常路径:交给原函数,行为与未 patch 完全一致 return orig.call(this, t); } // 异常路径:渲染组件已失效,跳过装配,清 flag 并推进 step 链 if (t && flag != null) t._renderFlag &= ~flag; if (this._next) this._next._func(t); }; } if (typeof proto._updateRenderData === 'function') { proto._updateRenderData = wrap(proto._updateRenderData, F_URD); } if (typeof proto._render === 'function') { proto._render = wrap(proto._render, F_RENDER); } if (typeof proto._postRender === 'function') { proto._postRender = wrap(proto._postRender, F_POST); } } // cocos2d-runtime.js 加载后 cc.RenderFlow 即同步可用;若本文件被更早 // require,则等引擎初始化完成事件再补一次,确保一定 patch 成功。 apply(); if (typeof cc !== 'undefined' && cc.game && cc.game.once) { cc.game.once(cc.game.EVENT_GAME_INITED, apply); } })();