Review fixes from Hoshe + Tyre: - EntityRng seeding: splitmix64(seed) ^ splitmix64(id) instead of splitmix64(seed + id) — eliminates collision class where adjacent seeds produce identical streams - AtomicBool ordering: Relaxed → SeqCst for shutdown flag (correct on weakly-ordered architectures) - Worker Drop: join handles instead of detaching threads - Normalize stub API: remove ChunkGenWorker convenience wrappers, use .pool consistently across all 3 workers - trigger_monologue: downgrade &mut to shared refs (no-op anchor was blocking parallel systems) - Remove dead SimRng inserts from migrated monologue tests - Document determinism gap on poll_worker_results - Document bevy_tasks/rayon dep rationale in Cargo.toml Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
69 lines
2.6 KiB
Rust
69 lines
2.6 KiB
Rust
//! Tick-loop integration systems for background workers (#843 Part C).
|
|
//!
|
|
//! - `poll_worker_results`: runs in PreInput, drains completed results
|
|
//! - `push_worker_requests`: runs in PostSnapshot, queues new work
|
|
//!
|
|
//! Both are no-ops when no results/requests are pending. The worker pools
|
|
//! exist as Bevy Resources — systems access them via `Res<ChunkGenWorker>` etc.
|
|
|
|
use bevy_ecs::prelude::*;
|
|
|
|
use super::stubs::{ChunkGenWorker, NpcPrepWorker, OffscreenTickWorker};
|
|
|
|
/// PreInput: poll all worker pools for completed results.
|
|
///
|
|
/// Currently logs completions at debug level — real incorporation logic
|
|
/// (spawning chunks, activating NPCs) plugs in at Phase 5+.
|
|
///
|
|
/// **DETERMINISM GAP (D-010):** Results are incorporated at the tick they
|
|
/// happen to be ready, not at a deterministic tick. Two runs with the same
|
|
/// seed may incorporate a chunk at tick 500 vs tick 502 depending on CPU
|
|
/// load — diverging world state from that point.
|
|
///
|
|
/// This is acceptable while all handlers are no-ops (no simulation state
|
|
/// is modified). Before any handler produces real state changes, implement
|
|
/// a `WorkerResultLog` resource that records `(tick, worker_type, result)`.
|
|
/// Replay reads from the log instead of polling channels. See plan #843.
|
|
pub fn poll_worker_results(
|
|
chunk_worker: Option<Res<ChunkGenWorker>>,
|
|
npc_worker: Option<Res<NpcPrepWorker>>,
|
|
offscreen_worker: Option<Res<OffscreenTickWorker>>,
|
|
) {
|
|
if let Some(worker) = chunk_worker {
|
|
for (result, _strategy) in worker.pool.drain() {
|
|
tracing::debug!(
|
|
chunk_x = result.chunk_x,
|
|
chunk_y = result.chunk_y,
|
|
"ChunkGen result ready"
|
|
);
|
|
}
|
|
}
|
|
|
|
if let Some(worker) = npc_worker {
|
|
for (result, _strategy) in worker.pool.drain() {
|
|
tracing::debug!(area = %result.area_id, "NpcPrep result ready");
|
|
}
|
|
}
|
|
|
|
if let Some(worker) = offscreen_worker {
|
|
for (result, _strategy) in worker.pool.drain() {
|
|
tracing::debug!(
|
|
area = %result.area_id,
|
|
ticks = result.ticks_advanced,
|
|
"OffscreenTick result ready"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// PostSnapshot: push new work requests based on player state.
|
|
///
|
|
/// Placeholder — real logic (predict player movement direction, queue
|
|
/// chunks ahead, snapshot departing NPCs) plugs in at Phase 5+.
|
|
pub fn push_worker_requests() {
|
|
// No-op until chunk streaming and NPC tier transitions are implemented.
|
|
// The worker pools are ready to receive requests via:
|
|
// chunk_worker.submit(req, DeliveryStrategy::GracefulDegrade);
|
|
// npc_worker.pool.submit(WorkRequest { ... });
|
|
}
|