UI资源加载规则配置

This commit is contained in:
宫欣海 2025-02-26 09:53:36 +08:00
parent 35fe0474e7
commit e2ab03b997
9 changed files with 315 additions and 18 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "kunpocc", "name": "kunpocc",
"version": "1.0.19", "version": "1.0.20",
"type": "module", "type": "module",
"description": "基于creator3.0+的kunpocc库", "description": "基于creator3.0+的kunpocc库",
"main": "./dist/kunpocc.cjs", "main": "./dist/kunpocc.cjs",

View File

@ -34,7 +34,7 @@ export class CocosUIModule extends ModuleBase {
// this._uiInitializer.init(this.reAdaptWhenScreenResize, this.fullIfWideScreen); // this._uiInitializer.init(this.reAdaptWhenScreenResize, this.fullIfWideScreen);
this.node.destroyAllChildren(); this.node.destroyAllChildren();
/** 注册窗口信息 */ /** 注册窗口信息 */
WindowManager.registerUI() WindowManager.registerUI();
this.onInit(); this.onInit();
} }

View File

@ -135,7 +135,7 @@ export abstract class WindowBase extends GComponent implements IWindow {
return this._header as T; return this._header as T;
} }
public setHeader<T extends IWindowHeader>(header: T): void { public _setHeader<T extends IWindowHeader>(header: T): void {
this._header = header; this._header = header;
} }

View File

@ -41,7 +41,8 @@ export { Ticker as BTTicker } from "./behaviortree/Ticker";
/** UI */ /** UI */
export { Window } from "./fgui/Window"; export { Window } from "./fgui/Window";
export { WindowHeader } from "./fgui/WindowHeader"; export { WindowHeader } from "./fgui/WindowHeader";
export * from "./ui/header"; export { AdapterType, WindowType } from "./ui/header";
export { IPackageConfig } from "./ui/IPackageConfig";
export { _uidecorator } from "./ui/UIDecorator"; export { _uidecorator } from "./ui/UIDecorator";
export { WindowGroup } from "./ui/WindowGroup"; export { WindowGroup } from "./ui/WindowGroup";
export { WindowHeaderInfo } from "./ui/WindowHeaderInfo"; export { WindowHeaderInfo } from "./ui/WindowHeaderInfo";

42
src/ui/IPackageConfig.ts Normal file
View File

@ -0,0 +1,42 @@
/**
* @Author: Gongxh
* @Date: 2025-02-25
* @Description:
*/
export interface IPackageConfig {
/** UI所在resources中的路径 */
uiPath: string;
/**
*
* 1. UI包,
* 2. header所在的包
* 3. , ,
*/
manualPackages: string[];
/**
*
*
*/
linkPackages: { [windowName: string]: string[] };
/**
*
* CPU时间GC的UI系统占用的内存是可以精确估算的使
*
*/
imReleasePackages: string[];
}
export interface IPackageConfigRes {
/** 配置信息 */
config: IPackageConfig;
/** 显示加载等待窗 */
showWaitWindow: () => void;
/** 隐藏加载等待窗 */
hideWaitWindow: () => void;
/** 打开窗口时UI包加载失败 */
fail: (windowName: string, errmsg: string, pkgs: string[]) => void;
}

View File

@ -75,5 +75,5 @@ export interface IWindow {
/** 获取资源栏数据 */ /** 获取资源栏数据 */
getHeaderInfo(): WindowHeaderInfo; getHeaderInfo(): WindowHeaderInfo;
setHeader(header: IWindowHeader): void; _setHeader(header: IWindowHeader): void;
} }

View File

