* 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
236 lines
6.5 KiB
TypeScript
236 lines
6.5 KiB
TypeScript
/**
|
|
* Rust 引擎桥接层
|
|
* 负责在微信小游戏环境中初始化和管理 Rust WASM 引擎
|
|
*/
|
|
|
|
import type { IPlatformCanvas } from '@esengine/platform-common';
|
|
import { WeChatAdapter } from './WeChatAdapter';
|
|
|
|
/**
|
|
* 引擎配置
|
|
*/
|
|
export interface EngineBridgeConfig {
|
|
wasmPath: string;
|
|
canvasWidth?: number;
|
|
canvasHeight?: number;
|
|
enableWebGL2?: boolean;
|
|
}
|
|
|
|
/**
|
|
* 引擎桥接层
|
|
* 将微信平台能力桥接到 Rust WASM 引擎
|
|
*/
|
|
export class EngineBridge {
|
|
private _adapter: WeChatAdapter;
|
|
private _canvas: IPlatformCanvas;
|
|
private _gl: WebGLRenderingContext | WebGL2RenderingContext | null = null;
|
|
private _wasmInstance: any = null;
|
|
private _config: EngineBridgeConfig;
|
|
|
|
constructor(adapter: WeChatAdapter, config: EngineBridgeConfig) {
|
|
this._adapter = adapter;
|
|
this._config = config;
|
|
|
|
// 创建主 Canvas
|
|
const windowInfo = adapter.getSystemInfo();
|
|
const width = config.canvasWidth ?? windowInfo.windowWidth;
|
|
const height = config.canvasHeight ?? windowInfo.windowHeight;
|
|
|
|
this._canvas = adapter.canvas.createCanvas(width, height);
|
|
}
|
|
|
|
/**
|
|
* 初始化引擎
|
|
*/
|
|
async initialize(): Promise<void> {
|
|
// 获取 WebGL 上下文
|
|
this._gl = this._getWebGLContext();
|
|
if (!this._gl) {
|
|
throw new Error('无法获取 WebGL 上下文');
|
|
}
|
|
|
|
// 加载 WASM 模块
|
|
const imports = this._createWASMImports();
|
|
this._wasmInstance = await this._adapter.wasm.instantiate(
|
|
this._config.wasmPath,
|
|
imports
|
|
);
|
|
|
|
// 初始化引擎
|
|
if (this._wasmInstance.exports.init) {
|
|
this._wasmInstance.exports.init();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取 WebGL 上下文
|
|
*/
|
|
private _getWebGLContext(): WebGLRenderingContext | WebGL2RenderingContext | null {
|
|
const contextType = this._config.enableWebGL2 ? 'webgl2' : 'webgl';
|
|
const gl = this._canvas.getContext(contextType, {
|
|
alpha: false,
|
|
antialias: false,
|
|
depth: false,
|
|
stencil: false,
|
|
premultipliedAlpha: true,
|
|
preserveDrawingBuffer: false
|
|
});
|
|
|
|
return gl as WebGLRenderingContext | WebGL2RenderingContext | null;
|
|
}
|
|
|
|
/**
|
|
* 创建 WASM 导入对象
|
|
*/
|
|
private _createWASMImports(): Record<string, Record<string, any>> {
|
|
return {
|
|
env: {
|
|
// 内存
|
|
memory: this._adapter.wasm.createMemory(256, 16384),
|
|
|
|
// 平台桥接函数
|
|
platform_log: (ptr: number, len: number) => {
|
|
const message = this._readString(ptr, len);
|
|
console.log('[Engine]', message);
|
|
},
|
|
|
|
platform_error: (ptr: number, len: number) => {
|
|
const message = this._readString(ptr, len);
|
|
console.error('[Engine]', message);
|
|
},
|
|
|
|
platform_now: () => {
|
|
return performance.now();
|
|
},
|
|
|
|
// WebGL 桥接
|
|
gl_bindBuffer: (target: number, buffer: number) => {
|
|
this._gl?.bindBuffer(target, this._getGLObject(buffer));
|
|
},
|
|
|
|
gl_bufferData: (target: number, dataPtr: number, dataLen: number, usage: number) => {
|
|
const data = this._readBuffer(dataPtr, dataLen);
|
|
this._gl?.bufferData(target, data, usage);
|
|
},
|
|
|
|
gl_clear: (mask: number) => {
|
|
this._gl?.clear(mask);
|
|
},
|
|
|
|
gl_clearColor: (r: number, g: number, b: number, a: number) => {
|
|
this._gl?.clearColor(r, g, b, a);
|
|
},
|
|
|
|
gl_drawArrays: (mode: number, first: number, count: number) => {
|
|
this._gl?.drawArrays(mode, first, count);
|
|
},
|
|
|
|
gl_drawElements: (mode: number, count: number, type: number, offset: number) => {
|
|
this._gl?.drawElements(mode, count, type, offset);
|
|
},
|
|
|
|
gl_enable: (cap: number) => {
|
|
this._gl?.enable(cap);
|
|
},
|
|
|
|
gl_disable: (cap: number) => {
|
|
this._gl?.disable(cap);
|
|
},
|
|
|
|
gl_viewport: (x: number, y: number, width: number, height: number) => {
|
|
this._gl?.viewport(x, y, width, height);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 从 WASM 内存读取字符串
|
|
*/
|
|
private _readString(ptr: number, len: number): string {
|
|
const memory = this._wasmInstance?.exports.memory as WebAssembly.Memory;
|
|
if (!memory) return '';
|
|
|
|
const bytes = new Uint8Array(memory.buffer, ptr, len);
|
|
return new TextDecoder().decode(bytes);
|
|
}
|
|
|
|
/**
|
|
* 从 WASM 内存读取缓冲区
|
|
*/
|
|
private _readBuffer(ptr: number, len: number): ArrayBuffer {
|
|
const memory = this._wasmInstance?.exports.memory as WebAssembly.Memory;
|
|
if (!memory) return new ArrayBuffer(0);
|
|
|
|
return memory.buffer.slice(ptr, ptr + len);
|
|
}
|
|
|
|
/**
|
|
* 获取 WebGL 对象(暂时简化实现)
|
|
*/
|
|
private _getGLObject(_id: number): WebGLBuffer | null {
|
|
// TODO: 实现 WebGL 对象管理
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 获取 Canvas
|
|
*/
|
|
get canvas(): IPlatformCanvas {
|
|
return this._canvas;
|
|
}
|
|
|
|
/**
|
|
* 获取 WebGL 上下文
|
|
*/
|
|
get gl(): WebGLRenderingContext | WebGL2RenderingContext | null {
|
|
return this._gl;
|
|
}
|
|
|
|
/**
|
|
* 获取 WASM 实例
|
|
*/
|
|
get wasmInstance(): any {
|
|
return this._wasmInstance;
|
|
}
|
|
|
|
/**
|
|
* 清屏
|
|
*/
|
|
clear(r: number, g: number, b: number, a: number): void {
|
|
if (this._gl) {
|
|
this._gl.clearColor(r, g, b, a);
|
|
this._gl.clear(this._gl.COLOR_BUFFER_BIT);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 渲染一帧
|
|
*/
|
|
render(): void {
|
|
if (this._wasmInstance?.exports.render) {
|
|
this._wasmInstance.exports.render();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新逻辑
|
|
*/
|
|
update(deltaTime: number): void {
|
|
if (this._wasmInstance?.exports.update) {
|
|
this._wasmInstance.exports.update(deltaTime);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 销毁引擎
|
|
*/
|
|
dispose(): void {
|
|
if (this._wasmInstance?.exports.dispose) {
|
|
this._wasmInstance.exports.dispose();
|
|
}
|
|
this._wasmInstance = null;
|
|
this._gl = null;
|
|
}
|
|
}
|