Encapsulate world state across all six ports: Level, Bsp, and node sum-types #1

Merged
bnied merged 0 commits from refs/pull/1/head into main 2026-07-14 02:04:51 +00:00
bnied commented 2026-07-14 02:04:28 +00:00 (Migrated from codeberg.org)

What

Removes global world state and "C-with-structs + free-functions" seams
across all six language ports, without changing rendered output or
controls. Each port keeps its own idioms — the fix is the same shape,
adapted per language, not a literal port of the C++ classes.

The three seams addressed (where each applies):

  1. Global map data → a Level type owning vertices/sectors/linedefs,
    threaded explicitly into player/renderer/BSP. (all six ports)
  2. BSP as free functions over a bare node → a Bsp type exposing
    findSector / traverse, build/classify kept private.
  3. Leaf-vs-internal via a bool flag → the language's native sum type.

Per port

Port Changes
C++ Level + Bsp + Visplane classes; node → std::variant<Leaf, Internal>
Swift Level struct + Bsp struct (node enum & Visplane were already idiomatic)
Go Level + BSP type; node → sealed bspNode interface + type-switch
Rust Level + Bsp; Visplane fields sealed behind accessors (node already an enum)
Python Level + Bsp class; node → `BSPLeaf
Zig Level struct of slices — kept comptime/.rodata, zero runtime cost (rest already idiomatic)

Plain value aggregates (Vec2, RGBA, Sector, LineDef, Seg, Input) stay
structs everywhere — they have no invariant to protect.

Why

Every subsystem previously reached into module/package/static globals for
the map, making the dependency invisible, untestable against a fixture
map, and impossible to instantiate twice. After this, the map is a value
passed by reference and the BSP/Visplane invariants are owned by their
types.

Verification

Each port built clean on its own toolchain:

  • C++ -Wall -Wextra (also ran + rendered identically), Swift swift build,
    Go go build + go vet, Rust cargo build (no new clippy lints),
    Python py_compile + BSP smoke test + API audit, Zig zig build.
## What Removes global world state and "C-with-structs + free-functions" seams across all six language ports, without changing rendered output or controls. Each port keeps its own idioms — the fix is the same *shape*, adapted per language, not a literal port of the C++ classes. The three seams addressed (where each applies): 1. **Global map data** → a `Level` type owning vertices/sectors/linedefs, threaded explicitly into player/renderer/BSP. *(all six ports)* 2. **BSP as free functions over a bare node** → a `Bsp` type exposing `findSector` / `traverse`, build/classify kept private. 3. **Leaf-vs-internal via a `bool` flag** → the language's native sum type. ## Per port | Port | Changes | |------|---------| | **C++** | `Level` + `Bsp` + `Visplane` classes; node → `std::variant<Leaf, Internal>` | | **Swift** | `Level` struct + `Bsp` struct (node enum & `Visplane` were already idiomatic) | | **Go** | `Level` + `BSP` type; node → sealed `bspNode` interface + type-switch | | **Rust** | `Level` + `Bsp`; `Visplane` fields sealed behind accessors (node already an `enum`) | | **Python** | `Level` + `Bsp` class; node → `BSPLeaf | BSPInternal`, dropping all `# type: ignore` | | **Zig** | `Level` struct of slices — kept comptime/`.rodata`, zero runtime cost (rest already idiomatic) | Plain value aggregates (Vec2, RGBA, Sector, LineDef, Seg, Input) stay structs everywhere — they have no invariant to protect. ## Why Every subsystem previously reached into module/package/static globals for the map, making the dependency invisible, untestable against a fixture map, and impossible to instantiate twice. After this, the map is a value passed by reference and the BSP/Visplane invariants are owned by their types. ## Verification Each port built clean on its own toolchain: - C++ `-Wall -Wextra` (also ran + rendered identically), Swift `swift build`, Go `go build` + `go vet`, Rust `cargo build` (no new clippy lints), Python `py_compile` + BSP smoke test + API audit, Zig `zig build`.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
spaceduck/BSPRenderer!1
No description provided.