feat(server): gate startup on initial region streaming
This commit is contained in:
parent
19fdec44d1
commit
ca39d36a81
|
|
@ -86,6 +86,25 @@ fn main() {
|
||||||
let mut schedule = Schedule::default();
|
let mut schedule = Schedule::default();
|
||||||
schedule.add_systems(stream_chunks);
|
schedule.add_systems(stream_chunks);
|
||||||
|
|
||||||
|
// Loading phase: dispatch the initial region and wait for the worker pool to finish before granting control.
|
||||||
|
info!("Streaming initial region");
|
||||||
|
loop {
|
||||||
|
schedule.run(&mut world);
|
||||||
|
|
||||||
|
let server_world = world.resource::<ServerWorld>();
|
||||||
|
let resident = server_world.loaded_count();
|
||||||
|
let in_flight = server_world.in_flight_count();
|
||||||
|
// Loading progress is simply the resident fraction of all known chunks.
|
||||||
|
let total = resident + in_flight;
|
||||||
|
debug!(resident, in_flight, total, "loading progress");
|
||||||
|
|
||||||
|
// The region is ready once at least one chunk has been generated and none remain in flight.
|
||||||
|
if server_world.streaming_idle() && resident > 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!("Initial region ready; granting player control");
|
||||||
|
|
||||||
// Drive several ticks, marching the dummy one chunk along +X between each. The manual movement stands in for network-driven player input and exists only to exercise load/unload as the anchor moves.
|
// Drive several ticks, marching the dummy one chunk along +X between each. The manual movement stands in for network-driven player input and exists only to exercise load/unload as the anchor moves.
|
||||||
for step in 0..5 {
|
for step in 0..5 {
|
||||||
info!(step, "tick");
|
info!(step, "tick");
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,18 @@ impl ServerWorld {
|
||||||
self.chunks.len()
|
self.chunks.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Number of chunks dispatched to the worker pool but not yet returned.
|
||||||
|
#[must_use]
|
||||||
|
pub fn in_flight_count(&self) -> usize {
|
||||||
|
self.in_flight.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` when the worker pool has no outstanding generation work, i.e. every dispatched chunk has been returned. A loading gate can poll this to decide when an initial region has finished streaming.
|
||||||
|
#[must_use]
|
||||||
|
pub fn streaming_idle(&self) -> bool {
|
||||||
|
self.in_flight.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
/// Reconciles resident chunks against a desired set without blocking the caller: finished chunks are drained from the worker pool, resident chunks absent from `desired` are evicted, and still-missing chunks are dispatched to the pool.
|
/// Reconciles resident chunks against a desired set without blocking the caller: finished chunks are drained from the worker pool, resident chunks absent from `desired` are evicted, and still-missing chunks are dispatched to the pool.
|
||||||
pub fn reconcile(&mut self, desired: &HashSet<ChunkPos>) -> StreamStats {
|
pub fn reconcile(&mut self, desired: &HashSet<ChunkPos>) -> StreamStats {
|
||||||
// Drain: absorb every chunk the workers have finished since the last pass.
|
// Drain: absorb every chunk the workers have finished since the last pass.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue