新增禁用sab功能
This commit is contained in:
15
.github/workflows/docs.yml
vendored
15
.github/workflows/docs.yml
vendored
@@ -50,6 +50,21 @@ jobs:
|
|||||||
- name: Build documentation
|
- name: Build documentation
|
||||||
run: npm run docs:build
|
run: npm run docs:build
|
||||||
|
|
||||||
|
- name: Add COOP/COEP headers for SharedArrayBuffer support
|
||||||
|
run: |
|
||||||
|
# Create _headers file for Netlify compatibility
|
||||||
|
echo "/*" > docs/.vitepress/dist/_headers
|
||||||
|
echo " Cross-Origin-Embedder-Policy: require-corp" >> docs/.vitepress/dist/_headers
|
||||||
|
echo " Cross-Origin-Opener-Policy: same-origin" >> docs/.vitepress/dist/_headers
|
||||||
|
|
||||||
|
# Create .htaccess file for Apache compatibility (GitHub Pages sometimes uses this)
|
||||||
|
echo "Header always set Cross-Origin-Embedder-Policy require-corp" > docs/.vitepress/dist/.htaccess
|
||||||
|
echo "Header always set Cross-Origin-Opener-Policy same-origin" >> docs/.vitepress/dist/.htaccess
|
||||||
|
|
||||||
|
# Create a meta tag fallback in a headers.html file that can be included
|
||||||
|
echo '<meta http-equiv="Cross-Origin-Embedder-Policy" content="require-corp">' > docs/.vitepress/dist/headers.html
|
||||||
|
echo '<meta http-equiv="Cross-Origin-Opener-Policy" content="same-origin">' >> docs/.vitepress/dist/headers.html
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-pages-artifact@v3
|
uses: actions/upload-pages-artifact@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -11370,8 +11370,9 @@ class WorkerEntitySystem extends EntitySystem {
|
|||||||
initializeSharedArrayBuffer() {
|
initializeSharedArrayBuffer() {
|
||||||
try {
|
try {
|
||||||
if (!this.isSharedArrayBufferSupported()) {
|
if (!this.isSharedArrayBufferSupported()) {
|
||||||
console.warn(`[${this.systemName}] SharedArrayBuffer not supported, falling back to traditional Worker mode`);
|
console.warn(`[${this.systemName}] SharedArrayBuffer not supported, falling back to single Worker mode for collision detection integrity`);
|
||||||
this.config.useSharedArrayBuffer = false;
|
this.config.useSharedArrayBuffer = false;
|
||||||
|
this.config.workerCount = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const bufferSize = this.config.maxEntities * this.config.entityDataSize * 4;
|
const bufferSize = this.config.maxEntities * this.config.entityDataSize * 4;
|
||||||
@@ -11379,10 +11380,11 @@ class WorkerEntitySystem extends EntitySystem {
|
|||||||
this.sharedFloatArray = new Float32Array(this.sharedBuffer);
|
this.sharedFloatArray = new Float32Array(this.sharedBuffer);
|
||||||
console.log(`[${this.systemName}] SharedArrayBuffer initialized successfully (${bufferSize} bytes)`);
|
console.log(`[${this.systemName}] SharedArrayBuffer initialized successfully (${bufferSize} bytes)`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(`[${this.systemName}] SharedArrayBuffer init failed, falling back to traditional Worker mode:`, error);
|
console.warn(`[${this.systemName}] SharedArrayBuffer init failed, falling back to single Worker mode for collision detection integrity:`, error);
|
||||||
this.config.useSharedArrayBuffer = false;
|
this.config.useSharedArrayBuffer = false;
|
||||||
this.sharedBuffer = null;
|
this.sharedBuffer = null;
|
||||||
this.sharedFloatArray = null;
|
this.sharedFloatArray = null;
|
||||||
|
this.config.workerCount = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -11912,11 +11914,11 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
|
|||||||
Matcher.empty().all(Position, Velocity, Physics),
|
Matcher.empty().all(Position, Velocity, Physics),
|
||||||
{
|
{
|
||||||
enableWorker,
|
enableWorker,
|
||||||
workerCount: navigator.hardwareConcurrency || 2,
|
// 当 SharedArrayBuffer 可用时使用多 Worker,否则使用单 Worker 保证碰撞检测完整性
|
||||||
// 恢复多Worker
|
workerCount: this.isSharedArrayBufferAvailable() ? navigator.hardwareConcurrency || 2 : 1,
|
||||||
systemConfig: defaultConfig,
|
systemConfig: defaultConfig,
|
||||||
useSharedArrayBuffer: true
|
useSharedArrayBuffer: true
|
||||||
// 使用SharedArrayBuffer进行全局碰撞检测
|
// 优先使用 SharedArrayBuffer
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.physicsConfig = {
|
this.physicsConfig = {
|
||||||
@@ -11928,6 +11930,12 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
|
|||||||
};
|
};
|
||||||
this.startTime = 0;
|
this.startTime = 0;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 检查 SharedArrayBuffer 是否可用
|
||||||
|
*/
|
||||||
|
isSharedArrayBufferAvailable() {
|
||||||
|
return typeof SharedArrayBuffer !== "undefined" && self.crossOriginIsolated;
|
||||||
|
}
|
||||||
extractEntityData(entity) {
|
extractEntityData(entity) {
|
||||||
const position = entity.getComponent(Position);
|
const position = entity.getComponent(Position);
|
||||||
const velocity = entity.getComponent(Velocity);
|
const velocity = entity.getComponent(Velocity);
|
||||||
@@ -12050,6 +12058,45 @@ let PhysicsWorkerSystem = class extends WorkerEntitySystem {
|
|||||||
getPhysicsConfig() {
|
getPhysicsConfig() {
|
||||||
return { ...this.physicsConfig };
|
return { ...this.physicsConfig };
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 强制禁用 SharedArrayBuffer(用于测试降级行为)
|
||||||
|
*/
|
||||||
|
forceDisableSharedArrayBuffer() {
|
||||||
|
console.log(`[${this.systemName}] Manually disabling SharedArrayBuffer for testing`);
|
||||||
|
this.config.useSharedArrayBuffer = false;
|
||||||
|
this.config.workerCount = 1;
|
||||||
|
this.sharedBuffer = null;
|
||||||
|
this.sharedFloatArray = null;
|
||||||
|
if (this.workerPool) {
|
||||||
|
this.workerPool.destroy();
|
||||||
|
this.workerPool = null;
|
||||||
|
}
|
||||||
|
if (this.config.enableWorker) {
|
||||||
|
this.initializeWorkerPool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取当前运行状态
|
||||||
|
*/
|
||||||
|
getCurrentStatus() {
|
||||||
|
const workerInfo = this.getWorkerInfo();
|
||||||
|
let mode = "sync";
|
||||||
|
if (workerInfo.enabled) {
|
||||||
|
if (workerInfo.sharedArrayBufferEnabled && workerInfo.sharedArrayBufferSupported) {
|
||||||
|
mode = "shared-buffer";
|
||||||
|
} else if (workerInfo.workerCount === 1) {
|
||||||
|
mode = "single-worker";
|
||||||
|
} else {
|
||||||
|
mode = "multi-worker";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
mode,
|
||||||
|
sharedArrayBufferEnabled: workerInfo.sharedArrayBufferEnabled,
|
||||||
|
workerCount: workerInfo.workerCount,
|
||||||
|
workerEnabled: workerInfo.enabled
|
||||||
|
};
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 性能监控
|
* 性能监控
|
||||||
*/
|
*/
|
||||||
@@ -12470,6 +12517,18 @@ class GameScene extends Scene {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 切换 SharedArrayBuffer 状态
|
||||||
|
*/
|
||||||
|
toggleSharedArrayBuffer() {
|
||||||
|
this.physicsSystem.forceDisableSharedArrayBuffer();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取物理系统状态
|
||||||
|
*/
|
||||||
|
getPhysicsSystemStatus() {
|
||||||
|
return this.physicsSystem.getCurrentStatus();
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 获取系统信息
|
* 获取系统信息
|
||||||
*/
|
*/
|
||||||
@@ -12533,6 +12592,7 @@ class WorkerDemo {
|
|||||||
"entityCount",
|
"entityCount",
|
||||||
"entityCountValue",
|
"entityCountValue",
|
||||||
"toggleWorker",
|
"toggleWorker",
|
||||||
|
"toggleSAB",
|
||||||
"gravity",
|
"gravity",
|
||||||
"gravityValue",
|
"gravityValue",
|
||||||
"friction",
|
"friction",
|
||||||
@@ -12547,7 +12607,8 @@ class WorkerDemo {
|
|||||||
"physicsTime",
|
"physicsTime",
|
||||||
"renderTime",
|
"renderTime",
|
||||||
"frameTime",
|
"frameTime",
|
||||||
"memoryUsage"
|
"memoryUsage",
|
||||||
|
"sabStatus"
|
||||||
];
|
];
|
||||||
for (const id of elementIds) {
|
for (const id of elementIds) {
|
||||||
const element = document.getElementById(id);
|
const element = document.getElementById(id);
|
||||||
@@ -12576,6 +12637,12 @@ class WorkerDemo {
|
|||||||
this.updateWorkerStatus();
|
this.updateWorkerStatus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (this.elements.toggleSAB) {
|
||||||
|
this.elements.toggleSAB.addEventListener("click", () => {
|
||||||
|
this.gameScene.toggleSharedArrayBuffer();
|
||||||
|
this.updateWorkerStatus();
|
||||||
|
});
|
||||||
|
}
|
||||||
if (this.elements.gravity && this.elements.gravityValue) {
|
if (this.elements.gravity && this.elements.gravityValue) {
|
||||||
const slider = this.elements.gravity;
|
const slider = this.elements.gravity;
|
||||||
slider.addEventListener("input", () => {
|
slider.addEventListener("input", () => {
|
||||||
@@ -12664,6 +12731,7 @@ class WorkerDemo {
|
|||||||
const systemInfo = this.gameScene.getSystemInfo();
|
const systemInfo = this.gameScene.getSystemInfo();
|
||||||
const workerInfo = systemInfo.physics;
|
const workerInfo = systemInfo.physics;
|
||||||
const entityCount = systemInfo.entityCount;
|
const entityCount = systemInfo.entityCount;
|
||||||
|
const status = this.gameScene.getPhysicsSystemStatus();
|
||||||
if (this.elements.workerStatus) {
|
if (this.elements.workerStatus) {
|
||||||
if (workerInfo.enabled) {
|
if (workerInfo.enabled) {
|
||||||
this.elements.workerStatus.textContent = `启用 (${workerInfo.workerCount} Workers)`;
|
this.elements.workerStatus.textContent = `启用 (${workerInfo.workerCount} Workers)`;
|
||||||
@@ -12681,6 +12749,24 @@ class WorkerDemo {
|
|||||||
this.elements.workerLoad.textContent = "N/A";
|
this.elements.workerLoad.textContent = "N/A";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.elements.sabStatus) {
|
||||||
|
const modeNames = {
|
||||||
|
"shared-buffer": "SharedArrayBuffer模式",
|
||||||
|
"single-worker": "单Worker模式",
|
||||||
|
"multi-worker": "多Worker模式",
|
||||||
|
"sync": "同步模式"
|
||||||
|
};
|
||||||
|
this.elements.sabStatus.textContent = modeNames[status.mode] || status.mode;
|
||||||
|
this.elements.sabStatus.className = status.mode === "shared-buffer" ? "worker-enabled" : "worker-disabled";
|
||||||
|
}
|
||||||
|
if (this.elements.toggleSAB) {
|
||||||
|
if (status.sharedArrayBufferEnabled) {
|
||||||
|
this.elements.toggleSAB.textContent = "禁用 SharedArrayBuffer";
|
||||||
|
} else {
|
||||||
|
this.elements.toggleSAB.textContent = "启用 SharedArrayBuffer";
|
||||||
|
this.elements.toggleSAB.setAttribute("disabled", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
getMemoryUsage() {
|
getMemoryUsage() {
|
||||||
if ("memory" in performance) {
|
if ("memory" in performance) {
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
color: #ff4a4a;
|
color: #ff4a4a;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script type="module" crossorigin src="/ecs-framework/demos/worker-system/assets/index-DRe9rMYY.js"></script>
|
<script type="module" crossorigin src="/ecs-framework/demos/worker-system/assets/index-DeXakP9I.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -171,6 +171,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Register Service Worker for SharedArrayBuffer support on GitHub Pages
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.register('/ecs-framework/sw.js')
|
||||||
|
.then((registration) => {
|
||||||
|
console.log('Service Worker registered for SharedArrayBuffer support:', registration);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log('Service Worker registration failed:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
39
docs/public/sw.js
Normal file
39
docs/public/sw.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Service Worker to add COOP/COEP headers for SharedArrayBuffer support
|
||||||
|
// This is a workaround for GitHub Pages which doesn't support custom headers
|
||||||
|
|
||||||
|
self.addEventListener('fetch', (event) => {
|
||||||
|
// Only handle requests for this origin
|
||||||
|
if (!event.request.url.startsWith(self.location.origin)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.respondWith(
|
||||||
|
fetch(event.request).then((response) => {
|
||||||
|
// Clone the response to modify headers
|
||||||
|
const newResponse = new Response(response.body, {
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
headers: {
|
||||||
|
...Object.fromEntries(response.headers.entries()),
|
||||||
|
'Cross-Origin-Embedder-Policy': 'require-corp',
|
||||||
|
'Cross-Origin-Opener-Policy': 'same-origin'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return newResponse;
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('Service Worker fetch failed:', error);
|
||||||
|
return fetch(event.request);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('install', (event) => {
|
||||||
|
console.log('Service Worker: Installing for SharedArrayBuffer support');
|
||||||
|
self.skipWaiting();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', (event) => {
|
||||||
|
console.log('Service Worker: Activated for SharedArrayBuffer support');
|
||||||
|
event.waitUntil(self.clients.claim());
|
||||||
|
});
|
||||||
@@ -138,6 +138,7 @@
|
|||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<label>Worker 设置:</label>
|
<label>Worker 设置:</label>
|
||||||
<button id="toggleWorker">禁用 Worker</button>
|
<button id="toggleWorker">禁用 Worker</button>
|
||||||
|
<button id="toggleSAB">禁用 SharedArrayBuffer</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
@@ -163,6 +164,7 @@
|
|||||||
<div class="stat-line">实体数量: <span id="entityCountStat">0</span></div>
|
<div class="stat-line">实体数量: <span id="entityCountStat">0</span></div>
|
||||||
<div class="stat-line">Worker状态: <span id="workerStatus" class="worker-disabled">未启用</span></div>
|
<div class="stat-line">Worker状态: <span id="workerStatus" class="worker-disabled">未启用</span></div>
|
||||||
<div class="stat-line">Worker负载: <span id="workerLoad">N/A</span></div>
|
<div class="stat-line">Worker负载: <span id="workerLoad">N/A</span></div>
|
||||||
|
<div class="stat-line">运行模式: <span id="sabStatus" class="worker-disabled">同步模式</span></div>
|
||||||
<div class="stat-line">物理系统耗时: <span id="physicsTime">0</span>ms</div>
|
<div class="stat-line">物理系统耗时: <span id="physicsTime">0</span>ms</div>
|
||||||
<div class="stat-line">渲染系统耗时: <span id="renderTime">0</span>ms</div>
|
<div class="stat-line">渲染系统耗时: <span id="renderTime">0</span>ms</div>
|
||||||
<div class="stat-line">总帧时间: <span id="frameTime">0</span>ms</div>
|
<div class="stat-line">总帧时间: <span id="frameTime">0</span>ms</div>
|
||||||
|
|||||||
@@ -160,6 +160,20 @@ export class GameScene extends Scene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换 SharedArrayBuffer 状态
|
||||||
|
*/
|
||||||
|
public toggleSharedArrayBuffer(): void {
|
||||||
|
this.physicsSystem.disableSharedArrayBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取物理系统状态
|
||||||
|
*/
|
||||||
|
public getPhysicsSystemStatus() {
|
||||||
|
return this.physicsSystem.getCurrentStatus();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取系统信息
|
* 获取系统信息
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -54,10 +54,10 @@ class WorkerDemo {
|
|||||||
|
|
||||||
private initializeUIElements(): void {
|
private initializeUIElements(): void {
|
||||||
const elementIds = [
|
const elementIds = [
|
||||||
'entityCount', 'entityCountValue', 'toggleWorker',
|
'entityCount', 'entityCountValue', 'toggleWorker', 'toggleSAB',
|
||||||
'gravity', 'gravityValue', 'friction', 'frictionValue', 'spawnParticles',
|
'gravity', 'gravityValue', 'friction', 'frictionValue', 'spawnParticles',
|
||||||
'clearEntities', 'resetDemo', 'fps', 'entityCountStat', 'workerStatus', 'workerLoad',
|
'clearEntities', 'resetDemo', 'fps', 'entityCountStat', 'workerStatus', 'workerLoad',
|
||||||
'physicsTime', 'renderTime', 'frameTime', 'memoryUsage'
|
'physicsTime', 'renderTime', 'frameTime', 'memoryUsage', 'sabStatus'
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const id of elementIds) {
|
for (const id of elementIds) {
|
||||||
@@ -93,6 +93,14 @@ class WorkerDemo {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SharedArrayBuffer切换按钮
|
||||||
|
if (this.elements.toggleSAB) {
|
||||||
|
this.elements.toggleSAB.addEventListener('click', () => {
|
||||||
|
this.gameScene.toggleSharedArrayBuffer();
|
||||||
|
this.updateWorkerStatus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 重力滑块
|
// 重力滑块
|
||||||
if (this.elements.gravity && this.elements.gravityValue) {
|
if (this.elements.gravity && this.elements.gravityValue) {
|
||||||
@@ -249,6 +257,7 @@ class WorkerDemo {
|
|||||||
const systemInfo = this.gameScene.getSystemInfo();
|
const systemInfo = this.gameScene.getSystemInfo();
|
||||||
const workerInfo = systemInfo.physics;
|
const workerInfo = systemInfo.physics;
|
||||||
const entityCount = systemInfo.entityCount;
|
const entityCount = systemInfo.entityCount;
|
||||||
|
const status = this.gameScene.getPhysicsSystemStatus();
|
||||||
|
|
||||||
if (this.elements.workerStatus) {
|
if (this.elements.workerStatus) {
|
||||||
if (workerInfo.enabled) {
|
if (workerInfo.enabled) {
|
||||||
@@ -268,6 +277,29 @@ class WorkerDemo {
|
|||||||
this.elements.workerLoad.textContent = 'N/A';
|
this.elements.workerLoad.textContent = 'N/A';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新 SharedArrayBuffer 状态
|
||||||
|
if (this.elements.sabStatus) {
|
||||||
|
const modeNames = {
|
||||||
|
'shared-buffer': 'SharedArrayBuffer模式',
|
||||||
|
'single-worker': '单Worker模式',
|
||||||
|
'multi-worker': '多Worker模式',
|
||||||
|
'sync': '同步模式'
|
||||||
|
};
|
||||||
|
|
||||||
|
this.elements.sabStatus.textContent = modeNames[status.mode] || status.mode;
|
||||||
|
this.elements.sabStatus.className = status.mode === 'shared-buffer' ? 'worker-enabled' : 'worker-disabled';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新 SharedArrayBuffer 按钮文本
|
||||||
|
if (this.elements.toggleSAB) {
|
||||||
|
if (status.sharedArrayBufferEnabled) {
|
||||||
|
this.elements.toggleSAB.textContent = '禁用 SharedArrayBuffer';
|
||||||
|
} else {
|
||||||
|
this.elements.toggleSAB.textContent = '启用 SharedArrayBuffer';
|
||||||
|
this.elements.toggleSAB.setAttribute('disabled', 'true'); // SAB 一旦禁用就无法重新启用
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMemoryUsage(): number {
|
private getMemoryUsage(): number {
|
||||||
|
|||||||
@@ -37,13 +37,17 @@ export class PhysicsWorkerSystem extends WorkerEntitySystem<PhysicsEntityData> {
|
|||||||
groundFriction: 0.98
|
groundFriction: 0.98
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 检查 SharedArrayBuffer 是否可用
|
||||||
|
const isSharedArrayBufferAvailable = typeof SharedArrayBuffer !== 'undefined' && self.crossOriginIsolated;
|
||||||
|
|
||||||
super(
|
super(
|
||||||
Matcher.empty().all(Position, Velocity, Physics),
|
Matcher.empty().all(Position, Velocity, Physics),
|
||||||
{
|
{
|
||||||
enableWorker,
|
enableWorker,
|
||||||
workerCount: navigator.hardwareConcurrency || 2, // 恢复多Worker
|
// 当 SharedArrayBuffer 可用时使用多 Worker,否则使用单 Worker 保证碰撞检测完整性
|
||||||
|
workerCount: isSharedArrayBufferAvailable ? (navigator.hardwareConcurrency || 2) : 1,
|
||||||
systemConfig: defaultConfig,
|
systemConfig: defaultConfig,
|
||||||
useSharedArrayBuffer: true // 使用SharedArrayBuffer进行全局碰撞检测
|
useSharedArrayBuffer: true // 优先使用 SharedArrayBuffer
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -226,6 +230,49 @@ export class PhysicsWorkerSystem extends WorkerEntitySystem<PhysicsEntityData> {
|
|||||||
return { ...this.physicsConfig };
|
return { ...this.physicsConfig };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用 SharedArrayBuffer(用于测试降级行为)
|
||||||
|
*/
|
||||||
|
public disableSharedArrayBuffer(): void {
|
||||||
|
console.log(`[${this.systemName}] Disabling SharedArrayBuffer for testing - falling back to single Worker mode`);
|
||||||
|
|
||||||
|
// 使用正式的配置更新 API
|
||||||
|
this.updateConfig({
|
||||||
|
useSharedArrayBuffer: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前运行状态
|
||||||
|
*/
|
||||||
|
public getCurrentStatus(): {
|
||||||
|
mode: 'shared-buffer' | 'single-worker' | 'multi-worker' | 'sync';
|
||||||
|
sharedArrayBufferEnabled: boolean;
|
||||||
|
workerCount: number;
|
||||||
|
workerEnabled: boolean;
|
||||||
|
} {
|
||||||
|
const workerInfo = this.getWorkerInfo();
|
||||||
|
|
||||||
|
let mode: 'shared-buffer' | 'single-worker' | 'multi-worker' | 'sync' = 'sync';
|
||||||
|
|
||||||
|
if (workerInfo.enabled) {
|
||||||
|
if (workerInfo.sharedArrayBufferEnabled && workerInfo.sharedArrayBufferSupported) {
|
||||||
|
mode = 'shared-buffer';
|
||||||
|
} else if (workerInfo.workerCount === 1) {
|
||||||
|
mode = 'single-worker';
|
||||||
|
} else {
|
||||||
|
mode = 'multi-worker';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
mode,
|
||||||
|
sharedArrayBufferEnabled: workerInfo.sharedArrayBufferEnabled,
|
||||||
|
workerCount: workerInfo.workerCount,
|
||||||
|
workerEnabled: workerInfo.enabled
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private startTime: number = 0;
|
private startTime: number = 0;
|
||||||
|
|
||||||
|
|
||||||
@@ -329,7 +376,7 @@ export class PhysicsWorkerSystem extends WorkerEntitySystem<PhysicsEntityData> {
|
|||||||
let y = sharedFloatArray[offset + 2];
|
let y = sharedFloatArray[offset + 2];
|
||||||
let dx = sharedFloatArray[offset + 3];
|
let dx = sharedFloatArray[offset + 3];
|
||||||
let dy = sharedFloatArray[offset + 4];
|
let dy = sharedFloatArray[offset + 4];
|
||||||
const mass = sharedFloatArray[offset + 5];
|
// const mass = sharedFloatArray[offset + 5]; // 未使用
|
||||||
const bounce = sharedFloatArray[offset + 6];
|
const bounce = sharedFloatArray[offset + 6];
|
||||||
const friction = sharedFloatArray[offset + 7];
|
const friction = sharedFloatArray[offset + 7];
|
||||||
const radius = sharedFloatArray[offset + 8];
|
const radius = sharedFloatArray[offset + 8];
|
||||||
|
|||||||
@@ -186,8 +186,8 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
protected config: Required<Omit<WorkerSystemConfig, 'systemConfig'>> & { systemConfig?: any };
|
protected config: Required<Omit<WorkerSystemConfig, 'systemConfig'>> & { systemConfig?: any };
|
||||||
private workerPool: WebWorkerPool | null = null;
|
private workerPool: WebWorkerPool | null = null;
|
||||||
private isProcessing = false;
|
private isProcessing = false;
|
||||||
private sharedBuffer: SharedArrayBuffer | null = null;
|
protected sharedBuffer: SharedArrayBuffer | null = null;
|
||||||
private sharedFloatArray: Float32Array | null = null;
|
protected sharedFloatArray: Float32Array | null = null;
|
||||||
|
|
||||||
constructor(matcher?: Matcher, config: WorkerSystemConfig = {}) {
|
constructor(matcher?: Matcher, config: WorkerSystemConfig = {}) {
|
||||||
super(matcher);
|
super(matcher);
|
||||||
@@ -248,8 +248,10 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
try {
|
try {
|
||||||
// 检查是否支持SharedArrayBuffer
|
// 检查是否支持SharedArrayBuffer
|
||||||
if (!this.isSharedArrayBufferSupported()) {
|
if (!this.isSharedArrayBufferSupported()) {
|
||||||
console.warn(`[${this.systemName}] SharedArrayBuffer not supported, falling back to traditional Worker mode`);
|
console.warn(`[${this.systemName}] SharedArrayBuffer not supported, falling back to single Worker mode for collision detection integrity`);
|
||||||
this.config.useSharedArrayBuffer = false;
|
this.config.useSharedArrayBuffer = false;
|
||||||
|
// 降级到单Worker模式:确保所有实体在同一个Worker中处理,维持实体间交互的完整性
|
||||||
|
this.config.workerCount = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,10 +263,11 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
|
|
||||||
console.log(`[${this.systemName}] SharedArrayBuffer initialized successfully (${bufferSize} bytes)`);
|
console.log(`[${this.systemName}] SharedArrayBuffer initialized successfully (${bufferSize} bytes)`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(`[${this.systemName}] SharedArrayBuffer init failed, falling back to traditional Worker mode:`, error);
|
console.warn(`[${this.systemName}] SharedArrayBuffer init failed, falling back to single Worker mode for collision detection integrity:`, error);
|
||||||
this.config.useSharedArrayBuffer = false;
|
this.config.useSharedArrayBuffer = false;
|
||||||
this.sharedBuffer = null;
|
this.sharedBuffer = null;
|
||||||
this.sharedFloatArray = null;
|
this.sharedFloatArray = null;
|
||||||
|
this.config.workerCount = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,8 +636,21 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
* 更新Worker配置
|
* 更新Worker配置
|
||||||
*/
|
*/
|
||||||
public updateConfig(newConfig: Partial<WorkerSystemConfig>): void {
|
public updateConfig(newConfig: Partial<WorkerSystemConfig>): void {
|
||||||
|
const oldConfig = { ...this.config };
|
||||||
Object.assign(this.config, newConfig);
|
Object.assign(this.config, newConfig);
|
||||||
|
|
||||||
|
// 如果 SharedArrayBuffer 设置发生变化,需要重新初始化
|
||||||
|
if (oldConfig.useSharedArrayBuffer !== this.config.useSharedArrayBuffer) {
|
||||||
|
this.reinitializeWorkerSystem();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 Worker 数量发生变化,需要重新创建 Worker 池
|
||||||
|
if (oldConfig.workerCount !== this.config.workerCount) {
|
||||||
|
this.reinitializeWorkerPool();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 如果禁用Worker,清理Worker池
|
// 如果禁用Worker,清理Worker池
|
||||||
if (!this.config.enableWorker && this.workerPool) {
|
if (!this.config.enableWorker && this.workerPool) {
|
||||||
this.workerPool.destroy();
|
this.workerPool.destroy();
|
||||||
@@ -647,6 +663,46 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重新初始化整个 Worker 系统(包括 SharedArrayBuffer)
|
||||||
|
*/
|
||||||
|
private reinitializeWorkerSystem(): void {
|
||||||
|
// 清理现有资源
|
||||||
|
if (this.workerPool) {
|
||||||
|
this.workerPool.destroy();
|
||||||
|
this.workerPool = null;
|
||||||
|
}
|
||||||
|
this.sharedBuffer = null;
|
||||||
|
this.sharedFloatArray = null;
|
||||||
|
|
||||||
|
// 如果禁用 SharedArrayBuffer,降级到单 Worker 模式
|
||||||
|
if (!this.config.useSharedArrayBuffer) {
|
||||||
|
this.config.workerCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新初始化
|
||||||
|
if (this.config.enableWorker && this.isWorkerSupported()) {
|
||||||
|
if (this.config.useSharedArrayBuffer) {
|
||||||
|
this.initializeSharedArrayBuffer();
|
||||||
|
}
|
||||||
|
this.initializeWorkerPool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重新初始化 Worker 池(保持 SharedArrayBuffer)
|
||||||
|
*/
|
||||||
|
private reinitializeWorkerPool(): void {
|
||||||
|
if (this.workerPool) {
|
||||||
|
this.workerPool.destroy();
|
||||||
|
this.workerPool = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.config.enableWorker && this.isWorkerSupported()) {
|
||||||
|
this.initializeWorkerPool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取系统性能信息
|
* 获取系统性能信息
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user