/** * WASM加载器 * 基于Cocos Creator官方文档的WASM/ASM加载最佳实践 * https://docs.cocos.com/creator/3.8/manual/zh/advanced-topics/wasm-asm-load.html */ import { Asset, assetManager, sys } from 'cc'; import { EDITOR } from 'cc/env'; // ASM模块内存配置常量 const PAGESIZE = 65536; // 64KiB const PAGECOUNT = 32 * 16; // 可根据需要调整 const MEMORYSIZE = PAGESIZE * PAGECOUNT; // 32 MiB export interface WasmLoadOptions { bundleName?: string; fileName: string; editorUuid?: string; // 编辑器内的资源UUID supportAsm?: boolean; // 是否支持ASM回退 asmFileName?: string; // ASM文件名 asmEditorUuid?: string; // ASM文件的编辑器UUID wasmFactory?: any; // WASM工厂函数 asmFactory?: any; // ASM工厂函数 } export interface WasmLoadResult { instance: any; isWasm: boolean; // true为WASM,false为ASM } export class WasmLoader { private static instance: WasmLoader; private initialized = false; private constructor() { } public static getInstance(): WasmLoader { if (!WasmLoader.instance) { WasmLoader.instance = new WasmLoader(); } return WasmLoader.instance; } /** * 初始化WASM加载器 * 注册WASM/ASM文件的下载器和解析器 */ public initialize(): void { if (this.initialized) { return; } // 判断当前平台是否支持加载WASM文件 // Cocos引擎目前暂不支持在iOS平台加载WASM文件 if (sys.hasFeature(sys.Feature.WASM) || (sys.isNative && sys.os !== sys.OS.IOS)) { if (sys.isNative) { // 原生平台 //@ts-ignore assetManager.downloader.register('.wasm', assetManager.downloader._downloaders[".bin"]); //@ts-ignore assetManager.parser.register('.wasm', assetManager.parser._parsers[".bin"]); } else if (sys.isBrowser || sys.platform === sys.Platform.WECHAT_GAME) { // 浏览器或微信小游戏平台 //@ts-ignore assetManager.downloader.register('.wasm', assetManager.downloader._downloadArrayBuffer); //@ts-ignore assetManager.downloader.register('.mem', assetManager.downloader._downloadArrayBuffer); } } else { // 不支持WASM的平台,注册ASM相关文件 if (sys.isNative) { //@ts-ignore assetManager.downloader.register('.mem', assetManager.downloader._downloaders[".bin"]); //@ts-ignore assetManager.parser.register('.mem', assetManager.parser._parsers[".bin"]); } } this.initialized = true; console.log('[WasmLoader] 初始化完成'); } /** * 加载WASM模块 * @param options 加载配置选项(必须包含工厂函数) * @returns Promise */ public async loadWasmModule(options: WasmLoadOptions): Promise { if (!this.initialized) { this.initialize(); } // 判断是否支持WASM if (sys.hasFeature(sys.Feature.WASM) || (sys.isNative && sys.os !== sys.OS.IOS)) { // 加载WASM return this.loadWasm(options); } else if (options.supportAsm && options.asmFileName && options.asmFactory) { // 回退到ASM return this.loadAsm(options); } else { throw new Error('当前平台不支持WASM,且未配置ASM回退选项'); } } /** * 加载WASM */ private async loadWasm(options: WasmLoadOptions): Promise { if (!options.wasmFactory) { throw new Error('WASM工厂函数未提供'); } try { const wasmFactory = options.wasmFactory; // 加载WASM二进制文件 const wasmFile = await this.loadWasmFile( options.bundleName || '', options.fileName, options.editorUuid ); // 初始化WASM const instance = await this.initWasm(wasmFactory, wasmFile); return { instance, isWasm: true }; } catch (error) { console.error('[WasmLoader] WASM加载失败:', error); throw error; } } /** * 加载ASM */ private async loadAsm(options: WasmLoadOptions): Promise { if (!options.asmFactory) { throw new Error('ASM工厂函数未提供'); } try { const asmFactory = options.asmFactory; // 加载ASM内存文件 const asmFile = await this.loadWasmFile( options.bundleName || '', options.asmFileName || options.fileName, options.asmEditorUuid ); // 初始化ASM const instance = await this.initAsm(asmFactory, asmFile); return { instance, isWasm: false }; } catch (error) { console.error('[WasmLoader] ASM加载失败:', error); throw error; } } /** * 加载WASM/ASM二进制文件 */ private loadWasmFile(bundleName: string, fileName: string, editorUuid?: string): Promise { return new Promise((resolve, reject) => { if (EDITOR) { // 编辑器内通过UUID加载资源 if (editorUuid) { assetManager.loadAny(editorUuid, (err, file: Asset) => { if (!err) { resolve(file); } else { reject(err); } }); } else { reject(new Error('编辑器环境下需要提供editorUuid')); } } else { // 运行时通过Bundle加载 if (bundleName && fileName) { assetManager.loadBundle(bundleName, (err, bundle) => { if (!err) { bundle.load(fileName, Asset, (err2: any, file: Asset) => { if (!err2) { resolve(file); } else { reject(err2); } }); } else { reject(err); } }); } else { reject(new Error('运行时环境下需要提供bundleName和fileName')); } } }); } /** * 初始化WASM模块 */ private initWasm(wasmFactory: any, wasmFile: Asset): Promise { const self = this; return new Promise((resolve, reject) => { wasmFactory({ instantiateWasm(importObject: WebAssembly.Imports, receiveInstance: any) { self.instantiateWasm(wasmFile, importObject).then((result) => { receiveInstance(result.instance, result.module); }).catch((err) => reject(err)); } }).then((instance: any) => { resolve(instance); }).catch((err: any) => reject(err)); }); } /** * 实例化WASM */ private instantiateWasm(wasmFile: Asset, importObject: WebAssembly.Imports): Promise { if (sys.isBrowser || sys.isNative) { //@ts-ignore return WebAssembly.instantiate(wasmFile._file, importObject); } else if (sys.platform === sys.Platform.WECHAT_GAME) { //@ts-ignore return CCWebAssembly.instantiate(wasmFile.nativeUrl, importObject); } else { return Promise.reject(new Error('不支持的平台')); } } /** * 初始化ASM模块 */ private initAsm(asmFactory: any, asmFile: Asset): Promise { const asmMemory: any = {}; asmMemory.buffer = new ArrayBuffer(MEMORYSIZE); const module = { asmMemory, memoryInitializerRequest: { //@ts-ignore response: asmFile._file, status: 200, } as Partial, }; return asmFactory(module); } /** * 便捷方法:加载简单的WASM模块(仅WASM,不支持ASM回退) */ public async loadSimpleWasm(wasmFactory: any, fileName: string, editorUuid?: string, bundleName?: string): Promise { const result = await this.loadWasmModule({ fileName, editorUuid, bundleName, supportAsm: false, wasmFactory }); return result.instance; } /** * 便捷方法:加载支持ASM回退的WASM模块 */ public async loadWasmWithAsmFallback( wasmFactory: any, asmFactory: any, fileName: string, asmFileName: string, editorUuid?: string, asmEditorUuid?: string, bundleName?: string ): Promise { return this.loadWasmModule({ fileName, editorUuid, bundleName, supportAsm: true, asmFileName, asmEditorUuid, wasmFactory, asmFactory }); } /** * 检查当前平台是否支持WASM */ public isWasmSupported(): boolean { return sys.hasFeature(sys.Feature.WASM) || (sys.isNative && sys.os !== sys.OS.IOS); } /** * 获取推荐的加载策略 */ public getRecommendedStrategy(): 'wasm' | 'asm' | 'unsupported' { if (this.isWasmSupported()) { return 'wasm'; } else if (sys.isNative || sys.isBrowser) { return 'asm'; } else { return 'unsupported'; } } } // 导出单例实例 export const wasmLoader = WasmLoader.getInstance();