VR-Engage  2.2
Loading...
Searching...
No Matches
Entity Detection Example

Overview

Purpose: This example demonstrates frontend/backend coordination for sensor simulation in VR-Engage. It shows how to implement a radar detection system that identifies incoming threats and communicates detection information from the simulation backend to the player station frontend.

Observable Behavior: When running this example, you will see/experience:

  • Radar detection of incoming munitions displayed in real-time
  • Player attribute store updates reflecting detection state
  • Frontend UI elements showing closest threat information and detection counts
  • Backend sensor simulation coordinating with frontend display components

Prerequisites:

Related Examples:

Key Concepts Demonstrated

This example demonstrates:

  1. Multi-Component Architecture - Three-part design pattern for complex functionality
    • See Player Station Framework for component patterns
    • Unique aspect: Demonstrates shared message library used by both frontend and backend
  2. Custom Message Definition - Lua-based message generation for inter-component communication
    • Lua message definitions compiled into C++ classes at build time
    • Type-safe message passing between simulation and player station
  3. Frontend/Backend Coordination - Sensor simulation in backend with UI updates in frontend
    • Backend performs detection calculations and threat assessment
    • Frontend subscribes to detection reports and updates player UI
    • Separation of concerns between simulation fidelity and user experience
  4. Player Attribute Store Integration - Dynamic attribute management for detection state
    • Real-time updates of detection information
    • Attribute-based communication pattern for UI integration
  5. VR-Forces Entity Controller Pattern - Simulation-side entity behavior extension
    • Custom entity controller for radar sensor simulation
    • Integration with VR-Forces entity lifecycle and simulation loop

Architecture

This example is divided into three components that work together to provide radar detection capabilities. The entityDetectionShared component defines the DetectionReportMessage used by both frontend and backend. Lua message definitions are compiled into type-safe C++ message classes at build time, creating a shared library consumed by both other components. This component must be built and deployed first as it represents a dependency for the other two components.

The entityDetectionFrontend component runs in the vrEngage.exe process and implements the DtEntityDetectionControlLogic class. This component subscribes to detection messages, updates the player attribute store with detection information, and displays radar detections in the player UI.

The entityDetectionSim component runs as a VR-Forces entity controller in the simulation process. It implements the DtDetectionReportController class, which performs radar detection simulation, calculates threat vectors and closest munitions, and publishes detection reports to the frontend.

Message Flow: Simulation Sensor Logic → DetectionReportMessage → Message Manager → Frontend Component → Player Attribute Store → UI Display

Vehicle Configuration

A key aspect of this example is the modification of the LSV (Light Strike Vehicle) entity configuration to include a radar munition sensor system. The example SMS includes a custom LSV entity definition that adds the radar-munition-sensor.sysdef system.

The radar munition sensor (DtRadarMunitionSensor) is a specialized VR-Forces component designed to detect incoming munitions. It extends the standard radar object sensor with munition-specific detection algorithms and provides real-time threat assessment based on munition trajectory, velocity, and time-to-impact. This sensor serves as the data source for the detection report controller.

When the LSV entity is created, the radar munition sensor component initializes and continuously scans for incoming munitions within its detection parameters. The DtDetectionReportController queries the sensor's detected contacts list, formats the detection information into a DetectionReportMessage, and sends it to the frontend for display.

The modified LSV entity definition is located at data/simulationModelSets/examples/entityDetection/vrfSim/entities/examples/LSV_with_radar.entity and includes the system definition in its configuration:

(systems
(radar-munition-sensor "radar-munition-sensor.sysdef")
; ... other systems
)

The radar-munition-sensor system is configured with several key parameters. The Detection Range defines the maximum distance at which munitions can be detected. The Field of View specifies the angular coverage of the sensor, typically 360° for omnidirectional threat detection. The Update Rate controls the frequency at which the sensor updates its contact list. The Signature Sensitivity sets the threshold for munition detection based on radar cross-section.

This architecture demonstrates how VR-Forces system definitions can be composed to add capabilities to existing vehicle models without modifying the base entity definitions.

Code Walkthrough

Shared Message Definition

The detection report message is defined in Lua and generates C++ classes during the build process. The message definition includes structures for individual detection reports with contact information and position data, as well as top-level attributes for routing the message to the correct player station and identifying the closest threat.

// File: examples/entityDetection/entityDetectionShared/detectionReport.lua
MESSAGE{
fileName="detectionReportMessage";
className="DetectionReport";
messageType="detectionReport";
structs={
DetectionReport={
{type = "string", name = "contactName"};
{type = "EntityType", name = "contactType"};
{type = "Vector3d", name = "position"};
};
};
attributes={
{type = "EntityIdentifier", name = "sender"};
{type = "String", name = "closestMarkingText"};
{type = "List<DetectionReport>", name = "detectionReports"};
};
}

