/**
 * @file pg.ts
 * @description 游戏工具库，提供了游戏开发中常用的工具函数和类
 * 包括事件系统、时间控制、节点管理、资源加载、音频播放等功能
 */

/**
 * 事件发射器类，实现了观察者模式，用于事件的订阅和发布
 * 采用单例模式设计
 */
class Emitter {
    /** 单例实例 */
    static instance;
    /**
     * 获取单例实例
     * @returns {Emitter} Emitter的单例实例
     */
    static getInstance() {
        if (!Emitter.instance) {
            Emitter.instance = new Emitter();
        }
        return Emitter.instance;
    }
    /** 发射器名称 */
    _name: any;
    /** 回调函数映射表，key为事件名，value为回调函数数组 */
    _callbacks: any;
    /**
     * 构造函数
     * @param {string} name - 发射器名称
     * @returns {Emitter} 发射器实例
     */
    constructor(name = "") {
        this._name = name;
        this._callbacks = {};
        return this;
    }
    /**
     * 清空所有事件监听
     */
    clear() {
        this._callbacks = {};
    }
    /**
     * 添加事件监听
     * @param {string} event - 事件名称
     * @param {Function} fn - 回调函数
     */
    on(event, fn) {
        if (!this._callbacks[event]) this._callbacks[event] = [];
        this._callbacks[event].push(fn);
    };
    /**
     * 添加一次性事件监听，触发后自动移除
     * @param {string} event - 事件名称
     * @param {Function} fn - 回调函数
     */
    once(event, fn) {
        function on() {
            this.off(event, on);
            fn.apply(this, arguments);
        }
        on.fn = fn;
        this.on(event, on);
    };
    /**
     * 移除事件监听
     * @param {string} event - 事件名称
     * @param {Function} fn - 回调函数
     * @returns {void}
     */
    off(event, fn) {
        // all
        if (0 == arguments.length) {
            this._callbacks = {};
            return;
        }

        // specific event
        let callbacks = this._callbacks[event];
        if (!callbacks) return;

        // remove all handlers
        if (1 == arguments.length) {
            delete this._callbacks[event];
            return;
        }

        // remove specific handler
        let cb;
        for (let i = 0; i < callbacks.length; i++) {
            cb = callbacks[i];
            if (cb === fn || cb.fn === fn) {
                callbacks.splice(i, 1);
                break;
            }
        }
        return;
    }
    /**
     * 触发事件
     * @param {string} event - 事件名称
     * @param {...any} args - 传递给监听器的参数
     */
    emit(event, ...args) {
        this._callbacks = this._callbacks || {};
        // let args = [].slice.call(arguments, 1); 
        let callbacks = this._callbacks[event];
        if (callbacks) {
            callbacks = callbacks.slice(0);
            for (let i = 0, len = callbacks.length; i < len; ++i) {
                callbacks[i].apply(this, args);
            }
        }
    }
    /**
     * 获取指定事件的所有监听器
     * @param {string} event - 事件名称
     * @returns {Array<Function>} 监听器数组
     */
    listeners(event) {
        this._callbacks = this._callbacks || {};
        return this._callbacks[event] || [];
    };
    /**
     * 检查是否有指定事件的监听器
     * @param {string} event - 事件名称
     * @returns {boolean} 是否有监听器
     */
    hasListeners(event) {
        return !!this.listeners(event).length;
    };
}

/**
 * 时间控制器类，用于管理延时操作
 */
class TimeCtrl {
    /** 当前剩余时间（毫秒） */
    private current: number;
    /**
     * 构造函数
     */
    constructor() {
        this.current = 0;
    }
    /**
     * 添加时间
     * @param {number} time - 要添加的时间（秒）
     * @returns {TimeCtrl} 当前实例，用于链式调用
     */
    fillTime(time) {
        this.current += (time * 1000)
        return this;
    }
    /**
     * 设置时间
     * @param {number} time - 要设置的时间（秒）
     * @returns {TimeCtrl} 当前实例，用于链式调用
     */
    setTime(time) {
        this.current += (time * 1000)
        return this;
    }
    /**
     * 等待设定的时间
     * @returns {Promise<boolean>} 等待完成后的Promise
     */
    wait() {
        return new Promise((resolve, reject) => {
            let lastTime = new Date().getTime();
            let id = setInterval(() => {
                let nowTime = new Date().getTime();
                this.current -= (nowTime - lastTime);
                lastTime = nowTime;
                if (this.current <= 0) {
                    clearInterval(id);
                    resolve(true);
                }
            }, 1)
        });
    }
    /**
     * 重置时间为0
     * @returns {TimeCtrl} 当前实例，用于链式调用
     */
    reset() {
        this.current = 0;
        return this;
    }
}
/**
 * pg工具库，提供了游戏开发中常用的工具函数集合
 * 包括日志、视图操作、资源加载、本地存储、HTTP请求、音频播放、时间控制等功能
 */
