DIS

The DIS plugin gives Bowire two paths into an IEEE 1278.1 Distributed Interactive Simulation multicast group:

  • Live discovery + entity-scoped streaming — point at a dis://group:port URL and the workbench probes the group, surfaces every active entity as a service, and streams typed PDU envelopes (filtered to that entity, or to the whole exercise feed) into the workbench.
  • Mock replay — DisMockEmitter re-broadcasts captured PDU sequences on UDP at the original cadence so simulation stacks can test against reproducible traffic without a live exercise.

Package: Kuestenlogik.Bowire.Protocol.Dis (sibling repo, not bundled with the CLI)

Setup

bowire plugin install Kuestenlogik.Bowire.Protocol.Dis

Standalone

bowire --url dis://239.1.2.3:3000

Embedded

app.MapBowire(options =>
{
    options.ServerUrls.Add("dis://239.1.2.3:3000");
});

URL shapes

dis://239.1.2.3:3000          # standard multicast group + DIS port
dis://multicast               # shortcut for 239.1.2.3 (default port)
239.1.2.3:3000                # bare host:port also accepted

Default group is 239.1.2.3, default port 3000 (IEEE 1278 convention). The probe duration during discovery is configurable via the plugin's probeDuration setting — defaults to 3 seconds, long enough to catch a heartbeat from every active entity.

Live discovery

DiscoverAsync joins the multicast group for the probe window, observes every EntityState PDU it sees, and surfaces:

  • one synthetic Exercise service whose monitor stream yields every PDU on the group (raw exercise feed)
  • one service per discovered entity, named after its EntityId (<site>:<application>:<entity>) plus marking + entity-type info, whose monitor stream yields only PDUs from that entity

Subscribing to a service opens a UDP socket on the same group and yields one JSON envelope per matched PDU. The envelope decodes the PDU header (kind, family, exercise id, timestamp) plus EntityState specifics (position, orientation, velocity, marking string, force id) when applicable. Every other PDU kind is decoded by its IEEE 1278.1 record into a pdu object with its typed fields and lists the entities it names in relatedEntityIds; raw carries the bytes either way.

An entity's stream shows every PDU that names that entity in any role — its own Entity State, a Fire it fired or was targeted by, a Collision on either side, a Designator aimed at it. Live Entity PDUs identify entities with the narrower Live Entity id and do not reach an entity stream yet.

Mock replay

DisMockEmitter plugs into Bowire's mock server via IBowireMockEmitter. Recordings tagged protocol: "dis" get re-broadcast on the configured multicast group at the original cadence:

Metadata key (first DIS step) Purpose Default
multicast-group UDP multicast destination 239.1.2.3
port UDP port 3000
ttl Multicast TTL — 1 keeps it on the local subnet 1

Each step carries:

  • protocol: "dis"
  • responseBinary — base64 of the raw PDU bytes (IEEE 1278 wire format)
  • capturedAt — millisecond timestamp used for emission pacing
  • optional metadata (only on the first DIS step — applied to the whole DIS sub-sequence)

By default replay is a thin relay that ships the captured bytes verbatim. Opt-in metadata re-scopes a capture without editing it; only the 12-byte header is rewritten:

Metadata key (first DIS step) Effect
exercise-id 1-255 — replaces the exercise id in every PDU
pdu-types Comma-separated PDU type names or ids — every other PDU is not sent
entities Comma-separated site:app:entity triples — a PDU is sent when it names one of them in any role; one that does not decode is not sent
retime now — the header timestamp becomes the time of sending, keeping the absolute/relative bit

A value the emitter does not understand fails the mock's start rather than filtering everything away. Use bowire mock --recording my-exercise.bwr --loop for repeated replay.

Relationship to the UDP plugin

Bowire.Protocol.Udp is the low-level cousin — it surfaces every received datagram as a JSON envelope without decoding any protocol. Run both at once: DIS on the URL for typed per-entity streams, UDP on the same port for the raw-bytes view. Pick the protocol string (dis vs udp) on your recording steps to route them to the right emitter.

See also: UDP, Recording, Mock Server.