Skip to content

feat: replicate delivery cartons, and print notes and slips onto the paper - #83

Merged
rexlManu merged 2 commits into
mainfrom
feat/coop-cartons-and-paper
Aug 29, 2026
Merged

rexlManu merged 2 commits into
mainfrom
feat/coop-cartons-and-paper

Conversation

@rexlManu

Copy link
Copy Markdown
Member

Closes #80. Closes #82.

Two changes that landed together because they meet on one prop.

#80 — cartons reach a joined client

Co-op was complete host-side and unplayable as a guest: a client saw the bay and the truck and no boxes, so it could not carry one in, open one, or reach a vial. The day never started.

CartonView + NoteLineView are the same kind of NetworkList row VialView and SlipView are, with a CartonReconciler following SlipReconciler. CartonProp, CartonLid and DeliveryBayStation read through a new CartonFeed, which answers from this process own DeliveryBay first and the last snapshot otherwise — the LabView.Current rule MachineStation already follows, so one piece of code draws a host box and a client one.

Hard rule 2

The interesting part of this change is what does not travel.

  • The box carries a count, never a manifest. Carton.Contents is the answer to [gameplay] Reconciling the delivery note against what actually arrived #32. What crosses is VialsRemaining; the bottles travel as VialView rows naming this carton as their container, so a client can draw the room and read "3 vials still in it" without being told which three. CartonView.From takes the count as a parameter rather than the carton manifest, so there is no signature through which sample ids could start travelling.
  • A note line carries the claim, not the vial that answers it. DeliveryNote.Line.Sample is absent and has no wire equivalent. A client holding it could tick off the answered rows, and a note that reconciled itself leaves nothing to find. That argument has to survive the wire or it only protects whoever is hosting.
  • Views_NameNothingThatOnlyTheHostMayKnow gains Contents and Manifest. The sweep discovers views by reflection, so both new views were already in scope for it.

No new authority code. LabCommandExecutor.CanReachInCarton is still the only route a vial leaves a box by, and a client request reaches it by the identical path. A sealed carton also registers no vial slots, so there is nothing for a client to address in the first place.

#82 — the paper says what it says

Notes and printouts were blank grey sheets whose words lived only in the bottom-left overlay. Both now carry their text, through the PixelText/PixelCanvas rasteriser the reference book has used since #50. The overlay stays — additive, not a replacement.

This is not a material swap on the existing sheet. ProcMesh.Box gives every vertex the same single palette-atlas texel — correct for flat untextured props — so painting through those UVs would sample one colour across the page. PrintedSheetSurface builds its own quad with real UVs, sized from the sheet renderer own bounds. The shared palette material is never written to and LabSceneBuilder did not have to change.

Paper and ink only. A printout that coloured a reading by severity would spend hard rule 4 on a prop.

A redraw is skipped when the words have not changed: SlipReconciler re-binds every visible slip once a frame by design, and redrawing on each would push the whole buffer to the GPU per slip per frame for words that change at most once in a slip life.

Verification

  • Both headless compile checks clean.
  • Unity imported and compiled everything with zero errors — that is the pass that enforces asmdef boundaries, where a hard-rule-2 violation would actually surface.
  • New EditMode tests: carton view round-trip and the two leak sweeps, note lines reaching the desk in printed order, client carton/note reconcile including the shelf-then-held sequence, and the printed sheet surface lifetime.
  • The EditMode suite was not run — it is not run in this project at present. Tests here are compile-verified only.
  • Not yet verified by eye: whether the header band moulded proud of the sheet collides with the printed title line, and a real two-instance co-op session.

A note and a printout were blank grey sheets whose words existed only in the
bottom-left reading overlay. Both now carry their text on the paper itself,
through PixelText/PixelCanvas — the same rasteriser the reference book has used
since #50, so there is no second way to draw text in the world.

The overlay stays. It is additive: a note and a slip are short enough to read
both ways, unlike a manual, so this does not copy ReferenceBook's suppression of
its own overlay.

Not a material swap on the sheet the scene builder already makes. ProcMesh.Box
gives every vertex on every face the same single palette-atlas texel — correct
for flat untextured props (2.1) — so painting a varying texture through those UVs
samples one colour across the whole page. PrintedSheetSurface builds its own quad
with real 0..1 UVs instead, sized from the sheet renderer own localBounds rather
than a copy of LabSceneBuilder dimensions. The shared palette material is never
written to, and LabSceneBuilder did not have to change.

Paper and ink only, never the signal palette: a printout that coloured a reading
by severity would spend hard rule 4 on a prop.

Both readings come from one string — body for the note, BuildReadingText() for
the slip — so the page in your hand cannot disagree with the overlay.

A redraw is skipped when the words have not changed. SlipReconciler re-binds
every visible slip once a frame by design, because a result key can arrive a
publish after the paper does; redrawing on each of those would re-wrap, allocate
and push the whole 128x176 buffer to the GPU per slip per frame, for words that
change at most once in a slip life.

PrintoutProp also gains the InspectionRotation the note and the book have. Its
readable face is its local up, and the identity default presented it edge-on —
text nobody can see is not a typography problem.

Refs #82
A joined client saw the bay and the truck and no boxes. It could not carry one
in, open one, or reach a single vial, so the day never started — co-op was
complete host-side and unplayable as a guest. This is the row that ends that:
the same kind of list VialView and SlipView are, for the third thing you pick up.

The box carries a count, never a manifest. Carton.Contents is the answer to #32 —
which vial arrived under which claim — so what crosses is VialsRemaining, an
integer, and the bottles travel where they always did, as VialView rows naming
this carton as their container. CartonView.From takes the count as a parameter
rather than reading the manifest, so there is no signature through which sample
ids could start travelling. Hard rule 2 is upheld by there being no field that
could express the answer.

NoteLineView carries the claim and not the vial that answers it. DeliveryNote.Line
also holds the SampleId that really answers each row; that field is absent and has
no wire equivalent. It is never printed on the paper, and a client holding it
could tick off the answered rows — a note that reconciled itself would leave
nothing to find, and that argument has to survive the wire or it only protects
whoever is hosting. Index does travel: a discrepancy is inserted where it was
booked, and a page numbered differently at the two ends would file the wrong claim.

Views_NameNothingThatOnlyTheHostMayKnow gains Contents and Manifest. The sweep
discovers views by reflection, so both new ones were already in its scope.

CartonProp, CartonLid and DeliveryBayStation now read a CartonPlacement through
CartonFeed, which answers from this process own DeliveryBay first and the last
snapshot otherwise — the LabView.Current rule MachineStation already follows, so
one piece of code draws a host box and a client one. The lid toast counts off the
note rather than the box, because quoting the real number there would announce #32.

No new authority code. LabCommandExecutor.CanReachInCarton is still the only route
a vial leaves a box by, and a client request reaches it through the identical path;
a sealed carton also registers no vial slots, so there is nothing to address.

LabRecords.Notes is filled on a client, rebuilt into real DeliveryNote objects, so
the desk and the paper number the rows identically. TerminalScreen no longer says
paperwork cannot reach a joined terminal.

Refs #80
@rexlManu
rexlManu merged commit 4db09da into main Aug 29, 2026
2 checks passed
@rexlManu
rexlManu deleted the feat/coop-cartons-and-paper branch August 29, 2026 19:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ui] Delivery notes and printouts are blank paper [netcode] Cartons and the delivery bay are not replicated

1 participant