Background predictive chunk streaming

Chunk generation and sending no longer block the read loop. The read
loop pushes a non-blocking recenter request and stays free to handle
movement, chat, and keep-alive acks immediately; a per-connection
streamer goroutine generates chunks in a worker pool and sends them
serially under the write mutex.

- network/streamer.go: per-connection streamer. spiralOrder emits
  chunks centre-outward; parallelSend fans Cache.Frame across a worker
  pool (Cache.Frame is already goroutine-safe), parallelGenerate warms
  a one-ring predictive border so movement finds ready chunks; the
  loaded-set is owned solely by the streamer.
- network/play.go: beginPlay launches the streamer and pushes an
  initial recenter instead of the old blocking streamAround;
  onPlayerMove now just calls requestRecenter (non-blocking).
- network/handler.go: ctx (connection lifetime) + streamer field; the
  streamer stops when the read loop ends (cancel on serve exit).
- network/configuration.go: client view_distance is saved (clamped
  2..16) and drives the streamer radius.
- Tests: spiral order (centre-first, ring structure) and the
  non-blocking recenter guarantee the read loop relies on.
This commit is contained in:
Master290 2026-06-25 00:54:57 +03:00
parent d1cc29bb60
commit d7c80a8858
5 changed files with 478 additions and 58 deletions

View file

@ -106,8 +106,20 @@ func (h *handler) handleClientInformation(pkt protocol.Packet) error {
return err
}
// view_distance drives the chunk streamer radius. The client sends 2..32;
// clamp into a sane server range so a huge view distance doesn't trigger a
// generation explosion.
vdInt := int(int8(vd))
if vdInt < 2 {
vdInt = 2
}
if vdInt > 16 {
vdInt = 16
}
h.viewDistance = vdInt
h.log.Info("client information",
"locale", locale, "view_distance", int8(vd),
"locale", locale, "view_distance", vdInt,
"chat_mode", chatMode, "main_hand", mainHand)
return nil
}