@ -339,7 +339,7 @@ export class WindowGroup {
let name = headerInfo.name; let name = headerInfo.name;
let header = this._getHeader(name); let header = this._getHeader(name);
if (header) { if (header) {
window.setHeader(header); window._setHeader(header);
header._addRef(); header._addRef();
} else { } else {
// 创建header节点 // 创建header节点
@ -347,7 +347,7 @@ export class WindowGroup {
let newHeader = UIPackage.createObject(pkg, name) as WindowHeader; let newHeader = UIPackage.createObject(pkg, name) as WindowHeader;
newHeader.name = name; newHeader.name = name;
newHeader.opaque = false; newHeader.opaque = false;
window.setHeader(newHeader); window._setHeader(newHeader);
newHeader.visible = false; newHeader.visible = false;
PropsHelper.serializeProps(newHeader, pkg); PropsHelper.serializeProps(newHeader, pkg);
newHeader._init(); newHeader._init();
@ -390,4 +390,14 @@ export class WindowGroup {
this._alphaGraph.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true); this._alphaGraph.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
this._alphaGraph.setPivot(0.5, 0.5, true); this._alphaGraph.setPivot(0.5, 0.5, true);
} }
/**
*
*/
public closeAllWindow(): void {
while (this.size > 0) {
let name = this.getTopWindowName();
WindowManager.closeWindow(name);
}
}
} }

View File

