Character cameras, PA grid, voxel engine (correct layers)
Policies that keep the org coherent
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 --> Apps1. Character cameras + controllers — `Novolis.Simulation.View`
Extend existing BCL-only package (already has YawPitchController, OrbitCameraRig, FreeLookCameraRig, TrackingCameraRig, IViewController, ViewPose).
Add:
| Type | Role |
|---|---|
| `LookIntent` / `MoveIntent` | Host-agnostic floats (yaw/pitch/zoom; wish XZ + jump/sprint) — apps map Raylib/Silk/Avalonia |
| `FirstPersonCameraRig` | `IViewController`: eye height + yaw/pitch → `ViewPose` (build on `YawPitchController`) |
| `ThirdPersonCameraRig` | Follow target, boom distance, pitch clamps, optional `Func<Vector3,Vector3,float>` collision pull-in |
| `CharacterCameraDirector` | Shared 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:
| Type | Role |
|---|---|
| `TileLayer` / `TileMap2D` | Multi-layer cell data (floor / object / zone) over width×depth |
| `WallEdgeMap` | Walls/doors on N/E/S/W **edges** (PA model), not only full-cell solids |
| `RoomFloodFill` | Enclosed region detection from edge walls + openings |
| `GridPathfinder` | A\* on walkability (orthogonal; optional diagonal costs) |
| `BuildBatch` / `DirtyRect` | Place/demolish ops + dirty AABB for remesh/path invalidation |
| `WalkabilityMask` | Bridge 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³,ushortblock ids, air = 0)PackedColumnhelpers optional later
3b. `Novolis.Simulation.Voxels`
| Type | Role |
|---|---|
| `ChunkedVoxelWorld` | Dictionary of chunks; get/set block; neighbor-aware solid query |
| `VoxelStreamer` | Keep Chebyshev radius of chunks around focus (3D; compose with Procedural `InfiniteChunkStream` for XZ focus only if useful) |
| `TerrainFiller` | Fill columns from an `IHeightSampler`-shaped callback `(x,z)→height` + block id (adapter from Procedural `NoiseHeightfield` at app layer) |
| Dig/place API | `TrySetBlock` + 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).
| Type | Role |
|---|---|
| `FaceCulledMesher` | Emit quads for exposed faces |
| `GreedyMesher` | Merge coplanar faces (MC-capable mesh density) |
| Output | `TriangleMesh` / 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 buildsimulation 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-dogfoodingafter GPR publish.