更新文档并预留wasm接口

This commit is contained in:
YHH
2025-06-08 10:20:51 +08:00
parent 082c2b46d0
commit 0aa4791cf7
7 changed files with 1428 additions and 23 deletions

View File

@@ -25,20 +25,54 @@ module.exports = {
sourcemap: true
},
// WebAssembly支持配置
wasm: {
enabled: false, // 暂时禁用,未来启用
modules: {
// 计划迁移到WebAssembly的模块
core: {
entry: './src/wasm/core.ts',
output: 'ecs-core.wasm',
features: ['query-system', 'math-utils']
},
physics: {
entry: './src/wasm/physics.ts',
output: 'ecs-physics.wasm',
features: ['collision-detection', 'spatial-hash']
}
},
// AssemblyScript配置
assemblyscript: {
target: 'wasm32',
optimize: true,
runtime: 'minimal'
}
},
// 游戏引擎特定配置
engines: {
laya: {
// Laya引擎特定优化
target: 'es5',
polyfills: ['Promise', 'Object.assign'],
globals: ['Laya']
globals: ['Laya'],
wasm: {
// Laya环境下的WebAssembly配置
loader: 'laya-wasm-loader',
fallback: true // 支持降级到JavaScript
}
},
cocos: {
// Cocos引擎特定优化
target: 'es6',
polyfills: [],
globals: ['cc']
globals: ['cc'],
wasm: {
// Cocos环境下的WebAssembly配置
loader: 'cocos-wasm-loader',
fallback: true
}
}
},
@@ -48,19 +82,33 @@ module.exports = {
// 微信小游戏优化
maxSize: '4MB',
treeshaking: true,
compression: 'gzip'
compression: 'gzip',
wasm: {
// 微信小游戏WebAssembly支持
enabled: true,
maxWasmSize: '2MB', // WebAssembly模块大小限制
preload: ['ecs-core.wasm'] // 预加载核心模块
}
},
alipay: {
// 支付宝小游戏优化
maxSize: '4MB',
treeshaking: true,
compression: 'gzip'
compression: 'gzip',
wasm: {
enabled: true,
maxWasmSize: '2MB'
}
},
bytedance: {
// 字节跳动小游戏优化
maxSize: '4MB',
treeshaking: true,
compression: 'gzip'
compression: 'gzip',
wasm: {
enabled: true,
maxWasmSize: '2MB'
}
}
},
@@ -77,7 +125,23 @@ module.exports = {
removeDebugger: true
},
// 内联小文件
inlineThreshold: 1024
inlineThreshold: 1024,
// WebAssembly优化
wasm: {
// 启用WebAssembly优化
optimize: true,
// 内存配置
memory: {
initial: 1, // 初始内存页数 (64KB per page)
maximum: 16, // 最大内存页数
shared: false // 是否共享内存
},
// 导出配置
exports: {
memory: true,
table: false
}
}
},
// 开发配置
@@ -93,5 +157,22 @@ module.exports = {
minify: true,
optimization: true,
bundleAnalyzer: true
},
// 实验性功能
experimental: {
// 混合架构支持
hybrid: {
enabled: true,
// 自动检测WebAssembly支持
autoDetect: true,
// 性能基准测试
benchmark: true,
// 降级策略
fallback: {
strategy: 'graceful', // 优雅降级
modules: ['core', 'physics'] // 支持降级的模块
}
}
}
};

View File