The VR-Engage message generation system processes these Lua definitions during the build, generating type-safe C++ message classes with appropriate accessors and serialization methods. The message includes sender identification for routing to the correct player station in multi-player scenarios, along with structured detection report data containing contact information and position.

Frontend Message Subscription

The frontend component registers its interest in detection messages during initialization. The component inherits from DtPlayerComponent and uses the standard initialization pattern to set up message handlers and player attribute store access.

// File: examples/entityDetection/entityDetectionFrontend/entityDetectionControlLogic.cxx
bool DtEntityDetectionControlLogic::initialize(DtPlayerStation* player, DtInitTable& config)
{
if (!DtPlayerComponent::initialize(player, config))
{
return false;
}
DtVreMessageManager::instance().addHandler(DetectionReportMessage::theType(),
return true;
}
virtual bool initialize(makVre::DtPlayerStation *player, makVre::DtInitTable &config) override
Configures message handlers and attribute store bindings.
makVre::DtAttributeHandle myRadarDetections
Definition entityDetectionControlLogic.h:37
makVre::DtVreMessageResult handleDetectionReport(makVre::DtVreMessage *msg)
Handles incoming detection report messages from the simulation backend.
virtual DtAttributeHandle & playerAttributeStore()
Gets the player attribute store.
virtual DtPlayerStation & player()
Gets the player station.

Message handler registration connects backend simulation events to frontend UI updates. The player attribute store provides the bridge between component logic and UI display, allowing QML interfaces or other display systems to bind directly to detection state. The delegate pattern enables type-safe callback handling while maintaining clean separation between the message system and component logic. Early initialization during the component lifecycle ensures messages are captured from the start of the simulation.

Detection Report Processing

When detection reports arrive from the backend, the frontend component processes them and updates the player attribute store. The message handler first verifies that the message is intended for this player station, then extracts detection information and updates the appropriate attribute store entries, including a list of detected munitions.

// File: examples/entityDetection/entityDetectionFrontend/entityDetectionControlLogic.cxx
{
ASSERT_TYPE(msg, DetectionReportMessage, rMsg);
// Make sure that this message is meant for our engaged entity.
if (rMsg->getSender() != player().entityId())
{
return IGNORED;
}
myRadarDetections["numberOfIncoming"]->set<int>(rMsg->getDetectionReports().size());
myRadarDetections["incomingMissile"]->set<bool>(rMsg->getDetectionReports().size() > 0);
myRadarDetections["closestName"]->set<std::string>(rMsg->getClosestMarkingText());
auto attrHandle = myRadarDetections["listOfMunitions"];
for (const auto& report : rMsg->getDetectionReports())
{
DtGeodeticCoord coord;
coord.setGeocentric(report.myPosition);
attrHandle[report.myContactName]->set<std::string>(coord.string().c_str());
}
return HANDLED;
}
bool set(const T &value)
Sets the value of the attribute.
Abstract base class for all VREngage messages.
Definition vreMessage.h:50
DtVreMessageResult
Enumeration of possible message handling results.
Definition vreMessage.h:33
@ HANDLED
The handler processed the message; continue processing.
Definition vreMessage.h:35
#define ASSERT_TYPE(msg, MsgType, msgCast)
Asserts that a message is of the expected type and casts it.
Definition vreMessageManager.h:205

Message routing ensures reports reach the correct player station in multi-player scenarios where multiple players may be active simultaneously. Player attribute store updates trigger UI refreshes automatically through the binding system, eliminating the need for manual UI update calls. The structured data extraction from detection reports allows different UI elements to display specific aspects of the threat information, such as total count, boolean threat indicator, closest threat identification, and a list of detected munitions. The return value indicates whether the message was handled by this component, allowing the message manager to track message processing and potentially route unprocessed messages to other handlers.

Backend Detection Controller

The simulation component performs radar detection calculations in its tick method, which is called regularly by the VR-Forces simulation loop. This component extends the entity controller pattern to add sensor simulation behavior to the controlled entity.

// File: examples/entityDetection/entityDetectionSim/detectionReportController.cxx
void DtDetectionReportController::tick()
{
// Check to see if the simulation is paused.
if (dT() == 0.)
{
return;
}
DetectionReportMessage* detectionReportMessage = DetectionReportMessage::create();
detectionReportMessage->setSender(entity()->entityId());
std::vector<DetectionReportMessage::DetectionReport> detectionReports;
std::string closestMarkingText;
double closestDistance = 1000000;
DtListItem* pItem = myFusedContactsList->first();
DtRwSensorContactInfo* pContactInfo = nullptr;
for (; pItem != nullptr; pItem = pItem->next())
{
pContactInfo = static_cast<DtRwSensorContactInfo*>(pItem->data());
if (pContactInfo && pContactInfo->isContactCurrentlyDetected() &&
pContactInfo->contactType().matchPattern(DtEntityType(2, -1, -1, -1, -1, -1, -1)))
{
DetectionReportMessage::DetectionReport report;
report.myContactName = pContactInfo->contact().string();
report.myContactType = pContactInfo->contactType();
report.myPosition = pContactInfo->contactPosition();
detectionReports.push_back(report);
double dist = DtDistance(entity()->nextFrameWorldPosition(), pContactInfo->contactPosition());
if (dist < closestDistance)
{
closestMarkingText = pContactInfo->contactMarkingText();
closestDistance = dist;
}
}
}
detectionReportMessage->setClosestMarkingText(closestMarkingText);
detectionReportMessage->setDetectionReports(detectionReports);
DtVreMessageManager::instance().queueMessage(detectionReportMessage);
}

Simulation logic runs in the backend for physics accuracy and proper network coordination with other simulation participants. The frontend receives processed detection results for immediate UI updates without needing to perform expensive sensor calculations in the player station process. Message-based decoupling allows independent evolution of simulation and display logic—changes to detection algorithms or sensor models don't require modifications to the UI code. The entity controller integrates seamlessly with the VR-Forces simulation loop, receiving regular tick calls and having access to entity state and the broader simulation environment.

VR-Forces Component Descriptor

The backend component uses a descriptor pattern for configuration, allowing simulation designers to customize sensor behavior without code changes.

// File: examples/entityDetection/entityDetectionSim/detectionReportControllerDescriptor.h
class DtDetectionReportControllerDescriptor : public DtComponentDescriptor
{
public:
void setUpdateInterval(double interval);
double updateInterval() const;
static DtComponentDescriptor* creator();
};

The descriptor pattern separates configuration from implementation, allowing parameters like update intervals to be adjusted through simulation model set definitions. The creator function enables factory-based component instantiation, which is essential for VR-Forces to dynamically create controllers as entities are spawned during simulation.

Deployment and Testing

Installation

Build the example following the Environment Setup & Build Guide. The three components must be built in dependency order, with the shared message library first:

cd examples\build
cmake --build . --config RelWithDebInfo --target entityDetectionShared
cmake --build . --config RelWithDebInfo --target entityDetectionFrontend
cmake --build . --config RelWithDebInfo --target entityDetectionSim

Install the plugins to the VR-Engage installation directory:

cmake --install . --config RelWithDebInfo

This copies the components to their appropriate locations. The frontend plugin installs to <VR-Engage-Install-Dir>\plugins64\vrEngage\release\exampleEntityDetectionFrontend.dll, the backend plugin to <VR-Engage-Install-Dir>\plugins64\vrForces\release\exampleEntityDetectionSim.dll, and the shared library to <VR-Engage-Install-Dir>\bin64\exampleEntityDetectionShared.dll.

Verify installation by checking for the installed files:

dir "<VR-Engage-Install-Dir>\plugins64\vrEngage\release\exampleEntityDetectionFrontend.dll"
dir "<VR-Engage-Install-Dir>\plugins64\vrForces\release\exampleEntityDetectionSim.dll"
dir "<VR-Engage-Install-Dir>\bin64\exampleEntityDetectionShared.dll"

Configuration

The example includes a pre-configured SMS (entityDetection.sms) that is already installed with VR-Engage at <VR-Engage-Install-Dir>\data\simulationModelSets\examples\entityDetection.sms. This SMS loads the backend detection controller and configures the necessary VR-Forces components for radar simulation. The SMS includes detection controller component descriptor registration, entity controller factory bindings, and simulation model set includes for base VR-Engage functionality.

Pre-Configured Test Entity:

The example provides a modified Light Strike Vehicle MK II (LSV) entity specifically configured with the radar munition sensor system. This entity is located at data/simulationModelSets/examples/entityDetection/vrfSim/entities/examples/vreLight Strike Vehicle MK II (LSV).entity and includes the radar-munition-sensor system definition required for detection functionality. The entity is available in VR-Forces when the entityDetection.sms is loaded.

Role Configuration:

The example includes a specialized driver role file that demonstrates detection component integration. The driverWithDetection.lua role file (located at data/simulationModelSets/examples/entityDetection/roles/driverWithDetection.lua) extends the standard driver role and adds two key components:

components = {
["warnOverlay"] = {
componentType = "DtQtQuickOverlay";
qmlFilename = "examples/incomingHUD.qml";
bindQmlPropertyToAttribute = {
incoming = "detections.incomingMissile";
closestMuni = "detections.closestName";
};
};
["entityDetectionControlLogic"] = {
componentType = "DtEntityDetectionControlLogic";
priority = 5;
};
}

The entityDetectionControlLogic component subscribes to detection messages and updates the player attribute store. The warnOverlay component binds detection state attributes to a QML-based HUD that displays incoming threat warnings. This demonstrates the complete integration pattern from backend sensor simulation through message passing to frontend UI display.

The example LSV entity references this role file for its "Driver" role, so when you engage the LSV as a driver, you automatically get the detection functionality and warning overlay.

To use the entity detection component in custom roles, add the entityDetectionControlLogic component group to your role configuration:

<role paramName="YourRole">
<componentGroup groupName="entityDetectionControlLogic"/>
<!-- other component groups... -->
</role>

Alternatively, create a Lua role file that inherits from a base role and adds the detection components similar to driverWithDetection.lua.

Testing Procedure

Launch VR-Engage with the entity detection SMS:

vrEngage.exe --setting "playerStationApp.defaultSimulationModelSets = {'data/simulationModelSets/examples/entityDetection.sms'};"

Creating a Test Scenario:

  1. Start an unhosted session or connect to a VR-Forces backend
  2. Create the test vehicle: In the entity creation palette, search for "Light Strike Vehicle MK II (LSV)" - this is the pre-configured entity with the radar munition sensor
  3. Select a role: Choose the "Driver" role, which uses the driverWithDetection.lua role configuration that includes the entityDetectionControlLogic component for detection processing and a QML-based warning overlay for displaying threat information
  4. Spawn incoming threats: Create munitions targeting your LSV entity to trigger the detection system. You can:
    • Use VR-Forces to launch missiles or projectiles toward your vehicle
    • Create hostile entities with weapons systems that can engage your vehicle
    • Use the VR-Forces scenario editor to set up pre-planned attack scenarios

Expected Behavior:

You should observe several behaviors indicating the system is working correctly. Detection reports appear in the player UI as threats approach your entity. The warning overlay displays incoming threat indicators with visual cues. The player attribute store reflects real-time detection counts, which you can verify through VR-Engage debug tools. The closest threat information displays with marking text identifying the threat. Detection state updates continuously during threat engagement, showing the dynamic nature of the sensor simulation.

As incoming munitions enter the detection range of the radar sensor, you should see:

  • Visual warning indicators in the QML overlay showing incoming threats
  • Detection count incrementing in the player attribute store (numberOfIncoming)
  • Boolean threat indicator activating (incomingMissile set to true)
  • Closest threat name displaying the marking text of the nearest detected munition
  • Real-time updates as threats approach and tracking updates occur

Technical Details

Dependencies: This example requires several VR-Engage framework libraries including vrePlayerStation for player component infrastructure, vreMessageManager for publish/subscribe messaging, VR-Forces simulation libraries (vrfmodel, vrfSimCore) for entity control logic, VR-Link network libraries (vl, vlutil) for DIS/HLA communication, and the Matrix library for coordinate transformations and spatial calculations.

Message Generation: The Lua message definitions are processed by the VR-Engage message generation CMake function during the build process. This generates C++ code with type-safe accessors, serialization methods, and factory registration. Message types are registered with DtVreMessageFactory at plugin load time, allowing the message manager to route messages correctly.

Build System Integration: The example uses a three-component build structure with explicit shared library dependency management. The CMake generateMessages() function processes Lua definitions into C++ source code. Plugin installation targets are configured for both frontend and backend deployment. Debug configurations are provided that launch VR-Engage with appropriate command-line settings for development testing.

File Structure:

Source layout (under the VR-Engage developer tree):

examples/entityDetection/
├── entityDetectionShared/ # Shared message definitions
│ ├── detectionReport.lua # Message definition in Lua
│ └── CMakeLists.txt # Build configuration
├── entityDetectionFrontend/ # Player station component
│ ├── entityDetectionControlLogic.h # Component header
│ ├── entityDetectionControlLogic.cxx # Component implementation
│ ├── plugin.cxx # Plugin registration
│ └── CMakeLists.txt # Build configuration
├── entityDetectionSim/ # Simulation backend component
│ ├── detectionReportController.h # Controller header
│ ├── detectionReportController.cxx # Controller implementation
│ ├── detectionReportControllerDescriptor.h # Descriptor header
│ ├── detectionReportControllerDescriptor.cxx # Descriptor implementation
│ ├── plugin.cxx # Plugin registration
│ └── CMakeLists.txt # Build configuration
└── README.md # This documentation

Installed data used by this example (under <VR-Engage-Install-Dir>):

<VR-Engage-Install-Dir>/data/simulationModelSets/examples/
├── entityDetection.sms # Simulation model set configuration
├── roles/
│ └── driverWithDetection.lua # Example role with detection
└── vrfSim/
└── entities/
└── examples/
└── vreLight Strike Vehicle MK II (LSV).entity