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:portURL 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 —
DisMockEmitterre-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
Exerciseservice whosemonitorstream 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, whosemonitorstream 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.