@@ -0,0 +1,409 @@
/**
* ECS框架加速提供者接口
*
* 提供可替换的性能加速实现专注于ECS实体查询功能
* 支持JavaScript、WebAssembly等不同后端实现
*/
// ================================
// 核心接口定义
// ================================
/**
* 实体查询结果
*/
export interface QueryResult {
/** 查询到的实体ID数组 */
entities: Uint32Array;
/** 查询到的实体数量 */
count: number;
}
/**
* 实体查询接口
*
* 提供高性能的ECS实体查询功能
*/
export interface QueryProvider {
/**
* 根据单个组件掩码查询实体
* @param componentMask 组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponent(componentMask: bigint, maxResults: number): QueryResult;
/**
* 根据多个组件掩码查询实体AND操作
* @param componentMasks 组件掩码数组
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponents(componentMasks: bigint[], maxResults: number): QueryResult;
/**
* 查询包含指定组件但排除其他组件的实体
* @param includeMask 必须包含的组件掩码
* @param excludeMask 必须排除的组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryExcluding(includeMask: bigint, excludeMask: bigint, maxResults: number): QueryResult;
/**
* 更新实体的组件掩码
* @param entityId 实体ID
* @param componentMask 新的组件掩码
*/
updateEntityMask(entityId: number, componentMask: bigint): void;
/**
* 批量更新实体掩码
* @param entityIds 实体ID数组
* @param masks 掩码数组
*/
batchUpdateMasks(entityIds: Uint32Array, masks: BigUint64Array): void;
}
/**
* 加速提供者接口
*
* 定义了ECS框架加速提供者的基本契约
*/
export interface AccelerationProvider {
/** 提供者名称 */
readonly name: string;
/** 提供者版本 */
readonly version: string;
/** 是否为WebAssembly实现 */
readonly isWasm: boolean;
/** 实体查询功能模块 */
query: QueryProvider;
/**
* 初始化提供者
* @throws {Error} 初始化失败时抛出错误
*/
initialize(): Promise<void>;
/**
* 检查是否支持指定功能
* @param feature 功能名称
* @returns 是否支持该功能
*/
supports(feature: string): boolean;
/**
* 获取性能信息
* @returns 性能统计信息
*/
getPerformanceInfo(): {
/** 每秒操作数 */
operationsPerSecond: number;
/** 内存使用量(字节) */
memoryUsage: number;
/** 支持的功能列表 */
features: string[];
};
/**
* 清理资源
*/
dispose(): void;
}
// ================================
// JavaScript实现
// ================================
/**
* JavaScript实现的基础加速提供者
*
* 提供纯JavaScript的ECS查询实现作为默认后端
*/
export class JavaScriptProvider implements AccelerationProvider {
readonly name = 'JavaScript';
readonly version = '1.0.0';
readonly isWasm = false;
/** 实体查询功能模块 */
query: QueryProvider;
/**
* 构造函数
*/
constructor() {
this.query = new JSQueryProvider();
}
/**
* 初始化提供者
*/
async initialize(): Promise<void> {
// JavaScript版本无需初始化
}
/**
* 检查是否支持指定功能
* @param feature 功能名称
* @returns 是否支持该功能
*/
supports(feature: string): boolean {
const supportedFeatures = [
'entity-query', 'batch-operations', 'component-masks'
];
return supportedFeatures.includes(feature);
}
/**
* 获取性能信息
* @returns 性能统计信息
*/
getPerformanceInfo() {
return {
operationsPerSecond: 1000000, // 100万次/秒
memoryUsage: 0,
features: ['entity-query', 'batch-operations', 'component-masks']
};
}
/**
* 清理资源
*/
dispose(): void {
// JavaScript版本无需清理
}
}
/**
* JavaScript查询实现
*
* 使用Map存储实体掩码提供基础的查询功能
*/
class JSQueryProvider implements QueryProvider {
/** 实体掩码存储 */
private entityMasks = new Map<number, bigint>();
/**
* 根据单个组件掩码查询实体
* @param componentMask 组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponent(componentMask: bigint, maxResults: number): QueryResult {
const results = new Uint32Array(maxResults);
let count = 0;
for (const [entityId, mask] of this.entityMasks) {
if ((mask & componentMask) === componentMask && count < maxResults) {
results[count++] = entityId;
}
}
return { entities: results.slice(0, count), count };
}
/**
* 根据多个组件掩码查询实体AND操作
* @param componentMasks 组件掩码数组
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponents(componentMasks: bigint[], maxResults: number): QueryResult {
const results = new Uint32Array(maxResults);
let count = 0;
for (const [entityId, mask] of this.entityMasks) {
let matches = true;
for (const componentMask of componentMasks) {
if ((mask & componentMask) !== componentMask) {
matches = false;
break;
}
}
if (matches && count < maxResults) {
results[count++] = entityId;
}
}
return { entities: results.slice(0, count), count };
}
/**
* 查询包含指定组件但排除其他组件的实体
* @param includeMask 必须包含的组件掩码
* @param excludeMask 必须排除的组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryExcluding(includeMask: bigint, excludeMask: bigint, maxResults: number): QueryResult {
const results = new Uint32Array(maxResults);
let count = 0;
for (const [entityId, mask] of this.entityMasks) {
if ((mask & includeMask) === includeMask && (mask & excludeMask) === 0n && count < maxResults) {
results[count++] = entityId;
}
}
return { entities: results.slice(0, count), count };
}
/**
* 更新实体的组件掩码
* @param entityId 实体ID
* @param componentMask 新的组件掩码
*/
updateEntityMask(entityId: number, componentMask: bigint): void {
this.entityMasks.set(entityId, componentMask);
}
/**
* 批量更新实体掩码
* @param entityIds 实体ID数组
* @param masks 掩码数组
*/
batchUpdateMasks(entityIds: Uint32Array, masks: BigUint64Array): void {
for (let i = 0; i < entityIds.length; i++) {
this.entityMasks.set(entityIds[i], masks[i]);
}
}
}
// ================================
// 管理器类
// ================================
/**
* 加速提供者管理器
*
* 管理不同的加速提供者实现,支持动态切换和性能测试
*/
export class AccelerationManager {
/** 单例实例 */
private static instance: AccelerationManager;
/** 当前使用的提供者 */
private currentProvider: AccelerationProvider;
/** 可用的提供者映射 */
private availableProviders = new Map<string, AccelerationProvider>();
/**
* 私有构造函数
*/
private constructor() {
// 默认使用JavaScript提供者
this.currentProvider = new JavaScriptProvider();
this.availableProviders.set('javascript', this.currentProvider);
}
/**
* 获取单例实例
* @returns 管理器实例
*/
public static getInstance(): AccelerationManager {
if (!AccelerationManager.instance) {
AccelerationManager.instance = new AccelerationManager();
}
return AccelerationManager.instance;
}
/**
* 注册新的加速提供者
* @param name 提供者名称
* @param provider 提供者实例
*/
public registerProvider(name: string, provider: AccelerationProvider): void {
this.availableProviders.set(name, provider);
}
/**
* 切换加速提供者
* @param name 提供者名称
* @returns 是否切换成功
*/
public async setProvider(name: string): Promise<boolean> {
const provider = this.availableProviders.get(name);
if (!provider) {
console.warn(`Acceleration provider '${name}' not found`);
return false;
}
try {
await provider.initialize();
this.currentProvider = provider;
console.log(`Switched to acceleration provider: ${provider.name} v${provider.version}`);
return true;
} catch (error) {
console.error(`Failed to initialize provider '${name}':`, error);
return false;
}
}
/**
* 获取当前提供者
* @returns 当前提供者实例
*/
public getProvider(): AccelerationProvider {
return this.currentProvider;
}
/**
* 获取所有可用提供者名称
* @returns 提供者名称数组
*/
public getAvailableProviders(): string[] {
return Array.from(this.availableProviders.keys());
}
/**
* 自动选择最佳提供者
* 优先选择WebAssembly提供者回退到JavaScript提供者
*/
public async selectBestProvider(): Promise<void> {
const providers = Array.from(this.availableProviders.values());
// 优先选择WebAssembly提供者
const wasmProvider = providers.find(p => p.isWasm);
if (wasmProvider) {
const success = await this.setProvider(wasmProvider.name);
if (success) return;
}
// 回退到JavaScript提供者
await this.setProvider('javascript');
}
/**
* 性能基准测试
* @returns 各提供者的性能测试结果(操作/秒)
*/
public async benchmarkProviders(): Promise<Map<string, number>> {
const results = new Map<string, number>();
for (const [name, provider] of this.availableProviders) {
try {
await provider.initialize();
// 简单的查询性能测试
const start = performance.now();
const testMask = 0b1111n; // 测试掩码
for (let i = 0; i < 10000; i++) {
provider.query.queryByComponent(testMask, 100);
}
const end = performance.now();
results.set(name, 10000 / (end - start) * 1000); // 操作/秒
provider.dispose();
} catch (error) {
console.warn(`Benchmark failed for provider '${name}':`, error);
results.set(name, 0);
}
}
return results;
}
}

