refactor: reorganize package structure and decouple framework packages (#338)
* refactor: reorganize package structure and decouple framework packages ## Package Structure Reorganization - Reorganized 55 packages into categorized subdirectories: - packages/framework/ - Generic framework (Laya/Cocos compatible) - packages/engine/ - ESEngine core modules - packages/rendering/ - Rendering modules (WASM dependent) - packages/physics/ - Physics modules - packages/streaming/ - World streaming - packages/network-ext/ - Network extensions - packages/editor/ - Editor framework and plugins - packages/rust/ - Rust WASM engine - packages/tools/ - Build tools and SDK ## Framework Package Decoupling - Decoupled behavior-tree and blueprint packages from ESEngine dependencies - Created abstracted interfaces (IBTAssetManager, IBehaviorTreeAssetContent) - ESEngine-specific code moved to esengine/ subpath exports - Framework packages now usable with Cocos/Laya without ESEngine ## CI Configuration - Updated CI to only type-check and lint framework packages - Added type-check:framework and lint:framework scripts ## Breaking Changes - Package import paths changed due to directory reorganization - ESEngine integrations now use subpath imports (e.g., '@esengine/behavior-tree/esengine') * fix: update es-engine file path after directory reorganization * docs: update README to focus on framework over engine * ci: only build framework packages, remove Rust/WASM dependencies * fix: remove esengine subpath from behavior-tree and blueprint builds ESEngine integration code will only be available in full engine builds. Framework packages are now purely engine-agnostic. * fix: move network-protocols to framework, build both in CI * fix: update workflow paths from packages/core to packages/framework/core * fix: exclude esengine folder from type-check in behavior-tree and blueprint * fix: update network tsconfig references to new paths * fix: add test:ci:framework to only test framework packages in CI * fix: only build core and math npm packages in CI * fix: exclude test files from CodeQL and fix string escaping security issue
This commit is contained in:
268
packages/rendering/fairygui/src/asset/FGUITextureManager.ts
Normal file
268
packages/rendering/fairygui/src/asset/FGUITextureManager.ts
Normal file
@@ -0,0 +1,268 @@
|
||||
/**
|
||||
* FGUI Texture Manager
|
||||
*
|
||||
* Manages texture loading for FairyGUI.
|
||||
* Uses the global IAssetFileLoader for platform-agnostic asset loading.
|
||||
*
|
||||
* FGUI 纹理管理器
|
||||
* 使用全局 IAssetFileLoader 进行平台无关的资产加载
|
||||
*/
|
||||
|
||||
import { getGlobalAssetFileLoader } from '@esengine/asset-system';
|
||||
|
||||
/**
|
||||
* Texture service interface for engine integration
|
||||
* 引擎集成的纹理服务接口
|
||||
*/
|
||||
export interface ITextureService {
|
||||
/**
|
||||
* Load texture from URL/path (e.g., Blob URL)
|
||||
* 从 URL/路径加载纹理(如 Blob URL)
|
||||
*
|
||||
* @param url - URL to load texture from (Blob URL, HTTP URL, etc.)
|
||||
* @returns Engine texture ID (may be 0 if async loading)
|
||||
*/
|
||||
loadTextureByPath(url: string): number;
|
||||
|
||||
/**
|
||||
* Get texture ID if already loaded
|
||||
* 获取已加载的纹理 ID
|
||||
*
|
||||
* @param url - URL to check
|
||||
* @returns Texture ID or undefined if not loaded
|
||||
*/
|
||||
getTextureIdByPath?(url: string): number | undefined;
|
||||
}
|
||||
|
||||
/** Global texture service instance | 全局纹理服务实例 */
|
||||
let globalTextureService: ITextureService | null = null;
|
||||
|
||||
/**
|
||||
* Set global texture service
|
||||
* 设置全局纹理服务
|
||||
*/
|
||||
export function setGlobalTextureService(service: ITextureService | null): void {
|
||||
globalTextureService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get global texture service
|
||||
* 获取全局纹理服务
|
||||
*/
|
||||
export function getGlobalTextureService(): ITextureService | null {
|
||||
return globalTextureService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Texture entry with loading state
|
||||
* 带加载状态的纹理条目
|
||||
*/
|
||||
interface TextureEntry {
|
||||
/** Engine texture ID (0 = not loaded) | 引擎纹理 ID */
|
||||
textureId: number;
|
||||
/** Loading state | 加载状态 */
|
||||
state: 'pending' | 'loading' | 'loaded' | 'error';
|
||||
/** Load promise | 加载 Promise */
|
||||
promise?: Promise<number>;
|
||||
}
|
||||
|
||||
/**
|
||||
* FGUITextureManager
|
||||
*
|
||||
* Centralized texture management for FairyGUI.
|
||||
* Handles loading, caching, and resolution of textures.
|
||||
*
|
||||
* FairyGUI 的集中纹理管理
|
||||
* 处理纹理的加载、缓存和解析
|
||||
*/
|
||||
export class FGUITextureManager {
|
||||
private static _instance: FGUITextureManager | null = null;
|
||||
|
||||
/** Texture cache: asset path -> texture entry | 纹理缓存 */
|
||||
private _cache: Map<string, TextureEntry> = new Map();
|
||||
|
||||
private constructor() {}
|
||||
|
||||
/**
|
||||
* Get singleton instance
|
||||
* 获取单例实例
|
||||
*/
|
||||
public static getInstance(): FGUITextureManager {
|
||||
if (!FGUITextureManager._instance) {
|
||||
FGUITextureManager._instance = new FGUITextureManager();
|
||||
}
|
||||
return FGUITextureManager._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve texture path to engine texture ID
|
||||
* 解析纹理路径为引擎纹理 ID
|
||||
*
|
||||
* This is the main API for FGUIRenderDataProvider.
|
||||
* Returns 0 if texture is not yet loaded, triggering async load.
|
||||
*
|
||||
* @param texturePath - Relative asset path (e.g., "assets/ui/Bag_atlas0.png")
|
||||
* @returns Engine texture ID or 0 if pending
|
||||
*/
|
||||
public resolveTexture(texturePath: string): number {
|
||||
const entry = this._cache.get(texturePath);
|
||||
|
||||
if (entry) {
|
||||
if (entry.state === 'loaded') {
|
||||
return entry.textureId;
|
||||
}
|
||||
// Still loading or error, return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Start loading
|
||||
this._loadTexture(texturePath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if texture is loaded
|
||||
* 检查纹理是否已加载
|
||||
*/
|
||||
public isTextureLoaded(texturePath: string): boolean {
|
||||
const entry = this._cache.get(texturePath);
|
||||
return entry?.state === 'loaded';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get texture ID if loaded
|
||||
* 获取已加载的纹理 ID
|
||||
*/
|
||||
public getTextureId(texturePath: string): number | undefined {
|
||||
const entry = this._cache.get(texturePath);
|
||||
return entry?.state === 'loaded' ? entry.textureId : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preload textures
|
||||
* 预加载纹理
|
||||
*/
|
||||
public async preloadTextures(texturePaths: string[]): Promise<void> {
|
||||
const promises: Promise<number>[] = [];
|
||||
|
||||
for (const path of texturePaths) {
|
||||
const entry = this._cache.get(path);
|
||||
if (!entry) {
|
||||
promises.push(this._loadTexture(path));
|
||||
} else if (entry.promise) {
|
||||
promises.push(entry.promise);
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear texture cache
|
||||
* 清除纹理缓存
|
||||
*/
|
||||
public clear(): void {
|
||||
this._cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a single texture
|
||||
* 加载单个纹理
|
||||
*/
|
||||
private _loadTexture(texturePath: string): Promise<number> {
|
||||
const entry: TextureEntry = {
|
||||
textureId: 0,
|
||||
state: 'loading'
|
||||
};
|
||||
|
||||
entry.promise = this._doLoadTexture(texturePath, entry);
|
||||
this._cache.set(texturePath, entry);
|
||||
|
||||
return entry.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal texture loading implementation
|
||||
* 内部纹理加载实现
|
||||
*/
|
||||
private async _doLoadTexture(texturePath: string, entry: TextureEntry): Promise<number> {
|
||||
const assetLoader = getGlobalAssetFileLoader();
|
||||
const textureService = getGlobalTextureService();
|
||||
|
||||
if (!assetLoader) {
|
||||
console.error('[FGUITextureManager] No global asset file loader available');
|
||||
entry.state = 'error';
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!textureService) {
|
||||
console.error('[FGUITextureManager] No texture service available');
|
||||
entry.state = 'error';
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
// Load image via global asset file loader
|
||||
// The image.src will be a usable URL (Blob URL in editor, HTTP URL in browser)
|
||||
// 通过全局资产文件加载器加载图片
|
||||
// image.src 是可用的 URL(编辑器中是 Blob URL,浏览器中是 HTTP URL)
|
||||
const image = await assetLoader.loadImage(texturePath);
|
||||
|
||||
// Use the image's src URL to load texture in engine
|
||||
// 使用图片的 src URL 在引擎中加载纹理
|
||||
const textureId = textureService.loadTextureByPath(image.src);
|
||||
|
||||
if (textureId > 0) {
|
||||
entry.textureId = textureId;
|
||||
entry.state = 'loaded';
|
||||
} else {
|
||||
entry.state = 'error';
|
||||
console.error(`[FGUITextureManager] Failed to create texture: ${texturePath}`);
|
||||
}
|
||||
|
||||
return entry.textureId;
|
||||
} catch (err) {
|
||||
entry.state = 'error';
|
||||
console.error(`[FGUITextureManager] Failed to load texture: ${texturePath}`, err);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get global FGUI texture manager instance
|
||||
* 获取全局 FGUI 纹理管理器实例
|
||||
*/
|
||||
export function getFGUITextureManager(): FGUITextureManager {
|
||||
return FGUITextureManager.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Special texture key for white pixel (used for Graph rendering)
|
||||
* 白色像素的特殊纹理键(用于 Graph 渲染)
|
||||
*/
|
||||
export const WHITE_PIXEL_TEXTURE_KEY = '__fgui_white_pixel__';
|
||||
|
||||
/**
|
||||
* Create texture resolver function for FGUIRenderDataProvider
|
||||
* 创建 FGUIRenderDataProvider 的纹理解析函数
|
||||
*/
|
||||
export function createTextureResolver(): (textureId: string | number) => number {
|
||||
const manager = getFGUITextureManager();
|
||||
|
||||
return (textureId: string | number): number => {
|
||||
if (typeof textureId === 'number') {
|
||||
return textureId;
|
||||
}
|
||||
|
||||
// Handle special white pixel texture for Graph rendering
|
||||
// Engine texture ID 0 is the default white texture
|
||||
// 处理用于 Graph 渲染的特殊白色像素纹理
|
||||
// 引擎纹理 ID 0 是默认的白色纹理
|
||||
if (textureId === WHITE_PIXEL_TEXTURE_KEY) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return manager.resolveTexture(textureId);
|
||||
};
|
||||
}
|
||||
91
packages/rendering/fairygui/src/asset/FUIAssetLoader.ts
Normal file
91
packages/rendering/fairygui/src/asset/FUIAssetLoader.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* FUI Asset Loader
|
||||
*
|
||||
* Asset loader for FairyGUI package files (.fui).
|
||||
*
|
||||
* FairyGUI 包文件资产加载器
|
||||
*/
|
||||
|
||||
import type {
|
||||
IAssetLoader,
|
||||
IAssetParseContext,
|
||||
IAssetContent,
|
||||
AssetContentType
|
||||
} from '@esengine/asset-system';
|
||||
import { UIPackage } from '../package/UIPackage';
|
||||
|
||||
/**
|
||||
* FUI asset interface
|
||||
* FUI 资产接口
|
||||
*/
|
||||
export interface IFUIAsset {
|
||||
/** Loaded UIPackage instance | 加载的 UIPackage 实例 */
|
||||
package: UIPackage;
|
||||
/** Package ID | 包 ID */
|
||||
id: string;
|
||||
/** Package name | 包名称 */
|
||||
name: string;
|
||||
/** Resource key used for loading | 加载时使用的资源键 */
|
||||
resKey: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* FUI asset type constant
|
||||
* FUI 资产类型常量
|
||||
*/
|
||||
export const FUI_ASSET_TYPE = 'fui';
|
||||
|
||||
/**
|
||||
* FUIAssetLoader
|
||||
*
|
||||
* Loads FairyGUI package files (.fui) and creates UIPackage instances.
|
||||
*
|
||||
* 加载 FairyGUI 包文件并创建 UIPackage 实例
|
||||
*/
|
||||
export class FUIAssetLoader implements IAssetLoader<IFUIAsset> {
|
||||
readonly supportedType = FUI_ASSET_TYPE;
|
||||
readonly supportedExtensions = ['.fui'];
|
||||
readonly contentType: AssetContentType = 'binary';
|
||||
|
||||
/**
|
||||
* Parse FUI package from binary content
|
||||
* 从二进制内容解析 FUI 包
|
||||
*/
|
||||
async parse(content: IAssetContent, context: IAssetParseContext): Promise<IFUIAsset> {
|
||||
if (!content.binary) {
|
||||
throw new Error('FUIAssetLoader: Binary content is empty');
|
||||
}
|
||||
|
||||
// Use path as resource key
|
||||
const resKey = context.metadata.path;
|
||||
|
||||
// Load package from binary data
|
||||
const pkg = UIPackage.addPackageFromBuffer(resKey, content.binary);
|
||||
|
||||
return {
|
||||
package: pkg,
|
||||
id: pkg.id,
|
||||
name: pkg.name,
|
||||
resKey
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose loaded FUI asset
|
||||
* 释放已加载的 FUI 资产
|
||||
*/
|
||||
dispose(asset: IFUIAsset): void {
|
||||
if (asset.package) {
|
||||
UIPackage.removePackage(asset.resKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default FUI asset loader instance
|
||||
* 默认 FUI 资产加载器实例
|
||||
*/
|
||||
export const fuiAssetLoader = new FUIAssetLoader();
|
||||
|
||||
// Re-export types from asset-system for convenience
|
||||
export type { IAssetLoader, IAssetContent, IAssetParseContext, AssetContentType };
|
||||
34
packages/rendering/fairygui/src/asset/index.ts
Normal file
34
packages/rendering/fairygui/src/asset/index.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* FairyGUI Asset Loaders
|
||||
*
|
||||
* Asset loaders for FairyGUI package files.
|
||||
*
|
||||
* FairyGUI 包文件的资产加载器
|
||||
*/
|
||||
|
||||
export {
|
||||
FUIAssetLoader,
|
||||
fuiAssetLoader,
|
||||
FUI_ASSET_TYPE
|
||||
} from './FUIAssetLoader';
|
||||
|
||||
export type { IFUIAsset } from './FUIAssetLoader';
|
||||
|
||||
// Texture management | 纹理管理
|
||||
export {
|
||||
FGUITextureManager,
|
||||
getFGUITextureManager,
|
||||
createTextureResolver,
|
||||
setGlobalTextureService,
|
||||
getGlobalTextureService
|
||||
} from './FGUITextureManager';
|
||||
|
||||
export type { ITextureService } from './FGUITextureManager';
|
||||
|
||||
// Re-export types from asset-system for convenience
|
||||
export type {
|
||||
IAssetLoader,
|
||||
IAssetContent,
|
||||
IAssetParseContext,
|
||||
AssetContentType
|
||||
} from '@esengine/asset-system';
|
||||
Reference in New Issue
Block a user