Skip to main content

Chunk System

The chunk system procedurally generates the forest trail that players navigate. Chunks stream ahead of the player and despawn behind them.

Pipeline Overview​

Server Startup
→ Load start chunk (ChunkPrefab_Start)
→ Prewarm 3 chunks ahead
→ Sync game seed to clients

Heartbeat (0.25s)
→ Update safe zone players
→ Ensure chunks ahead for all players
→ Check run completion
→ Process pending chunk queue (one per tick)
→ Process pending unload queue (one per tick)

Key Files​

FilePurpose
chunk-service.tsMain orchestrator — heartbeat, safe zones, run completion
chunk-lifecycle-manager.tsPer-chunk spawn / unload queue, ground-grid upkeep
run-director.tsSource of truth for the run plan — owns PacingManager + FeedbackState, handles devtools replans
chunk-generator.tsTemplate cloning, positioning, overlap detection
chunk-prepper.tsCreates Start/End parts from baseplate attachments
utils/pacing-manager.tsDifficulty cycle, safe zone markers, enemy scaling (pure calculator)
utils/chunk-planner.tsDFS with chronological backtracking — pre-validates the entire run's chunk layout
utils/planner/plan-chase-section.tsRiver / minecart atomic sections + river realignment
utils/planner/plan-fork-section.tsSplit-and-merge branch sections with interleaved DFS
danger-zone-manager.tsRing zones around baseplates for enemy spawning
baseplate-manager.tsOctree-based spatial indexing of chunk positions
director/feedback-state.tsPhase 8 accumulator — rolling signal vector from gameplay events
director/feedback-policies.tsPressure adjusters consuming FeedbackSignal (flag-gated)

RunDirector​

RunDirector (formerly RunPlanManager) is the single handle ChunkService uses for all run-level state. It owns:

  • The pre-validated placement plan (PlacementInstruction[]) produced by ChunkPlanner.planRun.
  • A composed PacingManager — pacing queries like getPacingForChunk(idx), getMaxTrailMarker() are exposed as director delegates.
  • The FeedbackState accumulator (Phase 8) — tracks deaths, clears, and streaks to feed the pressure policies.
  • Preset / fork-section / chase-section configuration from devtools.
  • Seed-retry logic for ensurePlanBuilt and the devtools planWithSeed / replanFutureChunks paths.

Callers consume it through ChunkService — never instantiate a separate PacingManager outside the director unless you're in a pure-function context (tests, planner sub-modules).

Chunk Planner​

ChunkPlanner.planRun is the main DFS loop. Chase and fork sections were extracted into utils/planner/:

  • plan-chase-section.ts — atomic multi-chunk sections (River, minecart). Handles river-specific steering: straight-first on entry, cardinal realignment over the last few chunks.
  • plan-fork-section.ts — split-and-merge branches. Interleaves A / B placements (A₀, B₀, A₁, B₁, …) with its own backtracking stack, then runs computeMergeChunks to reconverge.
  • planner/build-candidates.ts, overlap-checks.ts, simulate-placement.ts, screening.ts, bush-validation.ts — shared helpers.

Chunk Creation Flow​

  1. Plan lookup — runDirector.getRunPlan() returns the pre-validated PlacementInstruction for the next chunk index.
  2. Template Selection — getChunkForPacing() resolves the instruction against ReplicatedStorage.Prefabs.Cyclable.
  3. Preparation — prepareChunk() creates Start/End parts from baseplate attachments.
  4. Positioning — End-to-end alignment using Start/End attachment CFrames (planner already validated this works).
  5. Registration — Tagged Gameplay_Chunk, baseplate registered in octree.
  6. Danger Zones — Deferred ring creation around the baseplate.

Pacing System​

The game cycles through phases, with safe zones at fixed trail markers:

Calm (2 chunks) → Tense (2 chunks) → Challenge (2 chunks) → repeat
Safe Zones at markers: 10, 30, 70

Trail Markers​

  • ~1 marker per 2 chunks: trailMarker = floor(chunkIndex / 2) + 1
  • Physical wooden posts placed by GameplayChunk component
  • Max trail marker: 30 (MVP) — chunks stop generating after this

Difficulty Scaling​

  • Multiplier: 1.0 + (trailMarker × 0.05), capped at 3.0
  • Affects enemy density and aggression per phase

Chunk Unloading​

When enabled, chunks 3+ behind the furthest-back player are queued for unloading:

  1. Path nodes re-parented to UnloadedPathNodes folder (keeps refs valid)
  2. Danger zones removed
  3. Chunk model destroyed
  4. Echo boundary updated for late joiners

Safe Zones​

Safe zone detection uses a dual approach:

  • Registered parts — Tagged SafeZone parts checked via PointToObjectSpace
  • Pacing-based — Chunks with isSafeZone pacing flag

Safe zone effects (0.25s tick):

  • Health regen: 10 HP/sec (2.5 per tick)
  • Insanity decay (client-side)
  • Enemy exclusion

Server Verification​

Client detects safe zone entry via ZonePlus, fires remote. Server verifies with retry logic (3 attempts, 0.15s apart) to account for network latency.

Run Completion​

When a player reaches the final safe zone (marker 30):

  1. checkRunCompletion() detects player on SafeZone chunk at max marker
  2. runCompleteCallback fires
  3. Player teleported to lobby