Novolis Docs
novolis-governance / completed-plans/view_tiles_voxels_dc44b101.plan.md

Character cameras, PA grid, voxel engine (correct layers)

dotnetgovernancenovolis

name: View tiles voxels overview: Place character cameras/controllers in Simulation.View, add Prison Architect–style Simulation.Tiles and a Minecraft-capable Simulation.Voxels (+ meshing) stack under novolis-simulation—keeping gaming BCL-only and composing rendering in apps. todos:

  • id: view-character

content: Add LookIntent/MoveIntent, FirstPersonCameraRig, ThirdPersonCameraRig, CharacterCameraDirector, CharacterMotor to Simulation.View + tests status: completed

  • id: math-packed

content: Add ChunkCoord3 + VoxelChunk (16³ ushort) packed storage to Math.Arrays status: completed

  • id: sim-tiles

content: Create Novolis.Simulation.Tiles (layers, WallEdgeMap, flood-fill rooms, A*, BuildBatch/DirtyRect) + tests status: completed

  • id: sim-voxels

content: Create Novolis.Simulation.Voxels (ChunkedVoxelWorld, streamer, terrain filler, dig/place) + tests status: completed

  • id: sim-voxel-mesh

content: Create Novolis.Simulation.Voxels.Meshing (face-culled + greedy → Math.Geometry mesh) + tests status: completed

  • id: docs-map

content: Update library-boundaries + simulation READMEs; regen Platform slnx/map; nuget-only verify status: completed isProject: false


Placement (locked): Option 1 — extend `Novolis.Simulation.View`; add `Novolis.Simulation.Tiles` and `Novolis.Simulation.Voxels` (+ meshing). Do not put cameras/grids/voxels in novolis-gaming (policy + `library-boundaries.md`). Gaming keeps `Novolis.Game.Procedural` as the BCL authoring companion (noise / 2D chunk window).

flowchart TB
  subgraph gaming [novolis-gaming BCL]
    Proc[Game.Procedural noise stream]
  end
  subgraph sim [novolis-simulation]
    View[Simulation.View FP TP intents]
    Tiles[Simulation.Tiles PA grid]
    Vox[Simulation.Voxels world]
    Mesh[Simulation.Voxels.Meshing]
    World[Simulation.World PlanarOccupancy]
  end
  subgraph math [novolis-math]
    Arrays[Math.Arrays DenseGrid]
    Packed[PackedVolume ChunkBlocks]
  end
  Proc -.->|fill heights seed| Vox
  Arrays --> World
  Packed --> Vox
  Vox --> Mesh
  World --> Tiles
  View --> Apps[Apps compose to GPU]
  Mesh --> Apps
  Tiles --> Apps

1. Character cameras + controllers — Novolis.Simulation.View

Extend existing BCL-only package (already has YawPitchController, OrbitCameraRig, FreeLookCameraRig, TrackingCameraRig, IViewController, ViewPose).

Add:

TypeRole
LookIntent / MoveIntentHost-agnostic floats (yaw/pitch/zoom; wish XZ + jump/sprint) — apps map Raylib/Silk/Avalonia
FirstPersonCameraRigIViewController: eye height + yaw/pitch → ViewPose (build on YawPitchController)
ThirdPersonCameraRigFollow target, boom distance, pitch clamps, optional Func<Vector3,Vector3,float> collision pull-in
CharacterCameraDirectorShared look state; switch FP / TP / Orbit (OrbitCameraRig existing)
CharacterMotor (View-local)Integrate MoveIntent on XZ wish + gravity/jump without collision; expose desired delta for PlanarAgent / apps

Explicit non-goals (v1): head bob, recoil, gamepad HID bindings (stay in apps), Simulation→Raylib wiring.

Tests: unit tests in simulation test project for pose math, pitch clamps, director mode switch, motor jump.

Leverage dogfood later: patterns from DoomLite3D/Game/PlayerController.cs (lift logic, don’t take Raylib deps).


2. Prison Architect–style grid — Novolis.Simulation.Tiles

New packable package under novolis-simulation/src/Novolis.Simulation.Tiles/.

Depends: Novolis.Math.Arrays (DenseGrid), reuse `PlanarOccupancy` via Novolis.Simulation.World PackageReference (or duplicate thin walkability queries if World dep is too heavy — prefer World).

Core types:

TypeRole
TileLayer / TileMap2DMulti-layer cell data (floor / object / zone) over width×depth
WallEdgeMapWalls/doors on N/E/S/W edges (PA model), not only full-cell solids
RoomFloodFillEnclosed region detection from edge walls + openings
GridPathfinderA\* on walkability (orthogonal; optional diagonal costs)
BuildBatch / DirtyRectPlace/demolish ops + dirty AABB for remesh/path invalidation
WalkabilityMaskBridge to existing occupancy byte grids for PlanarAgent

v1 non-goals: full job/AI economy, furniture catalog, UI tools.

Tests: flood-fill rooms, A\* around walls, edge door opens path, dirty rect after demolish.


3. Voxel engine (Minecraft-clone minimum) — Novolis.Simulation.Voxels + meshing

3a. Storage — prefer Novolis.Math.Arrays extension

Add packed volume primitives (do not overload nullable DenseGrid<T>):

  • ChunkCoord3, VoxelChunk (fixed 16³, ushort block ids, air = 0)
  • PackedColumn helpers optional later

3b. Novolis.Simulation.Voxels

TypeRole
ChunkedVoxelWorldDictionary of chunks; get/set block; neighbor-aware solid query
VoxelStreamerKeep Chebyshev radius of chunks around focus (3D; compose with Procedural InfiniteChunkStream for XZ focus only if useful)
TerrainFillerFill columns from an IHeightSampler-shaped callback (x,z)→height + block id (adapter from Procedural NoiseHeightfield at app layer)
Dig/place APITrySetBlock + mark chunk + neighbors dirty for remesh

3c. Novolis.Simulation.Voxels.Meshing

Depends on Voxels + Novolis.Math.Geometry (triangle/editable mesh types already used by World.Builders).

TypeRole
FaceCulledMesherEmit quads for exposed faces
GreedyMesherMerge coplanar faces (MC-capable mesh density)
OutputTriangleMesh / existing geometry record — no Rendering/Raylib refs

v1 non-goals: skylight/AO, multiplayer sync, entity physics beyond AABB solid tests, biome decoration (Procedural later).

Tests: set/get across chunk borders, face cull air vs solid, greedy reduces quad count, streamer load/unload, filler produces walkable surface.


4. Docs / policy / solution wiring

  • Update `library-boundaries.md` checklist: First/ThirdPerson as shipped; add Tiles / Voxels facet rows.
  • Update simulation README / View README; gaming policy stays “no Simulation refs” — point authors at View/Tiles/Voxels for these features.
  • Add projects to simulation slnx; run `Generate-Platform-Slnx.ps1`.
  • Publish order to GPR: Math.Arrays (if packed types land there) → Simulation.View → Tiles / Voxels → Voxels.Meshing → consumers.

5. Verification

  • dotnet build simulation packages + unit tests for View / Tiles / Voxels.
  • verify-nuget-only.ps1 + verify-project-ref-mode.ps1 -SkipBuild.
  • Optional later (out of this plan’s code scope): dogfood mini samples (PA room builder, MC dig/place) under novolis-dogfooding after GPR publish.