In-world vessels
verifiedAgainst 119c2c3 · verifiedOn 2026-09-10.
In one paragraph
Section titled “In one paragraph”VoxelSandbox.Industry turns the headless VesselSolver into a placeable object without taking ownership of chemistry, terrain, player input, or save slots. VesselFormFactory proves a voxel footprint is clear and supported, then constructs the rendered and collidable form. VesselRuntime is the Unity bridge: it bakes optional authored catalogues, wires an atmospheric destination, and forwards Time.deltaTime. The plain-C# VesselDomain owns the fixed 20 Hz accumulator, ScienceVesselRun, gas releases, sticky failure state, and atomic checkpoint. One physical apparatus can therefore survive a reload and present a causal chemistry account without creating a World → Industry back-reference.
The pieces
Section titled “The pieces”| Symbol | File | Responsibility |
|---|---|---|
VesselApparatusDefinition |
Industry/Vessels/VesselApparatusDefinition.cs:17 |
Authored crude-apparatus footprint, visual dimensions/colours, and placeholder physical defaults; not mutable vessel state |
VesselFormFactory.TryPlace |
Industry/Vessels/VesselFormFactory.cs:39 |
Validates a clear footprint plus solid floor through IVoxelBlockWorld, then composes a procedural collider, mesh, runtime, and glow |
VesselRuntime |
Industry/Vessels/VesselRuntime.cs:22 |
Thin MonoBehaviour: catalogue bake, Unity lifecycle, player-facing charge/heat/save adapters |
VesselDomain |
Industry/Vessels/VesselDomain.cs:81 |
Plain-C# owner of a run, fixed cadence, environment energy, gas transfer, and failure quarantine |
VesselFailureReason |
Industry/Vessels/VesselDomain.cs:8 |
One sticky result for overpressure and thermal-limit failure |
VesselSaveData |
Industry/Vessels/VesselSaveData.cs:15 |
Versioned, JSON-friendly adapter for a complete checkpoint; Industry owns the DTO while World provides generic persistence |
VesselThermalGlowRuntime |
Industry/Vessels/VesselThermalGlowRuntime.cs:15 |
Cached, one-way blackbody emission presentation from simulated temperature |
The flow
Section titled “The flow”flowchart TD APP["VesselApparatusDefinition\nfootprint + defaults"] PLACE["VesselFormFactory\nvalidate then build"] WORLD["IVoxelBlockWorld\nair footprint + solid floor"] RUNTIME["VesselRuntime\nUnity wiring"] DOMAIN["VesselDomain\n20 Hz run owner"] SOLVER["ScienceVesselRun\nVesselSolver tick"] AIR["AtmosphericDomainRegistry\nnamed gas receiver"] SAVE["VesselSaveData\ncheckpoint adapter"] SESSION["GameSessionRuntime\ngeneric slot bridge"] GLOW["VesselThermalGlowRuntime\npresentation only"] APP --> PLACE WORLD --> PLACE PLACE --> RUNTIME --> DOMAIN --> SOLVER DOMAIN --> AIR RUNTIME --> SAVE --> SESSION DOMAIN --> GLOW
Place, do not voxel-edit. VesselFormFactory.TryPlace walks every cell in the authored footprint and then the floor row below it. An occupied footprint returns FootprintCellOccupied; an air floor returns NoFloorBeneath; either failure creates nothing. Build is reserved for a harness or caller that already proved placement. The factory makes the BoxCollider the authoritative physical obstruction, removes conflicting primitive colliders, assigns the apparatus before initialization, and then adds thermal glow. Apparatus occupies space but never writes terrain.
Unity forwards; the domain decides. VesselRuntime.EnsureInitialized (VesselRuntime.cs:243) creates the domain once and is safe where Awake does not fire. Its Update (:422) only forwards Time.deltaTime; a refused tick logs and disables the component. An invalid optional catalogue produces an empty immutable table/reaction array, leaving a placeable but honestly inert vessel rather than a substitute chemistry model.
Fixed chemistry from arbitrary frame deltas. VesselDomain.TryAdvanceBySeconds (VesselDomain.cs:378) accumulates wall-clock seconds and advances whole 1 / 20-second ticks. Each tick reserves event capacity before moving material, adds optional player/environment energy, calls ScienceVesselRun, and retains accepted pressure. A short frame only accumulates; completed earlier ticks remain committed if a later tick fails. This clock is intentionally independent of Unity’s global fixed timestep.
Release gas to somewhere real. Venting, relief, and rupture require both an AtmosphericDomainRegistry and a named WorldBlockPosition. The domain builds a complete gas transfer, asks the receiver to accept it, then removes exact moles and records the vent. Without a configured destination the release is rejected and gas stays in the vessel. An open vessel vents after an accepted tick and cannot pressurise. A sealed vessel may proportionally relieve to its setpoint; only after that can it rupture above rated pressure. Thermal failure is checked first and applies even while open.
Failures, observations, and rendering. FailureReason is sticky: after Overpressure or ThermalFailure, all later advances are refused. TryBuildLatestAfterAction reconstructs bounded causal evidence, while the runtime supplies observation/narration adapters and UI owns layout. VesselThermalGlowRuntime.Refresh reads temperature, updates only once the change exceeds 0.25 K, and writes renderer property blocks. It is display only, never a heat source.
Save without reversing dependencies. VesselRuntime.TryCaptureSaveRecord creates a VesselDomainCheckpoint; VesselSaveRecord.FromCheckpoint flattens stable run/domain ids, clock, charge including traces, event log, valve/seal/failure state, and active player heat. Restore rebuilds a fresh domain with saved identity and current apparatus parameters, validates the checkpoint, and performs no offline catch-up tick. GameSessionRuntime calls generic SaveGameService.TrySaveVessels<T> / TryLoadVessels<T> (SaveGameService.cs:343), so World need not import an Industry type.
Invariants you must not break
Section titled “Invariants you must not break”- The domain owns simulation. Cadence, charge, failure, and checkpoints remain in
VesselDomain;VesselRuntimeadapts Unity and authored assets only. - Placement is all-or-nothing. Gameplay calls
TryPlace; every footprint and floor cell must validate before any form exists, and placement must not edit voxels. - Every released mole has a named receiver. Receiver acceptance precedes charge mutation. Never add a local discard path for open, relief, or rupture gas.
- Failure permanently quarantines a vessel. Preserve sticky
FailureReason, refusal of new ticks/heat, and restoration of the same failed state. - A checkpoint restores as one state. Keep joint Chemistry/Industry validation, stable run/domain identities, and the no-offline-catch-up rule.
- Crude apparatus defaults are placeholders. Pressure, temperature, heat, and wall-transfer values are tuning inputs until material tiers exist, not sourced physical constants.
- Presentation cannot affect chemistry. Glow and after-action narration read observations; they never write temperature, charge, event, or failure state.
Where it connects
Section titled “Where it connects”- Chemistry: The chemistry solver supplies immutable inputs and transactional ticks. Industry supplies a world-owned control volume and consequences.
- Data and Inventory: Catalogues & authoring supplies substance/reaction assets;
MaterialBatchChargingconverts a carried batch through the baked table all-or-nothing. - World and Player: Player owns interaction input and requests placement, charging, and heat.
AtmosphericDomainRuntimesupplies the scene-owned receiver. World remains ignorant of vessel types. - Persistence and UI: Persistence owns atomic slot writes through generic DTO methods.
GameSessionRuntimecoordinates vessel records; UI renders only the evidence-bounded account. - Tests:
VesselDomainTests,VesselAtmosphereTransferTests,VesselDomainPersistenceTests,VesselSaveDataTests,VesselFormFactoryTests,VesselAfterActionNarrativeTests, andVesselThermalGlowRuntimeTestsinAssets/_Game/Tests/EditMode/Industry/cover these boundaries.
See also
Section titled “See also”- The chemistry solver — the headless transaction the domain drives.
- Persistence — atomic slot writes and the generic DTO bridge.
- Assemblies & boundaries — why World never references Industry back.
Docs/MASTERPLAN.md§29.2–29.6, §31.4, and §36.4;Docs/CHEMISTRY_FOUNDATIONS.md§28.7.
User-contributed notes
Corrections, clarifications, and practical tips for this page. Anonymous is fine — a name is optional. Basic Markdown works:
**bold**,*italic*,`code`, and links.Notes policy
Notes are lightly filtered for spam and may be edited or removed. Keep them about this page — no support requests, no personal data, nothing you would not publish. Links are limited and marked
nofollow.