let pg = {
    /**
     * 日志模块，提供不同级别的日志输出功能
     */
    logger: {
        /**
         * 输出调试日志
         * @param {string} str - 日志内容
         * @returns {null}
         */
        d: function (str) {
            cc.log(str);
            return null;
        },
        /**
         * 输出信息日志
         * @param {string} str - 日志内容
         * @returns {null}
         */
        i: function (str) {
            cc.log(str);
            return null;
        },
        /**
         * 输出警告日志
         * @param {string} str - 日志内容
         * @returns {null}
         */
        w: function (str) {
            cc.warn(str);
            return null;
        }
    },
    /**
     * 视图模块，提供节点管理、触控事件、渲染相关和动画播放等功能
     */
    view: {
        //---------------------节点管理------------------------------
        /**
         * 创建一个新节点
         * @returns {cc.Node} 新创建的节点
         */
        createNode() {
            let node = new cc.Node();
            return node;
        },
        /**
         * 添加子节点
         * @param {cc.Node|cc.Component} item - 父节点或组件
         * @param {cc.Node} child - 子节点
         * @param {number} [zIndex] - 子节点的渲染顺序
         * @returns {boolean} 是否添加成功
         */
        addChild(item, child, zIndex) {
            if (!child) return console.log("addChild error ->请传入子节点");
            if (!item) return console.log("addChild error ->请传入父节点");
            let node = item.node ? item.node : item;
            if (!node) return console.log("addChild error ->请传入父节点");
            if (child.parent)
                return pg.logger.w("此节点已经有父节点->" + child.name);
            if (zIndex >= 0) {
                node.addChild(child, zIndex)
            } else {
                node.addChild(child);
            }
            return true;
        },
        /**
         * 删除子节点
         * @param {cc.Node|cc.Component} item - 父节点或组件
         * @param {cc.Node} child - 要删除的子节点
         * @returns {boolean} 是否删除成功
         */
        removeChild(item, child) {
            if (!item) return pg.logger.w("节点remove失败,传入了错误的item");
            let node = item.node ? item.node : item;
            if (child.parent && child.parent == node) {
                node.removeChild(child);
                child.destroy();
            }
            return true;
        },
        /**
         * 移除节点自身
         * @param {cc.Node|cc.Component} item - 要移除的节点或组件
         * @returns {void}
         */
        removeSelf(item) {
            if (!item) return pg.logger.w("节点移除失败,传入了错误的item");
            let node = item.node ? item.node : item;
            node.removeFromParent();
            node.destroy();
        },
        /**
         * 删除所有子节点
         * @param {cc.Node|cc.Component} item - 父节点或组件
         * @returns {boolean} 是否删除成功
         */
        removChildren(item) {
            if (!item) return pg.logger.w("节点remove失败,传入了错误的item");
            let node = item.node ? item.node : item;
            if (!node.parent) return pg.logger.w("节点remove失败,传入了错误的item");
            node.removeAllChildren();
            return true;
        },
        /**
         * 查找节点
         * @param {cc.Node|cc.Component|string} item - 父节点或组件，如果是字符串则作为路径查找
         * @param {string} [childPath] - 子节点路径
         * @returns {cc.Node} 找到的节点
         */
        find(item, childPath): cc.Node {
            if (typeof item == "string") {
                childPath = item;
                item = null;
            }
            if (!childPath || childPath == '' || typeof childPath != 'string') return pg.logger.w("findChildByPath error->" + "请传入路径");
            let child = null;
            if (item) {
                let node = item.node ? item.node : item;
                if (!node.children || node.children.length == 0) return pg.logger.w("findChild error->" + "找不到此节点，请检查层级路径:" + childPath);
                child = cc.find(childPath, node);
            } else {
                child = cc.find(childPath);
            }
            if (!child) return pg.logger.w("findChildByPath error->" + "找不到此节点，请检查层级路径:" + childPath);
            return child;
        },
        //--------------------触控事件--------------------------------
        /**
         * 添加触摸事件监听
         * @param {cc.Node|cc.Component} item - 要添加监听的节点或组件
         * @param {Function} callback - 触摸回调函数
         * @param {object} target - 回调函数的this指向
         * @returns {boolean} 是否添加成功
         */
        touchOn(item, callback, target) {
            if (!item) return pg.logger.w("添加按钮响应失败,传入了错误的item");
            if (!callback || !target) return pg.logger.w("添加按钮响应失败,传入了空回调");
            let node = item.node ? item.node : item;
            node.on(cc.Node.EventType.TOUCH_END, callback, target);
            return true;
        },
        /**
         * 移除触摸事件监听
         * @param {cc.Node|cc.Component} item - 要移除监听的节点或组件
         * @param {Function} callback - 触摸回调函数
         * @param {object} target - 回调函数的this指向
         * @returns {boolean} 是否移除成功
         */
        touchOff(item, callback, target) {
            if (!item) return pg.logger.w("移除按钮响应失败,传入了错误的item");
            if (!callback || !target) return pg.logger.w("移除按钮响应失败,传入了空回调");
            let node = item.node ? item.node : item;
            if (!node || !node.parent) return pg.logger.w("节点已移除");
            node.off(cc.Node.EventType.TOUCH_END, callback, target);
            return true;
        },
        /**
         * 设置节点是否可点击
         * @param {cc.Node|cc.Component} item - 要设置的节点或组件
         * @param {boolean} isEnable - 是否允许点击
         * @returns {boolean} 是否设置成功
         */
        touchEnable(item, isEnable) {
            if (!item) return pg.logger.w("设置按钮响应失败,传入了错误的item");
            let node = item.node ? item.node : item;
            if (!node) return pg.logger.w("设置按钮响应失败,传入了错误的item");
            let btn = node.getComponent(cc.Button);
            if (!btn) return pg.logger.w("当前节点没有添加button->" + node.name);
            btn.interactable = isEnable;
            return true;
        },
        //-------------------渲染相关---------------------------------
        /**
         * 设置节点显示或隐藏
         * @param {cc.Node|cc.Component} item - 要设置的节点或组件
         * @param {boolean} isVisible - 是否显示
         * @returns {boolean} 是否设置成功
         */
        visible(item, isVisible) {
            if (!item) return pg.logger.w("节点显示失败,传入了错误的item");
            let node = item.node ? item.node : item;
            if (!node || !node.parent) return pg.logger.w("节点已移除");
            node.active = isVisible;
            return true;
        },
        /**
         * 更换节点的图片
         * @param {cc.Node|cc.Component} item - 要更换图片的节点或组件
         * @param {string} res - 图片资源路径
         * @returns {Promise<{width: number, height: number}>} 包含图片宽高的Promise
         */
        setImg(item, res) {
            return new Promise((resolve, reject) => {
                if (!item) return pg.logger.w("图片更换失败,传入了错误的item");
                if (!res) return pg.logger.w("图片更换失败,传入了错误的res");
                pg.load.loadImg(res).then((spriteFrame: cc.SpriteFrame) => {
                    if (!cc.isValid(item)) return pg.logger.i("节点已销毁");
                    let node = item.node ? item.node : item;
                    if (!cc.isValid(node)) return pg.logger.i("节点已销毁");
                    let component = node.getComponent(cc.Sprite);
                    let { width, height } = spriteFrame.getRect();
                    component.spriteFrame = spriteFrame;
                    resolve({ width, height });
                })
            })
        },
        /**
         * 设置网络图片
         * @param {cc.Node|cc.Component} item - 要设置图片的节点或组件
         * @param {string} res - 网络图片URL
         * @param {object} options - 配置选项
         * @param {number} options.w - 期望宽度
         * @param {number} options.h - 期望高度
         * @returns {Promise<{w: number, h: number}>} 包含图片宽高的Promise
         */
        setNetImg(item, res, { w, h }) {
            return new Promise((resolve, reject) => {
                if (!item) return pg.logger.w("图片更换失败,传入了错误的item");
                let node = item.node ? item.node : item;
                if (!res) {
                    if (node) node.active = false;
                    return pg.logger.w("图片更换失败,传入了错误的res");
                }
                if (!node) return pg.logger.w("图片更换失败,传入了错误的item");
                if (node.net_url == res) return;
                node.active = false;//
                pg.load.loadNetImg(res).then((texture: cc.Texture2D) => {
                    if (!cc.isValid(node)) return pg.logger.i("节点已销毁");
                    let nw = node.width = texture.width;
                    let nh = node.height = texture.height;
                    let component = node.getComponent(cc.Sprite);
                    let spriteFrame = new cc.SpriteFrame(texture);
                    component.spriteFrame = spriteFrame;
                    node.net_url = res;
                    if (!cc.isValid(node)) return pg.logger.i("节点已销毁");
                    if (!node) return pg.logger.w("节点已销毁");
                    if (w && h) {
                        let scaleX = w / nw;
                        let scaleY = h / nh;
                        let scale = scaleX <= scaleY ? scaleX : scaleY;
                        node.width = nw * scale;
                        node.height = nh * scale;
                    }
                    node.active = true;
                    resolve({ w: nw, h: nh });
                })
            })
        },
        /**
         * 将目标节点的图片设置到当前节点
         * @param {cc.Node|cc.Component} item - 要设置图片的节点或组件
         * @param {cc.Node} target - 图片来源节点
         * @returns {Promise<{width: number, height: number}>} 包含图片宽高的Promise
         */
        setNodeImg(item, target) {
            return new Promise((resolve, reject) => {
                if (!item) return pg.logger.w("图片更换失败,传入了错误的item");
                let spriteFrame = target.getComponent(cc.Sprite).spriteFrame;
                let node = item.node ? item.node : item;
                if (!cc.isValid(node)) return pg.logger.i("节点已销毁");
                let component = node.getComponent(cc.Sprite);
                let { width, height } = spriteFrame.getRect();
                component.spriteFrame = spriteFrame;
                resolve({ width, height });
            })
        },
        /**
         * 交换节点的两个材质
         * @param {cc.Node|cc.Component} item - 要交换材质的节点或组件
         * @param {number} [id0=0] - 第一个材质ID
         * @param {number} [id1=1] - 第二个材质ID
         */
        switchMaterial(item, id0 = 0, id1 = 1) {
            let material0 = item.getMaterial(id0);
            let material1 = item.getMaterial(id1);
            item.setMaterial(id0, material1);
            item.setMaterial(id1, material0);
        },
        /**
         * 设置文本内容
         * @param {cc.Node|cc.Component} item - 要设置文本的节点或组件
         * @param {string} text - 文本内容
         * @param {number} [count=0] - 文本长度限制，0表示不限制
         * @returns {boolean} 是否设置成功
         */
        setString(item, text, count = 0) {

            if (!item) return pg.logger.w("节点text失败,传入了错误的item");
            if (count > 0) {
                let parse_str = function (str, count) {
                    if (!str) return "";
                    var segmants = str.split('+');
                    str = segmants.join('');
                    var len = 0;
                    var idx = 0;
                    for (var i = 0; i < str.length; i++) {
                        var p = /[^x00-xff]/g;
                        var a = str.charAt(i);
                        if (p.test(a)) {
                            len += 2;
                            idx++;
                        }
                        else {
                            len += 1;
                            idx++;
                        }
                        if (len >= count * 2)
                            break;
                    }
                    return str.substr(0, idx);
                }
                text = parse_str(text, count);
            }
            let node = item.node ? item.node : item;
            if (!node) return;
            let component = node.getComponent(cc.Label);//组件功能 非node的功能
            component.string = text;
            return true;
        },
        /**
         * 设置节点颜色
         * @param {cc.Node|cc.Component} item - 要设置颜色的节点或组件
         * @param {string} color - 颜色值，十六进制格式如"#RRGGBB"
         * @param {number} [outlineWidth=-1] - 描边宽度，-1表示不设置描边
         * @returns {void}
         */
        setColor(item, color, outlineWidth = -1) {
            if (!item) return pg.logger.w("setColor warn->传入了错误的item");
            let RGB = this.colorRgb(color);
            if (!RGB || RGB.length == 0) return pg.logger.w("color ->传入了错误的color");
            item.color = new cc.Color(RGB[0], RGB[1], RGB[2]);
            if (outlineWidth < 0) return;
            let LabelOutline = item.getComponent(cc.LabelOutline);
            if (!LabelOutline) return pg.logger.w("LabelOutline warn->未添加描边");
            LabelOutline.width = outlineWidth;
        },
        /**
         * 将十六进制颜色转换为RGB数组
         * @param {string} color - 十六进制颜色值
         * @returns {number[]|string} RGB数组或原始颜色值
         */
        colorRgb(color) {
            var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
            var sColor = color;
            if (sColor && reg.test(sColor)) {
                if (sColor.length === 4) {
                    var sColorNew = "#";
                    for (var i = 1; i < 4; i += 1) {
                        sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
                    }
                    sColor = sColorNew;
                }
                //处理六位的颜色值
                var sColorChange = [];
                for (var i = 1; i < 7; i += 2) {
                    sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
                }
                return sColorChange;
            } else {
                return sColor;
            }
        },
        //-------------------动画播放--------------------------------
        /**
         * 播放Spine动画
         * @param {cc.Node|cc.Component} item - 包含Spine组件的节点或组件
         * @param {string} aniName - 动画名称
         * @param {boolean} loop - 是否循环播放
         * @returns {sp.Skeleton} Spine骨骼组件
         */
        playSpineAnimation(item, aniName, loop) {
            if (!item || !cc.isValid(item)) return pg.logger.w("动画播放失败,传入了错误的item");
            if (!aniName) return pg.logger.w("动画播放失败,传入了错误的aniName");
            let node = item.node ? item.node : item;
            if (!cc.isValid(node)) return pg.logger.w("节点已销毁");
            let skl = node.getComponent(sp.Skeleton);
            skl.setAnimation(0, aniName, loop);
            return skl;
        },
        /**
         * 播放DragonBones动画
         * @param {cc.Node|cc.Component} item - 包含DragonBones组件的节点或组件
         * @param {string} aniName - 动画名称
         * @param {number} [loop=-1] - 循环次数，-1表示无限循环
         * @returns {dragonBones.ArmatureDisplay} DragonBones骨骼组件
         */
        playDBAnimation(item, aniName, loop = -1) {
            if (!item || !cc.isValid(item)) return pg.logger.w("动画播放失败,传入了错误的item");
            if (!aniName) return pg.logger.w("动画播放失败,传入了错误的aniName");
            let node = item.node ? item.node : item;
            if (!cc.isValid(node)) return pg.logger.w("节点已销毁");
            let skl: dragonBones.ArmatureDisplay = node.getComponent(dragonBones.ArmatureDisplay);
            skl.playAnimation(aniName, loop);
            return skl;
        },


        /**
         * 为DragonBones动画添加每轮动画完成后的回调事件
         * @param {cc.Node|cc.Component} item - 包含DragonBones组件的节点或组件
         * @returns {dragonBones.ArmatureDisplay} DragonBones骨骼组件
         */
        addDBAnimationCallback(item, callback) {
            if (!item || !cc.isValid(item)) return pg.logger.w("添加动画回调失败,传入了错误的item");

            let node = item.node ? item.node : item;
            if (!cc.isValid(node)) return pg.logger.w("节点已销毁");

            let skl: dragonBones.ArmatureDisplay = node.getComponent(dragonBones.ArmatureDisplay);
            if (!skl) return pg.logger.w("节点上没有DragonBones组件");
            if (!callback) {
                skl.removeEventListener(dragonBones.EventObject.COMPLETE);
                return skl;
            }

            // 移除之前可能存在的监听器，避免重复添加
            skl.removeEventListener(dragonBones.EventObject.COMPLETE, callback);

            // 添加动画完成事件监听
            skl.addEventListener(dragonBones.EventObject.COMPLETE, callback);

            return skl;
        },

        /**
         * 为DragonBones动画添加一次性的动画完成回调事件，回调触发一次后自动移除
         * @param {cc.Node|cc.Component} item - 包含DragonBones组件的节点或组件
         * @returns {dragonBones.ArmatureDisplay} DragonBones骨骼组件
         */
        addDBAnimationCallbackOnce(item, callback) {
            if (!item || !cc.isValid(item)) return pg.logger.w("添加一次性动画回调失败,传入了错误的item");
            if (!callback) return pg.logger.w("添加一次性动画回调失败,未传入回调函数");

            let node = item.node ? item.node : item;
            if (!cc.isValid(node)) return pg.logger.w("节点已销毁");

            let skl: dragonBones.ArmatureDisplay = node.getComponent(dragonBones.ArmatureDisplay);
            if (!skl) return pg.logger.w("节点上没有DragonBones组件");

            // 创建一个包装回调，在执行原始回调后自动移除监听器
            const onceCallback = (event) => {
                // 先移除监听器，防止回调中可能的异常导致监听器未被移除
                skl.removeEventListener(dragonBones.EventObject.COMPLETE);
                // 执行原始回调
                callback(event);
            };

            // 移除之前可能存在的监听器，避免重复添加
            skl.removeEventListener(dragonBones.EventObject.COMPLETE, onceCallback);

            // 添加一次性动画完成事件监听
            skl.addEventListener(dragonBones.EventObject.COMPLETE, onceCallback);
 
            return skl;
        },

        /**
         * 设置DragonBones动画的播放速度
         * @param {cc.Node|cc.Component} item - 包含DragonBones组件的节点或组件
         * @param {number} timeScale - 动画播放速度倍率，1为正常速度，大于1加速，小于1减速，0暂停
         * @returns {dragonBones.ArmatureDisplay} DragonBones骨骼组件
         */
        timeScaleDBAnimation(item, timeScale = 1) {
            if (!item || !cc.isValid(item)) return pg.logger.w("设置动画速度失败,传入了错误的item");
            let node = item.node ? item.node : item;
            if (!cc.isValid(node)) return pg.logger.w("节点已销毁");

            let skl: dragonBones.ArmatureDisplay = node.getComponent(dragonBones.ArmatureDisplay);
            if (!skl) return pg.logger.w("节点上没有DragonBones组件");

            // 设置动画播放速度
            skl.timeScale = timeScale;

            return skl;
        },


        /**
         * 克隆节点
         * @param {cc.Node} node - 要克隆的节点
         * @returns {cc.Node} 克隆出的新节点
         */
        clone(node: cc.Node) {
            return cc.instantiate(node)
        }
    },
    /**
     * 资源加载模块，提供各种资源的加载功能
     */
    load: {
        //资源加载
        // loadBundle: function (bundleName) {
        //     return new Promise((resolve, reject) => {
        //         // let hallBundle = cc.assetManager.getBundle(`hall`);
        //         // hallBundle.releaseAll();
        //         // cc.assetManager.removeBundle(hallBundle);
        //         let bundle = cc.assetManager.getBundle(bundleName);
        //         if (bundle) return resolve('');
        //         cc.assetManager.loadBundle(bundleName, (err, bundle) => {
        //             if (err) return cc.error(err);
        //             resolve(bundle);
        //         });
        //     });
        // },
        /**
         * 加载资源
         * @param {string} res - 资源路径
         * @param {Function} type - 资源类型
         * @param {string} [bundleName] - 资源包名称
         * @returns {Promise<any>} 加载的资源
         */
        loadRes: function (res, type, bundleName) {
            //此处需要二次封装，新的存在assetbundle
            return new Promise((resolve, reject) => {
                cc.loader.loadRes(res, type, (err, data) => {
                    if (err && !data) return resolve(pg.logger.d('loading loadRes error-> ' + res));
                    resolve(data);
                });
            })
        },
        /**
         * 加载图片资源
         * @param {string} url - 图片资源路径
         * @returns {Promise<cc.SpriteFrame>} 加载的精灵帧
         */
        loadImg: function (url) {
            return new Promise((resolve, reject) => {
                this.loadRes(url, cc.SpriteFrame).then((data) => {
                    if (!data || data.length == 0) return;
                    resolve(data);
                })
            })
        },
        /**
         * 加载预制体
         * @param {string} [path=""] - 预制体路径
         * @returns {Promise<cc.Node>} 实例化后的节点
         */
        loadPrefab: function (path = "") {
            return new Promise((resolve, reject) => {
                let url = "/prefabs/" + path;
                this.loadRes(url, cc.Prefab).then((data) => {
                    if (!data || data.length == 0) return reject();
                    return resolve(cc.instantiate(data));
                })
            })
        },
        /**
         * 加载网络图片
         * @param {string} url - 网络图片URL
         * @returns {Promise<cc.Texture2D>} 加载的纹理
         */
        loadNetImg: function (url) {
            return new Promise((resolve, reject) => {
                cc.loader.load({ url }, (err, texture) => {
                    if (err && !texture) return resolve(pg.logger.w('loading loadRes warn-> ' + texture));
                    resolve(texture);
                });
            })
        },
        /**
         * 加载DragonBones动画资源
         * @param {cc.Node} item - 要加载动画的节点
         * @param {object} config - 配置信息
         * @param {string} config.png - 图片资源URL
         * @param {string} config.ske - 骨骼数据URL
         * @param {string} config.tex - 纹理数据URL
         * @returns {Promise<string>} 默认动画名称
         */
        loadDB(item, config) {
            return new Promise((resolve, reject) => {
                if (!config.png || !config.ske || !config.tex) {
                    return resolve('');
                }
                pg.load.loadNetRes(config.png).then((png: any) => {
                    pg.load.loadNetRes(config.ske).then((ske: any) => {
                        pg.load.loadNetRes(config.tex).then((tex: any) => {
                            var atlas = new dragonBones.DragonBonesAtlasAsset();
                            atlas.atlasJson = JSON.stringify(tex.json);
                            atlas.texture = png;

                            var asset = new dragonBones.DragonBonesAsset();
                            asset.dragonBonesJson = JSON.stringify(ske.json);

                            let dragonDisplay = item.getComponent(dragonBones.ArmatureDisplay);

                            dragonDisplay.dragonAtlasAsset = atlas;
                            dragonDisplay.dragonAsset = asset;

                            //设置
                            let defaultArmature = ske.json.armature[0];//aramture  所有的骨骼名称
                            dragonDisplay.armatureName = defaultArmature.name;
                            resolve(defaultArmature.animation[0].name);
                        })
                    })
                })

            });
        },
        /**
         * 加载网络资源
         * @param {string} url - 资源URL
         * @returns {Promise<any>} 加载的资源
         */
        loadNetRes: function (url) {
            return new Promise((resolve, reject) => {
                cc.assetManager.loadRemote(url, (err, info) => {
                    if (err) return resolve(pg.logger.w('loading loadRes warn-> ' + err));
                    resolve(info);
                });
            })
        },
    },
    /**
     * 本地存储模块，提供数据的本地存取功能
     */
    localStorage: {
        /**
         * 存储数据到本地
         * @param {string} key - 存储键名
         * @param {string} val - 存储的值
         */
        setItem: function (key, val) {
            cc.sys.localStorage.setItem(key, val);
        },
        /**
         * 从本地获取数据
         * @param {string} key - 存储键名
         * @param {string} defVal - 默认值，当键名不存在时返回
         * @returns {string} 存储的值或默认值
         */
        getItem: function (key, defVal) {
            return cc.sys.localStorage.getItem(key) || defVal;
        }
    },
    /**
     * HTTP请求模块，提供网络请求功能
     */
    http: {
        /**
         * 发送HTTP请求
         * @param {string} type - 请求类型，如 'GET', 'POST'
         * @param {string} url - 请求URL
         * @param {string|object} data - 请求数据
         * @param {Function} callback - 回调函数
         * @returns {Promise<any>} 请求结果
         */
        send: function (type, url, data, callback) {
            return new Promise((resolve) => {
                return setTimeout(() => {
                    return resolve({ status: 200 });
                }, 100 + Math.random() * 300);
                let xhr = cc.loader.getXMLHttpRequest();
                xhr.timeout = 5000;
                xhr.responseType = "text";
                xhr.open(type, url, true);
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                xhr.onreadystatechange = () => {
                    if (xhr.readyState !== 4) return;
                    if (xhr.status >= 200 && xhr.status < 300) {
                        try {
                            let resp = xhr.responseText;
                            pg.logger.d("resp->" + JSON.stringify(resp));
                            callback(resp);
                            resolve(resp);
                        } catch (e) {
                        }
                    }
                    else {

                    }
                };
                xhr.onerror = (e) => {
                    pg.logger.w("onerror->" + url);
                };
                xhr.ontimeout = (e) => {
                    pg.logger.w("ontimeout->" + url);
                };
                xhr.send(data);
            })

        }
    },
    /**
     * 音频模块，提供音频播放功能
     */
    audio: {
        /**
         * 通过URL播放音频
         * @param {string} audio_url - 音频URL
         * @param {Function} [cb=null] - 播放完成回调
         * @param {Function} [loadCb=null] - 加载完成回调
         * @returns {Promise<number>} 音频ID
         */
        playAudioByUrl(audio_url, cb = null, loadCb = null) {
            return new Promise((resolve, reject) => {
                if (!audio_url) return resolve(null);
                cc.assetManager.loadRemote(audio_url, (err, audioClip: any) => {
                    const audioId = cc.audioEngine.play(audioClip, false, 0.8);
                    cc.audioEngine.setFinishCallback(audioId, () => {
                        cb && cb();
                    });
                    loadCb && loadCb(audioId);
                    resolve(audioId);
                });
            });
        },
        /**
         * 通过URL播放背景音乐
         * @param {string} audio_url - 音频URL
         * @param {Function} [cb=null] - 播放完成回调
         * @param {Function} [loadCb=null] - 加载完成回调
         * @returns {Promise<number>} 音频ID
         */
        playBgAudioByUrl(audio_url, cb = null, loadCb = null) {
            return new Promise((resolve, reject) => {
                if (!audio_url) return resolve(null);
                cc.assetManager.loadRemote(audio_url, (err, audioClip: any) => {
                    const audioId = cc.audioEngine.playMusic(audioClip, true);
                    cc.audioEngine.setFinishCallback(audioId, () => {
                        cb && cb();
                    });
                    loadCb && loadCb(audioId);
                    resolve(audioId);
                });
            });
        },
        /**
         * 停止音频播放
         * @param {number} audioId - 音频ID
         */
        stopAudio(audioId) {
            if (!audioId) return;
            cc.audioEngine.stopEffect(audioId);
        },
        /**
         * 播放音频剪辑
         * @param {cc.AudioClip} audioClip - 音频剪辑
         * @param {Function} [cb=null] - 播放完成回调
         * @returns {number} 音频ID
         */
        playAudio(audioClip, cb = null) {
            if (audioClip) {
                const audioId = cc.audioEngine.playEffect(audioClip, false);
                if (cb) {
                    cc.audioEngine.setFinishCallback(audioId, () => {
                        cb && cb();
                    });
                }

                return audioId;
            }
        },
        /**
         * 播放节点上的音频
         * @param {cc.Node} audio - 包含AudioSource组件的节点
         * @returns {Promise<number>} 音频ID
         */
        playLocalAudio(audio: cc.Node) {
            return new Promise((resolve, reject) => {
                const id = cc.audioEngine.playEffect(audio.getComponent(cc.AudioSource).clip, false);
                cc.audioEngine.setFinishCallback(id, () => {
                    resolve(id);
                });
            })
        },
        /**
         * 获取音频剪辑
         * @param {string} audio_url - 音频URL
         * @returns {Promise<cc.AudioClip>} 音频剪辑
         */
        getAudioClip(audio_url) {
            return new Promise((resolve, reject) => {
                if (!audio_url) return resolve(null);
                cc.assetManager.loadRemote(audio_url, (err, audioClip: any) => {
                    resolve(audioClip);
                });
            });
        }

    },
    /**
     * 时间控制模块，提供延时和时间控制功能
     */
    time: {
        /**
         * 延时指定时间
         * @param {number} time - 延时时间（秒）
         * @returns {Promise<string>} 延时完成后的Promise
         */
        delay(time) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve('');
                }, time * 1000);
            });
        },
        /**
         * 创建时间控制器
         * @returns {TimeCtrl} 时间控制器实例
         */
        delayCtrl(): TimeCtrl {
            return new TimeCtrl();
        }
    },
    /**
     * 作业相关模块，提供作业相关功能
     */
    hw: {
        /**
         * 播放本地音频
         * @param {string} audioName - 音频名称
         * @param {boolean} [loop=false] - 是否循环播放
         * @returns {Promise<number>} 音频ID
         */
        playLocalAudio(audioName, loop = false) {
            console.log("play audio->" + audioName);
            const audio = cc.find(`Canvas/res/audio/${audioName}`).getComponent(cc.AudioSource);
            return new Promise((resolve, reject) => {
                const id = cc.audioEngine.playEffect(audio.clip, loop);
                resolve(id);
            })
        }
    },
    /**
     * 事件管理器，用于全局事件的订阅和发布
     */
    event: Emitter.getInstance()
};
/**
 * 导出pg工具库
 */
export default pg;