@ -6,6 +6,7 @@
import { debug, warn } from "../tool/log"; import { debug, warn } from "../tool/log";
import { ComponentExtendHelper } from "./ComponentExtendHelper"; import { ComponentExtendHelper } from "./ComponentExtendHelper";
import { IPackageConfigRes } from "./IPackageConfig";
import { IWindow } from "./IWindow"; import { IWindow } from "./IWindow";
import { _uidecorator } from "./UIDecorator"; import { _uidecorator } from "./UIDecorator";
import { WindowGroup } from "./WindowGroup"; import { WindowGroup } from "./WindowGroup";
@ -21,24 +22,39 @@ export class WindowManager {
/** 初始化时传入实例 */ /** 初始化时传入实例 */
private static _resPool: WindowResPool; private static _resPool: WindowResPool;
/** /** 配置UI包的一些信息 (可以不配置 完全手动管理) */
* public static initPackageConfig(res: IPackageConfigRes): void {
* @param windowName this._resPool.initPackageConfig(res);
* @param userdata
*/
public static showWindow(windowName: string, userdata?: any): void {
//TODO::如果没有资源 加载资源
this.showWindowIm(windowName, userdata);
} }
/** /**
* * (UI包的资源未加载, WindowManager.initPackageConfig一起使用)
* @param windowName
* @param userdata
*/
public static async showWindow(windowName: string, userdata?: any): Promise<void> {
return new Promise((resolve, reject) => {
this._resPool.loadWindowRes(windowName, {
complete: () => {
this.showWindowIm(windowName, userdata);
resolve();
},
fail: (pkgs: string[]) => {
reject(pkgs);
}
});
});
}
/**
* ()
* @param windowName - * @param windowName -
* @param userdata - * @param userdata -
*/ */
public static showWindowIm(windowName: string, userdata?: any): void { public static showWindowIm(windowName: string, userdata?: any): void {
const info = this._resPool.get(windowName); const info = this._resPool.get(windowName);
const windowGroup = this.getWindowGroup(info.group); const windowGroup = this.getWindowGroup(info.group);
this._resPool.addResRef(windowName);
windowGroup.showWindow(info, userdata); windowGroup.showWindow(info, userdata);
} }
@ -71,6 +87,25 @@ export class WindowManager {
} }
} }
/**
*
* @param ignoreNames
*/
public static closeAllWindow(ignoreNames: string[] = []): void {
let existIgnore = ignoreNames.length > 0;
this._windows.forEach((window: IWindow, name: string) => {
if (!existIgnore) {
this.closeWindow(name);
} else if (!ignoreNames.includes(name)) {
this.closeWindow(name);
}
});
if (!existIgnore) {
this._windows.clear();
}
}
/** /**
* *
* @template T - IWindow * @template T - IWindow
@ -162,6 +197,7 @@ export class WindowManager {
if (this.hasWindow(name)) { if (this.hasWindow(name)) {
this._windows.get(name)._close(); this._windows.get(name)._close();
this._windows.delete(name); this._windows.delete(name);
this._resPool.releaseWindowRes(name);
} }
} }
@ -175,6 +211,7 @@ export class WindowManager {
for (const { ctor, res } of _uidecorator.getWindowMaps().values()) { for (const { ctor, res } of _uidecorator.getWindowMaps().values()) {
debug(`窗口注册 窗口名:${res.name} 包名:${res.pkg} 组名:${res.group}`); debug(`窗口注册 窗口名:${res.name} 包名:${res.pkg} 组名:${res.group}`);
this._resPool.add(ctor, res.group, res.pkg, res.name); this._resPool.add(ctor, res.group, res.pkg, res.name);
} }
// 窗口header注册 // 窗口header注册
for (const { ctor, res } of _uidecorator.getHeaderMaps().values()) { for (const { ctor, res } of _uidecorator.getHeaderMaps().values()) {

View File

@ -4,7 +4,9 @@
* @Description: * @Description:
*/ */
import { UIObjectFactory } from "fairygui-cc"; import { UIObjectFactory, UIPackage } from "fairygui-cc";
import { warn } from "../kunpocc";
import { IPackageConfigRes } from "./IPackageConfig";
export interface WindowInfo { export interface WindowInfo {
/** 类的构造函数 */ /** 类的构造函数 */
@ -28,7 +30,23 @@ export class WindowResPool {
/** 窗口header信息池 */ /** 窗口header信息池 */
protected _headerInfos: Map<string, HeaderInfo> = new Map<string, any>(); protected _headerInfos: Map<string, HeaderInfo> = new Map<string, any>();
/** 可扩展 窗口资源引用计数 */ /** 是否设置过配置内容 */
private _isInit: boolean = false;
/** 窗口名对应的包名列表 */
private _windowPkgs: Map<string, string[]> = new Map();
/** 包的引用计数 */
private _pkgRefs: { [pkg: string]: number } = {};
private _uipath: string = "";
private _manualPackages: Set<string> = new Set();
private _imReleasePackages: Set<string> = new Set();
/** 注册的回调函数 */
private _showWaitWindow: () => void = null;
private _hideWaitWindow: () => void = null;
private _fail: (windowName: string, errmsg: string, pkgs: string[]) => void = null;
/** 等待窗口的引用计数 */
private _waitRef: number = 0;
/** /**
* *
@ -44,6 +62,7 @@ export class WindowResPool {
pkg: pkg, pkg: pkg,
name: name name: name
}); });
this.addWindowPkg(name, pkg);
// 窗口组件扩展 // 窗口组件扩展
UIObjectFactory.setExtension(`ui://${pkg}/${name}`, ctor); UIObjectFactory.setExtension(`ui://${pkg}/${name}`, ctor);
} }
@ -82,4 +101,192 @@ export class WindowResPool {
} }
return this._headerInfos.get(name); return this._headerInfos.get(name);
} }
/** 资源配置相关接口 */
public initPackageConfig(res: IPackageConfigRes): void {
if (!res || !res.config) {
return;
}
if (this._isInit) {
throw new Error("资源配置已初始化,请勿重复设置");
}
this._isInit = true;
this._showWaitWindow = res?.showWaitWindow;
this._hideWaitWindow = res?.hideWaitWindow;
this._fail = res?.fail;
this._uipath = res.config?.uiPath || "";
// 如果uipath不以/结尾 则添加/
if (this._uipath != "" && !this._uipath.endsWith("/")) {
this._uipath += "/";
}
this._manualPackages = new Set(res.config.manualPackages || []);
this._imReleasePackages = new Set(res.config.imReleasePackages || []);
let windowPkgs = res.config.linkPackages || {};
for (const windowName in windowPkgs) {
let pkgs = windowPkgs[windowName];
for (const pkg of pkgs || []) {
this.addWindowPkg(windowName, pkg);
}
}
// 遍历一遍,剔除手动管理的包
this._windowPkgs.forEach((pkgs: string[], windowName: string) => {
for (let i = pkgs.length - 1; i >= 0; i--) {
if (this._manualPackages.has(pkgs[i])) {
pkgs.splice(i, 1);
}
}
if (pkgs.length <= 0) {
this._windowPkgs.delete(windowName);
}
});
}
/** 添加窗口对应的包名 */
public addWindowPkg(windowName: string, pkgName: string): void {
if (!this._windowPkgs.has(windowName)) {
this._windowPkgs.set(windowName, [pkgName]);
} else {
this._windowPkgs.get(windowName).push(pkgName);
}
}
/**
*
* @param windowName
*/
public loadWindowRes(windowName: string, listenter: { complete: () => void, fail: (pkgs: string[]) => void }): void {
// 资源配置未初始化 直接返回成功
if (!this._isInit) {
warn(`UI包信息未配置 将手动管理所有UI包资源的加载如果需要配置请使用 【WindowManager.initPackageConfig】接口`);
listenter.complete();
return;
}
// 不需要包资源 直接返回成功
if (!this.hasWindowPkg(windowName)) {
listenter.complete();
return;
}
if (this._waitRef++ <= 0) {
// 调用注入的回调函数 用来显示等待窗
this._showWaitWindow?.();
}
this.loadPackages({
pkgs: this.getWindowPkgs(windowName),
complete: () => {
if (--this._waitRef <= 0) {
// 调用注入的回调函数 关闭等待窗
listenter.complete();
this._hideWaitWindow?.();
}
},
fail: (pkgs: string[]) => {
warn(`界面${windowName}打开失败`);
listenter.fail(pkgs);
this._fail?.(windowName, "UI包加载失败", pkgs);
if (--this._waitRef <= 0) {
// 调用注入的回调函数 关闭等待窗
this._hideWaitWindow?.();
}
}
});
}
public addResRef(windowName: string): void {
if (!this._isInit) {
return;
}
// 不需要包资源 直接返回成功
if (!this.hasWindowPkg(windowName)) {
return;
}
let pkgs = this.getWindowPkgs(windowName);
for (const pkg of pkgs) {
this.addRef(pkg);
}
}
/**
*
* @param windowName
*/
public releaseWindowRes(windowName: string): void {
if (!this._isInit || !this.hasWindowPkg(windowName)) {
return;
}
let pkgs = this.getWindowPkgs(windowName);
for (const pkg of pkgs) {
this.decRef(pkg);
}
}
/**
* fgui包
* @param pkgs
* @param progress
* @param complete
*/
private loadPackages(res: { pkgs: string[], complete: () => void, fail: (pkgs: string[]) => void }): void {
// 过滤已经加载的包
let needLoadPkgs = res.pkgs.filter(pkg => this.getRef(pkg) <= 0);
let successPkgs: string[] = [];
let failPkgs: string[] = [];
let total: number = needLoadPkgs.length;
if (total <= 0) {
res.complete();
return;
}
for (const pkg of needLoadPkgs) {
UIPackage.loadPackage(this._uipath + pkg, (err: any) => {
total--;
err ? failPkgs.push(pkg) : successPkgs.push(pkg);
if (total > 0) {
return;
}
if (failPkgs.length > 0) {
res.fail(failPkgs);
} else {
res.complete();
}
});
}
}
/** 获取窗口对应的包名列表 */
private getWindowPkgs(windowName: string): string[] {
if (this._windowPkgs.has(windowName)) {
return this._windowPkgs.get(windowName);
}
return [];
}
private hasWindowPkg(windowName: string): boolean {
return this._windowPkgs.has(windowName);
}
/** 获取包的引用计数 */
private getRef(pkg: string): number {
return this._pkgRefs[pkg] ? this._pkgRefs[pkg] : 0;
}
/** 增加包的引用计数 */
private addRef(pkg: string): void {
this._pkgRefs[pkg] = this.getRef(pkg) + 1;
}
/** 减少包的引用计数 */
private decRef(pkg: string): void {
this._pkgRefs[pkg] = this.getRef(pkg) - 1;
if (this.getRef(pkg) <= 0) {
delete this._pkgRefs[pkg];
// 如果需要立即释放 释放包资源
if (this._imReleasePackages.has(pkg)) {
UIPackage.removePackage(pkg);
}
}
}
} }