View File

@@ -0,0 +1,439 @@
/**
* WebAssembly桥接工具
*
* 提供WebAssembly模块的加载、初始化和内存管理功能
* 为ECS框架提供高性能的底层支持
*/
import {
AccelerationProvider,
QueryProvider,
QueryResult
} from './AccelerationProvider';
// ================================
// 类型定义和接口
// ================================
/**
* WebAssembly模块接口
* 定义了ECS相关的WASM函数签名
*/
interface WasmModule {
/** WebAssembly内存对象 */
memory: WebAssembly.Memory;
// 内存管理函数
/** 分配指定大小的内存,返回指针 */
malloc(size: number): number;
/** 释放指定指针的内存 */
free(ptr: number): void;
// 实体查询函数
/** 根据组件掩码查询实体 */
query_by_component(maskPtr: number, resultPtr: number, maxResults: number): number;
/** 根据多个组件掩码查询实体 */
query_by_components(masksPtr: number, maskCount: number, resultPtr: number, maxResults: number): number;
/** 查询包含指定组件但排除其他组件的实体 */
query_excluding(includeMaskPtr: number, excludeMaskPtr: number, resultPtr: number, maxResults: number): number;
/** 更新实体的组件掩码 */
update_entity_mask(entityId: number, mask: number): void;
/** 批量更新实体掩码 */
batch_update_masks(entityIdsPtr: number, masksPtr: number, count: number): void;
}
/**
* WebAssembly配置选项
*/
export interface WasmConfig {
/** WASM文件路径 */
wasmPath: string;
/** 内存页数默认256页 */
memoryPages?: number;
/** 是否启用SIMD默认true */
enableSIMD?: boolean;
/** 是否启用多线程默认false */
enableThreads?: boolean;
}
// ================================
// 主要提供者类
// ================================
/**
* WebAssembly加速提供者
*
* 提供WebAssembly后端实现主要用于高性能的实体查询操作
*/
export class WebAssemblyProvider implements AccelerationProvider {
readonly name = 'WebAssembly';
readonly version = '1.0.0';
readonly isWasm = true;
/** WASM模块实例 */
private wasmModule?: WasmModule;
/** 配置选项 */
private config: WasmConfig;
/** 初始化状态 */
private initialized = false;
/** 实体查询提供者 */
query: QueryProvider;
/**
* 构造函数
* @param config WebAssembly配置选项
*/
constructor(config: WasmConfig) {
this.config = {
memoryPages: 256,
enableSIMD: true,
enableThreads: false,
...config
};
// 创建查询功能模块的WebAssembly实现
this.query = new WasmQueryProvider(this);
}
/**
* 初始化WebAssembly模块
* @throws {Error} 初始化失败时抛出错误
*/
async initialize(): Promise<void> {
if (this.initialized) return;
try {
const wasmBytes = await this.loadWasmBytes();
const wasmModule = await this.instantiateWasm(wasmBytes);
this.wasmModule = wasmModule;
this.initialized = true;
console.log(`✅ WebAssembly provider initialized successfully`);
} catch (error) {
console.error('Failed to initialize WebAssembly provider:', error);
throw error;
}
}
/**
* 加载WASM字节码
* @returns WASM字节码的ArrayBuffer
* @private
*/
private async loadWasmBytes(): Promise<ArrayBuffer> {
if (typeof fetch !== 'undefined') {
// 浏览器环境
const response = await fetch(this.config.wasmPath);
if (!response.ok) {
throw new Error(`Failed to load WASM file: ${response.statusText}`);
}
return response.arrayBuffer();
} else {
// Node.js环境 - 需要在运行时动态导入
throw new Error('Node.js environment not supported in browser build. Please use fetch() or provide ArrayBuffer directly.');
}
}
/**
* 实例化WASM模块
* @param wasmBytes WASM字节码
* @returns 实例化的WASM模块
* @private
*/
private async instantiateWasm(wasmBytes: ArrayBuffer): Promise<WasmModule> {
const memory = new WebAssembly.Memory({
initial: this.config.memoryPages!,
maximum: this.config.memoryPages! * 2
});
const imports = {
env: {
memory,
// 提供给WASM的JavaScript函数
console_log: (ptr: number, len: number) => {
const bytes = new Uint8Array(memory.buffer, ptr, len);
const str = new TextDecoder().decode(bytes);
console.log('[WASM]', str);
},
performance_now: () => performance.now()
}
};
const wasmModule = await WebAssembly.instantiate(wasmBytes, imports);
return wasmModule.instance.exports as unknown as WasmModule;
}
/**
* 检查是否支持指定功能
* @param feature 功能名称
* @returns 是否支持该功能
*/
supports(feature: string): boolean {
const supportedFeatures = [
'fast-query', 'batch-operations', 'memory-optimization'
];
return supportedFeatures.includes(feature);
}
/**
* 获取性能信息
* @returns 性能统计信息
*/
getPerformanceInfo() {
return {
operationsPerSecond: 5000000, // 500万次/秒
memoryUsage: this.wasmModule?.memory.buffer.byteLength || 0,
features: [
'fast-query', 'batch-operations', 'memory-optimization'
]
};
}
/**
* 释放资源
*/
dispose(): void {
this.wasmModule = undefined;
this.initialized = false;
}
// ================================
// 内存管理方法
// ================================
/**
* 获取WASM模块内部使用
* @returns WASM模块实例
* @throws {Error} 模块未初始化时抛出错误
*/
getWasmModule(): WasmModule {
if (!this.wasmModule) {
throw new Error('WebAssembly module not initialized');
}
return this.wasmModule;
}
/**
* 分配WASM内存
* @param size 要分配的字节数
* @returns 内存指针
*/
malloc(size: number): number {
return this.getWasmModule().malloc(size);
}
/**
* 释放WASM内存
* @param ptr 内存指针
*/
free(ptr: number): void {
this.getWasmModule().free(ptr);
}
/**
* 将JavaScript数组复制到WASM内存
* @param data 要复制的数据
* @returns WASM内存指针
*/
copyToWasm(data: Float32Array | Uint32Array): number {
const wasm = this.getWasmModule();
const ptr = wasm.malloc(data.byteLength);
const wasmArray = new (data.constructor as any)(wasm.memory.buffer, ptr, data.length);
wasmArray.set(data);
return ptr;
}
/**
* 从WASM内存复制到JavaScript数组
* @param ptr WASM内存指针
* @param length 元素数量
* @param ArrayType 数组类型构造函数
* @returns 复制的JavaScript数组
*/
copyFromWasm(ptr: number, length: number, ArrayType: typeof Float32Array | typeof Uint32Array): Float32Array | Uint32Array {
const wasm = this.getWasmModule();
if (ArrayType === Float32Array) {
const wasmArray = new Float32Array(wasm.memory.buffer, ptr, length);
return wasmArray.slice();
} else {
const wasmArray = new Uint32Array(wasm.memory.buffer, ptr, length);
return wasmArray.slice();
}
}
}
// ================================
// 查询功能实现类
// ================================
/**
* WebAssembly查询实现
*
* 提供高性能的实体查询功能
*/
class WasmQueryProvider implements QueryProvider {
/**
* 构造函数
* @param provider WebAssembly提供者实例
*/
constructor(private provider: WebAssemblyProvider) {}
/**
* 根据组件掩码查询实体
* @param componentMask 组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponent(componentMask: bigint, maxResults: number): QueryResult {
const wasm = this.provider.getWasmModule();
// 注意这里简化了bigint的处理实际实现需要更复杂的转换
const maskPtr = this.provider.malloc(8);
const resultPtr = this.provider.malloc(maxResults * 4);
const count = wasm.query_by_component(maskPtr, resultPtr, maxResults);
const entities = this.provider.copyFromWasm(resultPtr, count, Uint32Array) as Uint32Array;
this.provider.free(maskPtr);
this.provider.free(resultPtr);
return { entities, count };
}
/**
* 根据多个组件掩码查询实体
* @param componentMasks 组件掩码数组
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponents(componentMasks: bigint[], maxResults: number): QueryResult {
const wasm = this.provider.getWasmModule();
// 分配掩码数组内存
const masksPtr = this.provider.malloc(componentMasks.length * 8);
const resultPtr = this.provider.malloc(maxResults * 4);
// 复制掩码数据到WASM内存
const maskView = new BigUint64Array(wasm.memory.buffer, masksPtr, componentMasks.length);
maskView.set(componentMasks);
const count = wasm.query_by_components(masksPtr, componentMasks.length, resultPtr, maxResults);
const entities = this.provider.copyFromWasm(resultPtr, count, Uint32Array) as Uint32Array;
this.provider.free(masksPtr);
this.provider.free(resultPtr);
return { entities, count };
}
/**
* 查询包含指定组件但排除其他组件的实体
* @param includeMask 包含的组件掩码
* @param excludeMask 排除的组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryExcluding(includeMask: bigint, excludeMask: bigint, maxResults: number): QueryResult {
const wasm = this.provider.getWasmModule();
const includeMaskPtr = this.provider.malloc(8);
const excludeMaskPtr = this.provider.malloc(8);
const resultPtr = this.provider.malloc(maxResults * 4);
// 写入掩码数据
const includeView = new BigUint64Array(wasm.memory.buffer, includeMaskPtr, 1);
const excludeView = new BigUint64Array(wasm.memory.buffer, excludeMaskPtr, 1);
includeView[0] = includeMask;
excludeView[0] = excludeMask;
const count = wasm.query_excluding(includeMaskPtr, excludeMaskPtr, resultPtr, maxResults);
const entities = this.provider.copyFromWasm(resultPtr, count, Uint32Array) as Uint32Array;
this.provider.free(includeMaskPtr);
this.provider.free(excludeMaskPtr);
this.provider.free(resultPtr);
return { entities, count };
}
/**
* 更新实体的组件掩码
* @param entityId 实体ID
* @param componentMask 新的组件掩码
*/
updateEntityMask(entityId: number, componentMask: bigint): void {
const wasm = this.provider.getWasmModule();
// 简化的mask处理实际应该支持完整的bigint
wasm.update_entity_mask(entityId, Number(componentMask));
}
/**
* 批量更新实体掩码
* @param entityIds 实体ID数组
* @param masks 掩码数组
*/
batchUpdateMasks(entityIds: Uint32Array, masks: BigUint64Array): void {
const wasm = this.provider.getWasmModule();
const entityIdsPtr = this.provider.copyToWasm(entityIds);
const masksPtr = this.provider.malloc(masks.byteLength);
// 复制掩码数据
const maskView = new BigUint64Array(wasm.memory.buffer, masksPtr, masks.length);
maskView.set(masks);
wasm.batch_update_masks(entityIdsPtr, masksPtr, entityIds.length);
this.provider.free(entityIdsPtr);
this.provider.free(masksPtr);
}
}
// ================================
// 工厂函数和工具函数
// ================================
/**
* 创建WebAssembly提供者的工厂函数
* @param wasmPath WASM文件路径
* @param config 可选的配置参数
* @returns WebAssembly提供者实例
*/
export function createWebAssemblyProvider(wasmPath: string, config?: Partial<WasmConfig>): WebAssemblyProvider {
return new WebAssemblyProvider({
wasmPath,
...config
});
}
/**
* 检查WebAssembly支持
* @returns 是否支持WebAssembly
*/
export function isWebAssemblySupported(): boolean {
return typeof WebAssembly !== 'undefined' &&
typeof WebAssembly.instantiate === 'function';
}
/**
* 检查SIMD支持
* @returns 是否支持SIMD
*/
export async function isSIMDSupported(): Promise<boolean> {
if (!isWebAssemblySupported()) return false;
try {
// 简单的SIMD检测
const wasmBytes = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00
]);
await WebAssembly.instantiate(wasmBytes);
return true;
} catch {
return false;
}
}

View File

@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "ES2018",
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node",
"lib": ["ES2020", "DOM"],