feat(worker): 添加微信小游戏 Worker 支持和 Worker Generator CLI (#297)
* feat(worker): 添加微信小游戏 Worker 支持和 Worker Generator CLI - 新增 @esengine/worker-generator 包,用于从 WorkerEntitySystem 生成 Worker 文件 - WorkerEntitySystem 添加 workerScriptPath 配置项,支持预编译 Worker 脚本 - CLI 工具支持 --wechat 模式,自动转换 ES6+ 为 ES5 语法 - 修复微信小游戏 Worker 消息格式差异(res 直接是数据,无需 .data) - 更新中英文文档,添加微信小游戏支持章节 * docs: 更新 changelog,添加 v2.3.1 说明并标注 v2.3.0 为废弃 * fix: 修复 CI 检查问题 - 移除 cli.ts 中未使用的 toKebabCase 函数 - 修复 generator.ts 中正则表达式的 ReDoS 风险(使用 [ \t] 替代 \s*) - 更新 changelog 版本号(2.3.1 -> 2.3.2) * docs: 移除未发布版本的 changelog 条目 * fix(worker-generator): 使用 TypeScript 编译器替代手写正则进行 ES5 转换 - 修复 CodeQL 检测的 ReDoS 安全问题 - 使用 ts.transpileModule 进行安全可靠的代码转换 - 移除所有可能导致回溯的正则表达式
This commit is contained in:
@@ -34,6 +34,20 @@ export interface WorkerSystemConfig {
|
||||
entityDataSize?: number;
|
||||
/** 最大实体数量(用于预分配SharedArrayBuffer) */
|
||||
maxEntities?: number;
|
||||
/**
|
||||
* 预编译 Worker 脚本路径(微信小游戏等不支持动态脚本的平台必需)
|
||||
* Pre-compiled Worker script path (required for platforms like WeChat Mini Game that don't support dynamic scripts)
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // 微信小游戏使用方式:
|
||||
* // 1. 创建 Worker 文件: workers/physics-worker.js
|
||||
* // 2. 在 game.json 配置 "workers": "workers"
|
||||
* // 3. 指定路径:
|
||||
* workerScriptPath: 'workers/physics-worker.js'
|
||||
* ```
|
||||
*/
|
||||
workerScriptPath?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,9 +202,10 @@ export type SharedArrayBufferProcessFunction = (
|
||||
* ```
|
||||
*/
|
||||
export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem {
|
||||
protected config: Required<Omit<WorkerSystemConfig, 'systemConfig' | 'entitiesPerWorker'>> & {
|
||||
protected config: Required<Omit<WorkerSystemConfig, 'systemConfig' | 'entitiesPerWorker' | 'workerScriptPath'>> & {
|
||||
systemConfig?: any;
|
||||
entitiesPerWorker?: number;
|
||||
workerScriptPath?: string;
|
||||
};
|
||||
private workerPool: PlatformWorkerPool | null = null;
|
||||
private isProcessing = false;
|
||||
@@ -222,7 +237,8 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
...(config.entitiesPerWorker !== undefined && { entitiesPerWorker: config.entitiesPerWorker }),
|
||||
useSharedArrayBuffer: config.useSharedArrayBuffer ?? this.isSharedArrayBufferSupported(),
|
||||
entityDataSize: config.entityDataSize ?? this.getDefaultEntityDataSize(),
|
||||
maxEntities: config.maxEntities ?? 10000
|
||||
maxEntities: config.maxEntities ?? 10000,
|
||||
...(config.workerScriptPath !== undefined && { workerScriptPath: config.workerScriptPath })
|
||||
};
|
||||
|
||||
|
||||
@@ -300,16 +316,34 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
*/
|
||||
private initializeWorkerPool(): void {
|
||||
try {
|
||||
const script = this.createWorkerScript();
|
||||
|
||||
// 在WorkerEntitySystem中处理平台相关逻辑
|
||||
const workers: PlatformWorker[] = [];
|
||||
const platformConfig = this.platformAdapter.getPlatformConfig();
|
||||
const fullScript = (platformConfig.workerScriptPrefix || '') + script;
|
||||
const workers: PlatformWorker[] = [];
|
||||
|
||||
// 判断使用外部脚本路径还是动态生成脚本
|
||||
// Determine whether to use external script path or dynamically generated script
|
||||
let scriptOrPath: string;
|
||||
|
||||
if (this.config.workerScriptPath) {
|
||||
// 使用预编译的外部 Worker 文件(微信小游戏等平台)
|
||||
// Use pre-compiled external Worker file (for WeChat Mini Game, etc.)
|
||||
scriptOrPath = this.config.workerScriptPath;
|
||||
this.logger.info(`${this.systemName}: 使用外部Worker文件: ${scriptOrPath}`);
|
||||
} else if (platformConfig.limitations?.noEval) {
|
||||
// 平台不支持动态脚本,且未提供外部脚本路径
|
||||
// Platform doesn't support dynamic scripts and no external script path provided
|
||||
this.logger.error(`${this.systemName}: 当前平台不支持动态Worker脚本,请配置 workerScriptPath 指定预编译的Worker文件`);
|
||||
this.config.enableWorker = false;
|
||||
return;
|
||||
} else {
|
||||
// 动态生成 Worker 脚本(浏览器等支持的平台)
|
||||
// Dynamically generate Worker script (for browsers and other supported platforms)
|
||||
const script = this.createWorkerScript();
|
||||
scriptOrPath = (platformConfig.workerScriptPrefix || '') + script;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.config.workerCount; i++) {
|
||||
try {
|
||||
const worker = this.platformAdapter.createWorker(fullScript, {
|
||||
const worker = this.platformAdapter.createWorker(scriptOrPath, {
|
||||
name: `WorkerEntitySystem-${i}`
|
||||
});
|
||||
workers.push(worker);
|
||||
|
||||
Reference in New Issue
Block a user