|
VR-Engage
2.2
|
Purpose: This example shows how to implement a custom Protocol Data Unit (PDU) / interaction in VR-Engage using a comment messaging pattern. It fully implements the receive/display and network translation paths for a Comment PDU or interaction, and demonstrates how you would wire an outbound send path once you add your own UI or scripting.
Observable Behavior: When running this example with the comment plugins enabled and a role that includes DtCommentLogic and DtCommentConnector, your station displays incoming Comment PDUs or interactions as entries in a "Comment" action menu. Each received comment targeting your entity appears as a menu item you can dismiss; dismissing removes that specific comment. If you add UI that publishes CommentMessage instances or drive the network from an external tool such as VR-Forces, you can exercise the full send/receive path.
Prerequisites: Understanding of VR-Engage frontend-backend architecture and familiarity with the message system and event delegation. Knowledge of VR-Link networking (DIS/HLA protocols) and basic understanding of DIS PDU structures or HLA interactions is required.
Related Examples: The Vehicle Blinker Example covers frontend-backend coordination, while the Input Device Example addresses custom UI integration.
This example implements custom message definition for application-specific message types through message schemas defined in Lua files. Code generation creates C++ message classes with type-safe, strongly-typed fields using declarative message definition with automatic serialization.
The frontend UI component provides the user interface for receiving and dismissing comments through DtCommentLogic. It integrates with the VR-Engage action menu system, handles received comments and user dismissal actions, and displays dynamic menu items for active comments; composing or sending new comments from the UI is left to your own code.
The network connector pattern bridges internal messages and network PDUs using DtCommentConnector to translate between internal messages and network PDUs. It registers VR-Link callbacks for incoming PDU notifications and converts outgoing messages to DIS Comment PDUs or HLA Comment Interactions; the outbound path is exercised whenever your own UI, scripts, or backend systems publish CommentMessage instances.
The three-component architecture provides separation of concerns with commentMessage as the shared message definition library, commentFrontend handling comment display and user dismissal interaction in the frontend process, and commentNet managing network transmission through per-protocol plugins for DIS, HLA1516e, and HLA4.
flowchart LR
subgraph Frontend["VR-Engage Frontend"]
commentLogic["DtCommentLogic\n(Comment UI Component)"]
end
subgraph Connector["Network Connector Plugin\n(commentDIS, commentHLA1516E, etc.)"]
commentConnector["DtCommentConnector\n(Protocol Adapter)"]
exerciseConn["DtExerciseConn\n(VR-Link Exercise Connection)"]
end
network["DIS / HLA Exercise Network\n(Other Participants)"]
commentLogic -- CommentMessage --> commentConnector
commentConnector -- sendStamped(DIS/HLA Comment) --> exerciseConn
exerciseConn <-- DIS/HLA Comment --> network
network -- DIS/HLA Comment --> exerciseConn
exerciseConn -- callback(commentCb) --> commentConnector
commentConnector -- CommentMessage --> commentLogic
Component Responsibilities:
| Component | Process | Library Type | Responsibilities |
|---|---|---|---|
commentMessage | Shared | SHARED library | Message schema definition, serialization/deserialization |
commentFrontend | Frontend | MODULE (plugin) | UI integration, received comment display, dismissal actions |
commentNet | Frontend | MODULE (plugin) | Network transmission, PDU conversion, protocol handling |
Message Flow (Sending Comment) (pattern to follow once you add a sender):
CommentMessage with sender, receiver, and comment textDtVreMessageManagerDtCommentConnector receives the message (sender matches local entity ID)DtCommentInteraction VR-Link objectDtExerciseConn::sendStamped()Message Flow (Receiving Comment):
commentCb()DtCommentConnector::handleCommentInteraction()CommentMessage with sender/receiver/commentDtVreMessageManagerDtCommentLogic::handleCommentMessage() receives messageCustom messages defined declaratively in Lua:
The generateMessages() CMake function processes .lua files to create commentMessage.h and commentMessage.cxx files. The generated class inherits from DtVreMessage base with accessor/mutator methods created for each attribute. Serialization/deserialization is automatically implemented, and the message type string is used for handler registration.
Generated Interface (conceptual, actual file auto-generated):
The frontend component manages UI display of comments:
This class inherits from DtPlayerComponent as a generic frontend component, maintains a reference to the action menu for comment display, and implements two message handlers for comments and menu actions respectively.
Initialize creates the action menu and registers message handlers:
DtVreMessageDelegate creates type-safe callback binding while CommentMessage::theType() returns the message type string for filtering. The menu manager is retrieved from the player attribute store as a shared service, with the menu initially empty and elements added dynamically when comments are received.
When comment arrives, add it to the menu and display:
Filter logic prevents self-echoing through sender != receiver checks, while the menu element action "closeComment" enables user dismissal. The element parameter stores the sender ID for element identification, and the HANDLED return value indicates the message was fully processed.
User clicks to dismiss comment from menu:
Parameter matching allows identification of specific comments to dismiss while supporting multiple active comments simultaneously. The menu automatically hides when all elements are removed.
Unregister handlers to prevent dangling references:
The connector bridges internal messages and network PDUs:
This class inherits from DtSimEventConnector as the base for network event handlers. The DT_PROTOCOL_NAMESPACE macro expands to protocol-specific namespaces (DIS, HLA1516e, etc.), while handleCommentInteraction() processes incoming VR-Link PDUs and handleCommentMessage() processes outgoing internal messages. It stores the local entity ID for filtering purposes.
Install registers VR-Link callback and message handler:
VR-Link uses C-style callbacks, requiring the global commentCb function, while the user pointer (usr) passes the this pointer for context. The DtCommentInteraction::addCallback() method registers for PDU notification, and the local entity ID is cached for filtering incoming and outgoing messages.
Convert incoming PDU to internal message:
Filtering by receiver ID prevents processing broadcasts not intended for this entity. DtCommentInteraction serves as the VR-Link wrapper for Comment PDUs, with messages created dynamically using factory methods and queueMessage() providing asynchronous delivery processed in the next frame.
Convert outgoing message to PDU:
Filtering by sender ID prevents re-transmitting received messages, while the DtCommentInteraction constructor populates PDU fields. The sendStamped() method adds timestamps and transmits immediately, with protocol-specific serialization handled automatically by VR-Link.
Cleanup removes callbacks and handlers:
Each plugin registers its components:
Network connectors are built separately for each protocol (DIS, HLA1516e, HLA4), with protocol-specific macros (DtDIS, DtHLA_1516_EVOLVED, etc.) defined by the build system. Connector names include protocol suffixes for disambiguation.
Build all components (see Environment Setup & Build Guide):
Install all plugins to the VR-Engage installation:
This copies:
<VR-Engage-Install-Dir>\bin64\exampleCommentMessage.dll<VR-Engage-Install-Dir>\plugins64\vrEngage\release\exampleCommentFrontend.dll<VR-Engage-Install-Dir>\plugins64\vrEngage\release\exampleCommentDIS.dll (and HLA variants)Verify installation:
Frontend plugins load automatically: VR-Engage automatically discovers and loads all plugins in the plugins64/vrEngage/release/ directory at startup. No plugin manifest configuration is required for frontend plugins.
Example simulation model set (VR-Forces integration):
If you are running VR-Engage against a VR-Forces backend, the easiest way to configure this example is to use the provided simulation model set vrengage/data/data/simulationModelSets/examples/customPdu.sms. It configures a DIS exercise connection on localhost and uses the human role vrengage/data/data/simulationModelSets/examples/customPdu/roles/human.lua, which adds the DtCommentLogic component and DtCommentConnector so that incoming Comment PDUs or interactions targeting your human entity will appear in the Comment menu in VR-Engage.
The role file configures the components and connectors as follows:
When you launch VR-Engage with this simulation model set selected, no additional role or connection configuration is required for the example.
Manual integration without the example SMS:
If you are not using the customPdu.sms file and want to integrate the example into your own configuration, you can instead:
appData/scripts/playerDefinitions).data/connection/connectionDIS.lua).Conceptually this looks like:
Single-Station Test (verify receive/display behavior):
Multi-Station Test (end-to-end network verification):
Verification:
Message library not found:
exampleCommentMessage.dll in <VR-Engage-Install-Dir>\bin64\Frontend plugin not loading:
Network connector not registering:
connectors listComments not appearing:
Duplicate messages:
cmsg->getSender() != myPlayer->entityId() check in frontend| Class | Base Class | Purpose | Component |
|---|---|---|---|
CommentMessage | DtVreMessage | Internal message type | commentMessage (generated) |
DtCommentLogic | DtPlayerComponent | Frontend UI and display | commentFrontend |
DtCommentConnector | DtSimEventConnector | Network PDU handling | commentNet |
Message System APIs:
DtVreMessageManager::instance() - Get message manager singletonDtVreMessageManager::addHandler() - Register message handlerDtVreMessageManager::removeHandler() - Unregister message handlerDtVreMessageManager::queueMessage() - Publish message asynchronouslyDtVreMessageDelegate - Type-safe message handler callbackAction Menu APIs:
DtPlayerStation::playerAttributeStore() - Access shared servicesDtPlayerAttributeStore::getAttribute<>() - Retrieve service by typeDtMenuManager::addMenu() - Register custom menuDtMenu::addElement() - Add dynamic menu itemDtMenu::removeElement() - Remove menu itemDtMenu::closeMenu() - Hide menuDtMenuElement constructor - Create menu item with action and parameterVR-Link APIs:
DtCommentInteraction::addCallback() - Register PDU callbackDtCommentInteraction::removeCallback() - Unregister PDU callbackDtCommentInteraction::senderId() - Get sender entity IDDtCommentInteraction::receiverId() - Get receiver entity IDDtCommentInteraction::comment() - Get comment textDtCommentInteraction::setSenderId() - Set sender IDDtCommentInteraction::setReceiverId() - Set receiver IDDtCommentInteraction::setComment() - Set comment textDtExerciseConn::sendStamped() - Transmit PDU with timestampLua Message Attributes:
| Attribute | Type | Description |
|---|---|---|
fileName | string | Base name for generated files (without extension) |
className | string | C++ class name (will be suffixed with "Message") |
messageType | string | Unique message type identifier (hierarchical dotted notation) |
comment | string | Documentation comment for generated class |
attributes | table array | List of message fields with {type, name} |
Supported Attribute Types:
String, Int, Double, BoolEntityIdentifier, Vector3, QuaternionDIS Comment PDU is a freeform text message with:
| Field | Type | Description |
|---|---|---|
| Originating Entity ID | Entity Identifier | Sender entity |
| Receiving Entity ID | Entity Identifier | Receiver entity (or 0.0.0 for broadcast) |
| Variable Datum | Datum Record | Contains comment text as variable-length string |
HLA Comment Interaction has similar fields mapped to HLA object attributes.
commentMessage → exampleCommentMessage.dll (SHARED)commentFrontend → exampleCommentFrontend.dll (MODULE)commentDIS → exampleCommentDIS.dllcommentHLA1516e → exampleCommentHLA1516e.dllcommentHLA4 → exampleCommentHLA4.dllbin64/plugins64/vrEngage/release/plugins64/vrEngage/release/This example builds separate network connector plugins for each protocol:
| Protocol | Preprocessor Define | Connector Name | Build Target |
|---|---|---|---|
| DIS | DtDIS | DtCommentConnector-DIS | commentDIS |
| HLA 1516 | DtHLA_1516 | DtCommentConnector-HLA1516 | commentHLA1516 |
| HLA 1516 Evolved | DtHLA_1516_EVOLVED | DtCommentConnector-HLA1516E | commentHLA1516e |
| HLA 4 | DtHLA_4 | DtCommentConnector-HLA4 | commentHLA4 |
Only one connector should be loaded per VR-Engage instance (matching the exercise connection protocol).
Related documentation: