@honor-minigame/cli
Version:
honor minigame pack cli
73 lines (67 loc) • 3.11 kB
JavaScript
/**
* 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);
}
})();