worker系统不支持sab回退到普通worker

This commit is contained in:
YHH
2025-09-28 20:22:06 +08:00
parent 1dfcd008aa
commit dedb91379f
6 changed files with 164 additions and 69 deletions

3
docs/public/_headers Normal file
View File

@@ -0,0 +1,3 @@
/*
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin

View File

@@ -19,16 +19,12 @@
}).observe(document, { childList: true, subtree: true });
function getFetchOpts(link) {
const fetchOpts = {};
if (link.integrity)
fetchOpts.integrity = link.integrity;
if (link.referrerPolicy)
fetchOpts.referrerPolicy = link.referrerPolicy;
if (link.integrity) fetchOpts.integrity = link.integrity;
if (link.referrerPolicy) fetchOpts.referrerPolicy = link.referrerPolicy;
if (link.crossOrigin === "use-credentials")
fetchOpts.credentials = "include";
else if (link.crossOrigin === "anonymous")
fetchOpts.credentials = "omit";
else
fetchOpts.credentials = "same-origin";
else if (link.crossOrigin === "anonymous") fetchOpts.credentials = "omit";
else fetchOpts.credentials = "same-origin";
return fetchOpts;
}
function processPreload(link) {
@@ -1077,28 +1073,14 @@ var LogLevel;
LogLevel2[LogLevel2["None"] = 5] = "None";
})(LogLevel || (LogLevel = {}));
const Colors = {
// 基础颜色
BLACK: "\x1B[30m",
RED: "\x1B[31m",
GREEN: "\x1B[32m",
YELLOW: "\x1B[33m",
BLUE: "\x1B[34m",
MAGENTA: "\x1B[35m",
CYAN: "\x1B[36m",
WHITE: "\x1B[37m",
// 亮色版本
BRIGHT_BLACK: "\x1B[90m",
BRIGHT_RED: "\x1B[91m",
BRIGHT_GREEN: "\x1B[92m",
BRIGHT_YELLOW: "\x1B[93m",
BRIGHT_BLUE: "\x1B[94m",
BRIGHT_MAGENTA: "\x1B[95m",
BRIGHT_CYAN: "\x1B[96m",
BRIGHT_WHITE: "\x1B[97m",
// 特殊
RESET: "\x1B[0m",
BOLD: "\x1B[1m",
UNDERLINE: "\x1B[4m"
RESET: "\x1B[0m"
};
class ConsoleLogger {
constructor(config = {}) {
@@ -1403,8 +1385,7 @@ class SoAStorage {
const value = instance[key];
const type = typeof value;
if (type === "number") {
if (highPrecisionFields.has(key))
;
if (highPrecisionFields.has(key)) ;
else if (float64Fields.has(key)) {
this.fields.set(key, new Float64Array(this._capacity));
} else if (int32Fields.has(key)) {
@@ -11388,12 +11369,20 @@ class WorkerEntitySystem extends EntitySystem {
*/
initializeSharedArrayBuffer() {
try {
if (!this.isSharedArrayBufferSupported()) {
console.warn(`[${this.systemName}] SharedArrayBuffer not supported, falling back to traditional Worker mode`);
this.config.useSharedArrayBuffer = false;
return;
}
const bufferSize = this.config.maxEntities * this.config.entityDataSize * 4;
this.sharedBuffer = new SharedArrayBuffer(bufferSize);
this.sharedFloatArray = new Float32Array(this.sharedBuffer);
console.log(`[${this.systemName}] SharedArrayBuffer initialized successfully (${bufferSize} bytes)`);
} catch (error) {
console.warn(`[${this.systemName}] SharedArrayBuffer init failed:`, error);
console.warn(`[${this.systemName}] SharedArrayBuffer init failed, falling back to traditional Worker mode:`, error);
this.config.useSharedArrayBuffer = false;
this.sharedBuffer = null;
this.sharedFloatArray = null;
}
}
/**
@@ -11506,21 +11495,26 @@ class WorkerEntitySystem extends EntitySystem {
this.isProcessing = true;
try {
if (this.config.enableWorker && this.workerPool) {
if (this.config.useSharedArrayBuffer && this.sharedFloatArray) {
if (this.config.useSharedArrayBuffer && this.sharedFloatArray && this.isSharedArrayBufferSupported()) {
this.processWithSharedArrayBuffer(entities).finally(() => {
this.isProcessing = false;
});
} else {
if (this.config.useSharedArrayBuffer) {
console.log(`[${this.systemName}] Falling back to traditional Worker mode for this frame`);
}
this.processWithWorker(entities).finally(() => {
this.isProcessing = false;
});
}
} else {
console.log(`[${this.systemName}] Worker not available, processing synchronously`);
this.processSynchronously(entities);
this.isProcessing = false;
}
} catch (error) {
this.isProcessing = false;
console.error(`[${this.systemName}] Processing failed:`, error);
throw error;
}
}
@@ -11666,10 +11660,21 @@ class WorkerEntitySystem extends EntitySystem {
* 获取系统性能信息
*/
getWorkerInfo() {
let currentMode = "sync";
if (this.config.enableWorker && this.workerPool) {
if (this.config.useSharedArrayBuffer && this.sharedFloatArray && this.isSharedArrayBufferSupported()) {
currentMode = "shared-buffer";
} else {
currentMode = "worker";
}
}
return {
enabled: this.config.enableWorker,
workerCount: this.config.workerCount,
isProcessing: this.isProcessing
isProcessing: this.isProcessing,
sharedArrayBufferSupported: this.isSharedArrayBufferSupported(),
sharedArrayBufferEnabled: this.config.useSharedArrayBuffer,
currentMode
};
}
/**
@@ -11800,15 +11805,12 @@ class WebWorkerPool {
this.busyWorkers.clear();
}
}
var __defProp$3 = Object.defineProperty;
var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
var __decorateClass$3 = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result)
__defProp$3(target, key, result);
result = decorator(result) || result;
return result;
};
let Position = class extends Component {
@@ -11890,15 +11892,12 @@ let Lifetime = class extends Component {
Lifetime = __decorateClass$3([
ECSComponent("Lifetime")
], Lifetime);
var __defProp$2 = Object.defineProperty;
var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
var __decorateClass$2 = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result)
__defProp$2(target, key, result);
result = decorator(result) || result;
return result;
};
let PhysicsWorkerSystem = class extends WorkerEntitySystem {
@@ -12004,8 +12003,7 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
const relativeVelocityX = ball2.dx - ball1.dx;
const relativeVelocityY = ball2.dy - ball1.dy;
const velocityAlongNormal = relativeVelocityX * nx + relativeVelocityY * ny;
if (velocityAlongNormal > 0)
continue;
if (velocityAlongNormal > 0) continue;
const restitution = (ball1.bounce + ball2.bounce) * 0.5;
const impulseScalar = -(1 + restitution) * velocityAlongNormal / (1 / ball1.mass + 1 / ball2.mass);
const impulseX = impulseScalar * nx;
@@ -12072,8 +12070,7 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
*/
writeEntityToBuffer(entityData, offset) {
const sharedArray = this.sharedFloatArray;
if (!sharedArray)
return;
if (!sharedArray) return;
const currentEntityCount = Math.floor(offset / 9) + 1;
sharedArray[0] = currentEntityCount;
const dataOffset = offset + 9;
@@ -12099,8 +12096,7 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
*/
readEntityFromBuffer(offset) {
const sharedArray = this.sharedFloatArray;
if (!sharedArray)
return null;
if (!sharedArray) return null;
const dataOffset = offset + 9;
return {
id: sharedArray[dataOffset + 0],
@@ -12129,8 +12125,7 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
for (let i = startIndex; i < endIndex && i < actualEntityCount; i++) {
const offset = i * 9 + 9;
const id = sharedFloatArray[offset + 0];
if (id === 0)
continue;
if (id === 0) continue;
let x = sharedFloatArray[offset + 1];
let y = sharedFloatArray[offset + 2];
let dx = sharedFloatArray[offset + 3];
@@ -12167,8 +12162,7 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
for (let i = startIndex; i < endIndex && i < actualEntityCount; i++) {
const offset1 = i * 9 + 9;
const id1 = sharedFloatArray[offset1 + 0];
if (id1 === 0)
continue;
if (id1 === 0) continue;
let x1 = sharedFloatArray[offset1 + 1];
let y1 = sharedFloatArray[offset1 + 2];
let dx1 = sharedFloatArray[offset1 + 3];
@@ -12177,12 +12171,10 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
const bounce1 = sharedFloatArray[offset1 + 6];
const radius1 = sharedFloatArray[offset1 + 8];
for (let j = 0; j < actualEntityCount; j++) {
if (i === j)
continue;
if (i === j) continue;
const offset2 = j * 9 + 9;
const id2 = sharedFloatArray[offset2 + 0];
if (id2 === 0)
continue;
if (id2 === 0) continue;
const x2 = sharedFloatArray[offset2 + 1];
const y2 = sharedFloatArray[offset2 + 2];
const dx2 = sharedFloatArray[offset2 + 3];
@@ -12190,8 +12182,7 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
const mass2 = sharedFloatArray[offset2 + 5];
const bounce2 = sharedFloatArray[offset2 + 6];
const radius2 = sharedFloatArray[offset2 + 8];
if (isNaN(x2) || isNaN(y2) || isNaN(radius2) || radius2 <= 0)
continue;
if (isNaN(x2) || isNaN(y2) || isNaN(radius2) || radius2 <= 0) continue;
const deltaX = x2 - x1;
const deltaY = y2 - y1;
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
@@ -12207,8 +12198,7 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
const relativeVelocityX = dx2 - dx1;
const relativeVelocityY = dy2 - dy1;
const velocityAlongNormal = relativeVelocityX * nx + relativeVelocityY * ny;
if (velocityAlongNormal > 0)
continue;
if (velocityAlongNormal > 0) continue;
const restitution = (bounce1 + bounce2) * 0.5;
const impulseScalar = -(1 + restitution) * velocityAlongNormal / (1 / mass1 + 1 / mass2);
const impulseX = impulseScalar * nx;
@@ -12231,15 +12221,12 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
PhysicsWorkerSystem = __decorateClass$2([
ECSSystem("PhysicsWorkerSystem")
], PhysicsWorkerSystem);
var __defProp$1 = Object.defineProperty;
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
var __decorateClass$1 = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result)
__defProp$1(target, key, result);
result = decorator(result) || result;
return result;
};
let RenderSystem = class extends EntitySystem {
@@ -12321,15 +12308,12 @@ let RenderSystem = class extends EntitySystem {
RenderSystem = __decorateClass$1([
ECSSystem("RenderSystem")
], RenderSystem);
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result)
__defProp(target, key, result);
result = decorator(result) || result;
return result;
};
let LifetimeSystem = class extends EntitySystem {
@@ -12507,8 +12491,7 @@ class WorkerDemo {
this.lastWorkerStatusUpdate = 0;
this.elements = {};
this.gameLoop = () => {
if (!this.isRunning)
return;
if (!this.isRunning) return;
const currentTime = performance.now();
const deltaTime = (currentTime - this.lastTime) / 1e3;
this.lastTime = currentTime;

View File

@@ -118,7 +118,7 @@
color: #ff4a4a;
}
</style>
<script type="module" crossorigin src="/ecs-framework/demos/worker-system/assets/index-83126548.js"></script>
<script type="module" crossorigin src="/ecs-framework/demos/worker-system/assets/index-DRe9rMYY.js"></script>
</head>
<body>
<div class="container">

View File

@@ -53,7 +53,9 @@
"docs:build": "npm run docs:api && vitepress build docs",
"docs:preview": "vitepress preview docs",
"docs:api": "typedoc",
"docs:api:watch": "typedoc --watch"
"docs:api:watch": "typedoc --watch",
"update:worker-demo": "npm run build:core && cd examples/worker-system-demo && npm run build && cd ../.. && npm run copy:worker-demo",
"copy:worker-demo": "node scripts/update-worker-demo.js"
},
"author": "yhh",
"license": "MIT",

View File

@@ -246,15 +246,25 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
*/
private initializeSharedArrayBuffer(): void {
try {
// 检查是否支持SharedArrayBuffer
if (!this.isSharedArrayBufferSupported()) {
console.warn(`[${this.systemName}] SharedArrayBuffer not supported, falling back to traditional Worker mode`);
this.config.useSharedArrayBuffer = false;
return;
}
// 使用配置的实体数据大小和最大实体数量
// 预分配缓冲区maxEntities * entityDataSize * 4字节
const bufferSize = this.config.maxEntities * this.config.entityDataSize * 4;
this.sharedBuffer = new SharedArrayBuffer(bufferSize);
this.sharedFloatArray = new Float32Array(this.sharedBuffer);
console.log(`[${this.systemName}] SharedArrayBuffer initialized successfully (${bufferSize} bytes)`);
} catch (error) {
console.warn(`[${this.systemName}] SharedArrayBuffer init failed:`, error);
console.warn(`[${this.systemName}] SharedArrayBuffer init failed, falling back to traditional Worker mode:`, error);
this.config.useSharedArrayBuffer = false;
this.sharedBuffer = null;
this.sharedFloatArray = null;
}
}
@@ -377,23 +387,31 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
try {
if (this.config.enableWorker && this.workerPool) {
if (this.config.useSharedArrayBuffer && this.sharedFloatArray) {
// 检查SharedArrayBuffer是否真正可用
if (this.config.useSharedArrayBuffer && this.sharedFloatArray && this.isSharedArrayBufferSupported()) {
// 使用SharedArrayBuffer优化的异步处理
this.processWithSharedArrayBuffer(entities).finally(() => {
this.isProcessing = false;
});
} else {
// 如果配置了SharedArrayBuffer但不可用记录降级信息
if (this.config.useSharedArrayBuffer) {
console.log(`[${this.systemName}] Falling back to traditional Worker mode for this frame`);
}
// 传统Worker异步处理
this.processWithWorker(entities).finally(() => {
this.isProcessing = false;
});
}
} else {
// 同步处理最后的fallback
console.log(`[${this.systemName}] Worker not available, processing synchronously`);
this.processSynchronously(entities);
this.isProcessing = false;
}
} catch (error) {
this.isProcessing = false;
console.error(`[${this.systemName}] Processing failed:`, error);
throw error;
}
}
@@ -636,11 +654,27 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
enabled: boolean;
workerCount: number;
isProcessing: boolean;
sharedArrayBufferSupported: boolean;
sharedArrayBufferEnabled: boolean;
currentMode: 'shared-buffer' | 'worker' | 'sync';
} {
let currentMode: 'shared-buffer' | 'worker' | 'sync' = 'sync';
if (this.config.enableWorker && this.workerPool) {
if (this.config.useSharedArrayBuffer && this.sharedFloatArray && this.isSharedArrayBufferSupported()) {
currentMode = 'shared-buffer';
} else {
currentMode = 'worker';
}
}
return {
enabled: this.config.enableWorker,
workerCount: this.config.workerCount,
isProcessing: this.isProcessing
isProcessing: this.isProcessing,
sharedArrayBufferSupported: this.isSharedArrayBufferSupported(),
sharedArrayBufferEnabled: this.config.useSharedArrayBuffer,
currentMode
};
}

View File

@@ -0,0 +1,73 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const DEMO_DIST_DIR = 'examples/worker-system-demo/dist';
const VITEPRESS_DEMO_DIR = 'docs/public/demos/worker-system';
function updateWorkerDemo() {
console.log('🔄 更新 Worker System Demo 资源...');
try {
// 1. 清理旧的 JS 文件
const assetsDir = path.join(VITEPRESS_DEMO_DIR, 'assets');
if (fs.existsSync(assetsDir)) {
const files = fs.readdirSync(assetsDir);
const jsFiles = files.filter(file => file.startsWith('index-') && file.endsWith('.js'));
for (const jsFile of jsFiles) {
const filePath = path.join(assetsDir, jsFile);
fs.unlinkSync(filePath);
console.log(`🗑️ 删除旧文件: ${jsFile}`);
}
}
// 2. 复制新的资源文件
const sourceAssetsDir = path.join(DEMO_DIST_DIR, 'assets');
if (!fs.existsSync(sourceAssetsDir)) {
throw new Error(`源目录不存在: ${sourceAssetsDir}`);
}
// 确保目标目录存在
if (!fs.existsSync(assetsDir)) {
fs.mkdirSync(assetsDir, { recursive: true });
}
const sourceFiles = fs.readdirSync(sourceAssetsDir);
const newJsFile = sourceFiles.find(file => file.startsWith('index-') && file.endsWith('.js'));
if (!newJsFile) {
throw new Error('未找到新的 JS 文件');
}
// 复制新的 JS 文件
const sourcePath = path.join(sourceAssetsDir, newJsFile);
const targetPath = path.join(assetsDir, newJsFile);
fs.copyFileSync(sourcePath, targetPath);
console.log(`📁 复制新文件: ${newJsFile}`);
// 3. 更新 index.html 中的引用
const indexHtmlPath = path.join(VITEPRESS_DEMO_DIR, 'index.html');
if (fs.existsSync(indexHtmlPath)) {
let content = fs.readFileSync(indexHtmlPath, 'utf-8');
// 更新 script 标签中的文件名
const scriptRegex = /src="\/ecs-framework\/demos\/worker-system\/assets\/index-[^"]+\.js"/;
const newScriptSrc = `/ecs-framework/demos/worker-system/assets/${newJsFile}`;
content = content.replace(scriptRegex, `src="${newScriptSrc}"`);
fs.writeFileSync(indexHtmlPath, content);
console.log(`📝 更新 index.html 引用: ${newJsFile}`);
}
console.log('✅ Worker System Demo 资源更新完成!');
console.log('💡 提示:运行 npm run docs:build 来重新构建文档');
} catch (error) {
console.error('❌ 更新失败:', error.message);
process.exit(1);
}
}
updateWorkerDemo();