diff --git a/crates/server/src/client_stream.rs b/crates/server/src/client_stream.rs index 42d81a6..48fce0e 100644 --- a/crates/server/src/client_stream.rs +++ b/crates/server/src/client_stream.rs @@ -18,6 +18,10 @@ pub const SERVER_MAX_RADIUS: u16 = 12; /// Worldgen version stamped on delivered chunk diffs. A single version exists today; this becomes the chunk's stored version once worldgen versioning lands. const WORLDGEN_VERSION: u32 = 0; +/// Upper bound on chunks encoded and sent to one client per tick. +// TODO: replace the fixed count with a time budget once per-chunk cost varies with LOD. +const MAX_DELIVERIES_PER_TICK: usize = 32; + /// The load and drop lists produced by diffing a client's previous desired set against a new one. #[derive(Debug, Default, PartialEq, Eq)] pub struct DesiredDiff { @@ -94,7 +98,7 @@ impl ClientStream { /// Delivers every desired-but-undelivered chunk that has become resident in `world`. /// - /// Each chunk is encoded as a [`ChunkData`] diff against `baseline` (an all-air chunk), making the payload self-contained. Positions still pending in the worker pool are skipped and retried on a later call. Returns the number of chunks delivered. + /// Each chunk is encoded as a [`ChunkData`] diff against `baseline` (an all-air chunk), making the payload self-contained. Positions still pending in the worker pool are skipped and retried on a later call, as are positions beyond [`MAX_DELIVERIES_PER_TICK`]. Returns the number of chunks delivered. pub fn flush(&mut self, world: &ServerWorld, baseline: &Chunk) -> usize { // Collected first to avoid borrowing `self.desired` while mutating `self.sent`. let ready: Vec = self @@ -106,6 +110,11 @@ impl ClientStream { let mut delivered = 0; for pos in ready { + // The budget counts chunks actually encoded, so ticks where most of the desired set is still in flight are not charged for work they did not do. + if delivered >= MAX_DELIVERIES_PER_TICK { + break; + } + let Some(chunk) = world.chunk(pos) else { // Not resident yet; a later flush retries once the worker pool returns it. continue; diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs index e435662..63db29f 100644 --- a/crates/server/src/main.rs +++ b/crates/server/src/main.rs @@ -225,10 +225,8 @@ fn run_simulation(world: &mut World, network: &NetworkServer) -> ! { ServerEvent::ChunkSubscribe { id, request } => { if let Some(client) = clients.get_mut(&id) { let (added, drops) = client.resubscribe(request.center, request.radius); - info!( - id, - added, drops, "client {id}: +{added} chunks, -{drops} drops" - ); + // Fires on every chunk boundary the client crosses, so it sits below the connect and disconnect events rather than beside them. + debug!(id, added, drops, "client resubscribed"); } else { warn!(id, "chunk subscribe from unknown session"); }