Skip to content

occluder.fbs — the disclosed occluder set

Source: modules/Descent.Vtt.Protocol/schemas/occluder.fbs at build time. 12 line(s) withheld — internal regions exist in the source and are removed by the scrubbing pipeline; that they exist is public, their content is not.

// The disclosed occluder set — walls, on the wire (§9.2, ADR-034).
//
// Read schemas/README.md first; its three rules are assumed here.
//
// **Why occluders travel at all, when visibility does not.** ADR-034 makes line of sight
// strictly server-authoritative and the client's fog a *presentation* of the authoritative
// mask. That does not make geometry itself secret: §9.2 puts "own-entity movement prediction
// and collision preview over geometry the acting client has been disclosed" explicitly IN
// scope. A client needs walls to predict a move that will not walk through one; it does not
// get them in order to compute what it can see.
//
// **The set is per viewer and it is a subset, always.** §9.2: entities the server has not
// disclosed are "absent from the client's data set entirely; they are never
// present-but-culled, because a culling shader is one patched line away from being
// disabled". The same rule governs this message — an undisclosed wall is not sent with a
// flag, it is not sent. That is what keeps the client's A* a *preview* rather than an answer.
//
// **A secret door is the case that decides the shape of this file.** If the server sent
// every wall and let the client hide some, a player could read the concealed geometry out of
// their own memory. So the filter runs server-side, before the encode, and this schema has
// no field a client could use to reconstruct what was withheld — no total count, no
// identifiers with gaps, no bounding box of the full set.
namespace Descent.Vtt.Protocol;
/// One wall segment, in raw fixed-point (i32.16), exactly as ADR-017 requires.
///
/// A **struct** rather than a table: it is four fixed scalars with no optional member, so
/// the vector below is a flat inline run of 16-byte records with no vtable and no offset
/// indirection per element. A table here would cost a vtable lookup per wall on a path that
/// reads every wall on every disclosure change.
///
/// The ordinates are Q16.16 and never floating point, so both hosts agree bit-exactly —
/// neither ever sees an f32.
struct OccluderSegment {
ax: int32;
ay: int32;
bx: int32;
by: int32;
}
/// Server -> client. The occluder set this viewer is permitted to hold.
///
/// **Whole-set replacement, never a delta.** Walls change when a map is authored or a door
/// opens — rarely, and never at tick cadence — so the bandwidth argument for a delta does not
/// arise. What does arise is the correctness argument against one: a delta stream over a
/// *filtered* set has to express "this wall left your set", and whether it left because it
/// was deleted or because it stopped being disclosed is precisely the distinction that leaks.
/// Replacing the set says nothing about why it changed.
table OccluderSync {
/// §9.6: every packet carries this, field id 0.
protocol_version: uint32;
/// Monotonic per room. Lets a client discard a sync that lost a race with a newer one.
///
/// **Not a tick.** Occluders are not tick-driven and pinning them to the tick sequence
/// would imply a cadence they do not have. It orders two syncs against each other and
/// nothing else.
revision: int64;
/// The disclosed walls. **Empty is a legitimate answer** meaning "you have been disclosed
/// no geometry", and a client must treat it as such rather than as a failed load.
segments: [OccluderSegment];
}
root_type OccluderSync;
/// Identifies an occluder buffer on disk or in a capture.
file_identifier "DVO1";