feat(simulation): background worker pool infrastructure (#843 Part C)
Generic BackgroundWorkerPool<Req, Resp> with crossbeam channels, closure handlers, and 3 delivery strategies (Fallback, GracefulDegrade, ModalLock). Stub workers registered as Bevy resources: - ChunkGenWorker (2 threads) — terrain/props/navmesh generation - NpcPrepWorker (1 thread) — pre-compute NPC state for incoming areas - OffscreenTickWorker (1 thread) — advance NPCs outside active tier Tick loop integration: - PreInput: poll_worker_results drains completed work - PostSnapshot: push_worker_requests queues new work (no-op until Phase 5) Handlers are stubs — real computation plugs in when the phases that need them arrive. The infrastructure (channels, threads, push/poll, shutdown) is real and tested. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
//! Stub worker resources (#843 Part C).
|
||||
//!
|
||||
//! Each worker type is a Bevy Resource wrapping a typed `BackgroundWorkerPool`.
|
||||
//! The actual computation logic is a no-op placeholder — implementations
|
||||
//! plug in when the phases that need them arrive (Phase 5+).
|
||||
//!
|
||||
//! The infrastructure (channels, threads, push/poll) is real and tested.
|
||||
|
||||
use bevy_ecs::prelude::*;
|
||||
|
||||
use super::pool::{BackgroundWorkerPool, DeliveryStrategy, WorkRequest};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ChunkGen — terrain, buildings, props, navmesh for a world chunk
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Request to generate a chunk at the given coordinates.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ChunkGenRequest {
|
||||
pub chunk_x: i32,
|
||||
pub chunk_y: i32,
|
||||
pub chunk_z: i32,
|
||||
pub world_seed: u64,
|
||||
}
|
||||
|
||||
/// Generated chunk data (placeholder — real struct will hold terrain, props, navmesh).
|
||||
#[derive(Debug)]
|
||||
pub struct ChunkGenResult {
|
||||
pub chunk_x: i32,
|
||||
pub chunk_y: i32,
|
||||
pub chunk_z: i32,
|
||||
/// Placeholder: real result holds terrain heightfield, building list, prop list, navmesh.
|
||||
pub generated: bool,
|
||||
}
|
||||
|
||||
/// Bevy resource for the chunk generation worker pool.
|
||||
#[derive(Resource)]
|
||||
pub struct ChunkGenWorker {
|
||||
pub pool: BackgroundWorkerPool<ChunkGenRequest, ChunkGenResult>,
|
||||
}
|
||||
|
||||
impl ChunkGenWorker {
|
||||
pub fn new(thread_count: usize) -> Self {
|
||||
Self {
|
||||
pool: BackgroundWorkerPool::spawn(thread_count, |req: ChunkGenRequest| {
|
||||
// Stub: real implementation generates terrain from seed + coordinates
|
||||
ChunkGenResult {
|
||||
chunk_x: req.chunk_x,
|
||||
chunk_y: req.chunk_y,
|
||||
chunk_z: req.chunk_z,
|
||||
generated: true,
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn submit(&self, req: ChunkGenRequest, strategy: DeliveryStrategy) {
|
||||
self.pool
|
||||
.submit(WorkRequest { payload: req, strategy });
|
||||
}
|
||||
|
||||
pub fn drain(&self) -> Vec<(ChunkGenResult, DeliveryStrategy)> {
|
||||
self.pool.drain()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// NpcPrep — pre-compute NPC state for areas about to become visible
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Request to prepare NPCs for an area.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NpcPrepRequest {
|
||||
pub area_id: String,
|
||||
pub world_seed: u64,
|
||||
}
|
||||
|
||||
/// Prepared NPC state (placeholder).
|
||||
#[derive(Debug)]
|
||||
pub struct NpcPrepResult {
|
||||
pub area_id: String,
|
||||
pub npc_count: usize,
|
||||
}
|
||||
|
||||
/// Bevy resource for the NPC preparation worker pool.
|
||||
#[derive(Resource)]
|
||||
pub struct NpcPrepWorker {
|
||||
pub pool: BackgroundWorkerPool<NpcPrepRequest, NpcPrepResult>,
|
||||
}
|
||||
|
||||
impl NpcPrepWorker {
|
||||
pub fn new(thread_count: usize) -> Self {
|
||||
Self {
|
||||
pool: BackgroundWorkerPool::spawn(thread_count, |req: NpcPrepRequest| {
|
||||
// Stub: real implementation pre-generates NPC appearance, inventory, mood
|
||||
NpcPrepResult {
|
||||
area_id: req.area_id,
|
||||
npc_count: 0,
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// OffscreenTick — advance NPC state for entities outside the active tier
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Request to advance off-screen NPCs by a specific number of ticks.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OffscreenTickRequest {
|
||||
pub area_id: String,
|
||||
/// Exact number of simulation ticks to advance. Deterministic.
|
||||
pub ticks_to_advance: u64,
|
||||
pub world_seed: u64,
|
||||
}
|
||||
|
||||
/// Updated NPC state after off-screen ticking (placeholder).
|
||||
#[derive(Debug)]
|
||||
pub struct OffscreenTickResult {
|
||||
pub area_id: String,
|
||||
pub ticks_advanced: u64,
|
||||
}
|
||||
|
||||
/// Bevy resource for the off-screen tick worker pool.
|
||||
#[derive(Resource)]
|
||||
pub struct OffscreenTickWorker {
|
||||
pub pool: BackgroundWorkerPool<OffscreenTickRequest, OffscreenTickResult>,
|
||||
}
|
||||
|
||||
impl OffscreenTickWorker {
|
||||
pub fn new(thread_count: usize) -> Self {
|
||||
Self {
|
||||
pool: BackgroundWorkerPool::spawn(thread_count, |req: OffscreenTickRequest| {
|
||||
// Stub: real implementation snapshots NPC state, advances N ticks
|
||||
OffscreenTickResult {
|
||||
area_id: req.area_id,
|
||||
ticks_advanced: req.ticks_to_advance,
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user