@awesome-ecs/workers
Version:
The Workers package for Awesome ECS. Provides basic implementation for the Worker communication using ECS.
261 lines (210 loc) • 7.46 kB
Markdown
# Awesome ECS (Entity-Component-System)
## Workers Package
The Workers package extends the Awesome ECS framework with multithreaded processing capabilities using Web Workers or Node.js Worker Threads. It enables distributing computational workloads across multiple threads while maintaining the ECS architecture.
## Real-World Usage Patterns
Based on the analysis of real-world usage in project-anchor, here are the key implementation patterns for the Workers package:
### Worker Thread Integration
- **Worker-Specific Components**: Special components manage worker state and communication
```typescript
// In worker-thread.ts module
export class WorkerThreadEntity extends EntityBase<WorkerModel> {
get status(): TasksComponent {
return this.getComponent(ComponentType.tasks);
}
}
```
- **Thread Task Scheduling**: Systems coordinate task distribution across worker threads
```typescript
// Inside a system middleware
action(context: ISystemContext<WorkerThreadEntity>): void {
const entity = context.entity;
const tasks = entity.tasks;
// Assign tasks to worker threads
if (tasks.queue.length < tasks.maxQueueSize) {
tasks.queue.push(this.getNextTask());
}
}
```
- **Message Passing**: Structured communication between main thread and worker threads
```typescript
// Inside worker communication system
const message = {
type: 'TASK_COMPLETE',
data: result,
taskId: task.id
};
worker.postMessage(message);
```
### Task Management
- **Task Queuing**: Tasks are queued and processed by worker threads
```typescript
// In a terrain generation system
const task = {
id: generateUid(),
type: 'GENERATE_TERRAIN',
data: {
seed: this.seed,
resolution: this.resolution,
chunks: pendingChunks
}
};
workerEntity.tasks.queue.push(task);
```
- **Result Handling**: Systems process results from worker threads
```typescript
// Inside result handling system
handleWorkerMessage(message: WorkerMessage) {
if (message.type === 'TASK_COMPLETE') {
const { taskId, data } = message;
// Find the entity waiting for this task result
const entity = this.findEntityByTaskId(taskId);
// Update entity with worker result
if (entity) {
this.updateEntityWithResult(entity, data);
}
}
}
```
### Integration with ECS
- **Worker System Modules**: Dedicated system modules manage worker threads
```typescript
export class WorkerThreadSystemsModule extends LocalSystemsModuleBase<WorkerThreadEntity> {
constructor(
private workerInitSystem: WorkerInitSystem,
private workerMessageSystem: WorkerMessageSystem,
private workerTaskSystem: WorkerTaskSystem
) {
super();
this.registerSystems(SystemPipelineType.initialize, [
workerInitSystem
]);
this.registerSystems(SystemPipelineType.update, [
workerMessageSystem,
workerTaskSystem
]);
}
}
```
- **CPU-Intensive Operations**: Workers handle computationally expensive tasks
```typescript
// Examples of operations offloaded to workers:
// - Terrain generation
// - Pathfinding calculations
// - Physics simulations
// - AI processing
```
### Overview
The Workers implementation provides:
- Thread-based parallel processing for CPU-intensive tasks
- Message-based communication between the main thread and worker threads
- Health monitoring and worker lifecycle management
- Queue-based work distribution system
### Package Structure
- **abstract/**: Core interfaces and types for worker operations
- `worker-message.ts`: Defines message formats for worker communication
- `worker-queue.ts`: Queue implementation for worker messages
- `worker-instance.ts`: Defines worker instance structure
- `worker-health.ts`: Health monitoring interfaces
- `worker-factory.ts`: Factory for creating worker instances
- `worker-system-context.ts`: System context for worker operations
- `types/`: Type definitions for worker components
- `events/`: Event definitions for worker communication
- **components/**: Worker-specific components
- Components for managing worker state and communication
- **systems/**: Systems for handling worker operations
- `middlewares/`: Middleware implementations for worker systems
- Systems for worker lifecycle management
- **runtime/**: Worker runtime implementation
- Runtime environment for workers
- **entities/**: Worker-specific entities
- Entity implementations for workers
- **helpers/**: Utility functions for worker operations
- Helper functions for common worker tasks
## Real-World Example
### Using Workers for Terrain Generation
```typescript
// Main thread: Setting up worker system
class TerrainGenerationSystem implements ISystemMiddleware<TerrainEntity> {
action(context: ISystemContext<TerrainEntity>): void {
const terrain = context.entity;
// Create task for terrain generation
const task = {
id: generateUid(),
type: 'GENERATE_TERRAIN',
data: {
seed: terrain.seed.value,
size: terrain.area.size,
resolution: terrain.area.resolution
}
};
// Send task to worker
this.workerManager.assignTask(task, (result) => {
// Process result when task is complete
this.applyTerrainData(terrain, result.heightmapData);
});
}
}
// Worker thread: Processing terrain generation
self.addEventListener('message', (event) => {
const { id, type, data } = event.data;
if (type === 'GENERATE_TERRAIN') {
// Generate terrain data using the provided parameters
const terrainData = generateTerrain(data.seed, data.size, data.resolution);
// Send result back to main thread
self.postMessage({
type: 'TASK_COMPLETE',
taskId: id,
data: {
heightmapData: terrainData
}
});
}
});
```
### Worker Lifecycle Management
```typescript
// Worker manager module
@autoinject
export class WorkerManager {
private workers: Map<string, WorkerEntity> = new Map();
constructor(private entityManager: EntityManager) {}
initialize(numWorkers: number) {
// Create worker entities
for (let i = 0; i < numWorkers; i++) {
const workerId = `worker-${i}`;
// Create worker entity
const workerEntity = this.entityManager.createEntity({
entityType: EntityType.worker,
entityUid: workerId,
model: {
uid: workerId,
workerType: 'general'
}
});
this.workers.set(workerId, workerEntity);
}
}
assignTask(task: WorkerTask, callback: (result: any) => void) {
// Find available worker
const availableWorker = this.findAvailableWorker();
if (availableWorker) {
// Register callback for when task completes
this.taskCallbacks.set(task.id, callback);
// Assign task to worker
availableWorker.tasks.queue.push(task);
availableWorker.tasks.status = 'busy';
} else {
// Queue task for later assignment
this.pendingTasks.push({
task,
callback
});
}
}
}
```
### Integration with Other Packages
The Workers package is designed to integrate with:
- `@awesome-ecs/core`: Core ECS functionality
- `@awesome-ecs/ai`: AI behavior implementations that can be offloaded to worker threads