VR-Engage  2.2
Loading...
Searching...
No Matches
Role Configuration

Role configuration connects C++ components to the runtime system, enabling users to select roles from the engagement interface and allowing configuration without recompilation. This section covers role definition files, reusable configuration modules (often referred to as component groups), parameter systems, entity integration, and deployment patterns. Understanding role configuration is important for making toolkit extensions available to end users and for customizing existing roles to meet specific training requirements.

Role system architecture

The role system bridges compiled C++ components and runtime configuration through a layered architecture. At the lowest level, C++ components implement functionality. Reusable configuration modules ("component groups") organize related components into units that can be shared across roles. Role definition files assemble these modules and individual components into complete player experiences. Entity files bind roles to specific vehicle types and allow parameter customization. This layered approach enables maximum reuse while supporting vehicle-specific customization.

Layer File Type Contents
Entity .entity Entity definition, role bindings, parameter overrides
Role .lua Role definition, display layouts, includes, components table
C++ Components C++ DtDriverControlLogic, DtObserverUpdater, DtAudioUpdater, etc.

When a user engages an entity and selects a role, VR-Engage follows this resolution process: the entity file identifies available roles and their configuration sources, the role file specifies which reusable configuration modules to pull in and how to configure the display, those modules and the role file together enumerate the specific C++ components to create, and finally the framework instantiates each component with merged configuration from all layers. Parameter values flow down through the layers, with entity-level overrides taking precedence over role defaults, which take precedence over component defaults.

Role definition and composition

This section covers the file formats and mechanisms for defining roles: role definition files, reusable component groups, and how the loader composes them into complete configurations.

Role definition files

Role definition files are Lua scripts located in data/simulationModelSets/VR-Engage/roles/. Each file defines a complete role configuration including display layouts, component instantiation, and default parameter values. The Lua format enables conditional logic, includes, and computed values while remaining human-readable.

Basic role structure

A minimal role file specifies the components required for the role and at least one display layout. The components table lists component entries that reference registered C++ component types. Each entry can include parameters that override component defaults.

-- filepath: data/simulationModelSets/VR-Engage/roles/myDriver.lua
--
-- Custom driver role for ground vehicles
--
displayLayouts = {
["1 Screen Horizontal"] = {
channelLayout = {
{ name = "main"; x = 0; y = 0; width = 1; height = 1 };
};
};
};
components = {
-- Control logic for driver input processing
["controlLogic"] = {
componentType = "DtDriverControlLogic";
inputConfigFile = "driverInput.lua";
joystickFunctionGroups = {"Driver"};
mouseControlSupport = true;
};
-- Observer for camera control
["observerUpdater"] = {
componentType = "DtDriverObserverUpdater";
};
-- Audio feedback
["engineAudio"] = {
componentType = "DtEngineAudioUpdater";
masterVolume = 0.8;
};
};

The componentType field references the type name registered with the component factory during plugin initialization. This name must match exactly—the framework performs a case-sensitive lookup in the factory registry. Other fields in the component entry become configuration parameters passed to the component's initialize() method through the DtInitTable. For a detailed description of component lifecycle and initialization, see Player Station Framework.

Display layouts

Display layouts define how the visual output is organized across physical displays. Each layout specifies one or more channels with their screen positions and dimensions. Layouts support both single-monitor desktop configurations and multi-display setups for full-dome or multi-projector systems.

-- filepath: data/simulationModelSets/VR-Engage/roles/pilotMultiscreen.lua
displayLayouts = {
["1 Screen Horizontal"] = {
channelLayout = {
{ name = "main"; x = 0; y = 0; width = 1; height = 1 };
};
};
["3 Screen Horizontal"] = {
channelLayout = {
{ name = "left"; x = 0.0; y = 0; width = 0.333; height = 1; fovOffset = -45 };
{ name = "center"; x = 0.333; y = 0; width = 0.334; height = 1; fovOffset = 0 };
{ name = "right"; x = 0.667; y = 0; width = 0.333; height = 1; fovOffset = 45 };
};
};
["VR Headset"] = {
channelLayout = {
{ name = "hmd"; x = 0; y = 0; width = 1; height = 1; stereo = true };
};
vrEnabled = true;
};
};

Channel names are referenced by overlay configurations and observer updaters. Channels are a VR-Vantage concept that map rendering viewports to screen regions; VR-Engage role configurations use them to control how the 3D view is displayed. The fovOffset parameter adjusts the field of view for peripheral displays in multi-monitor setups. The stereo flag enables stereoscopic rendering for VR headsets. VR-Engage selects the appropriate layout based on user preference and hardware detection.

Including shared configuration

Roles often share common functionality like radio systems or action menus. The includes table specifies additional Lua files to load and merge into the role configuration. This promotes reuse and ensures consistency across roles that share capabilities.

-- filepath: data/simulationModelSets/VR-Engage/roles/tankDriver.lua
includes = {
"@(vre-roles-dir)/devices/radio.vehicle.lua";
"@(vre-roles-dir)/common/actionMenu.lua";
"@(vre-roles-dir)/common/notifications.lua";
};
components = {
-- Role-specific components
["controlLogic"] = {
componentType = "DtDriverControlLogic";
inputConfigFile = "driverInput.lua";
};
-- Components from includes are merged automatically
};

The path macro @(vre-roles-dir) resolves to the roles directory within the active simulation model set. Using this macro ensures paths remain valid across different installation locations.

Included files follow the same structure as role files. When files are included, their components entries merge with the including file's entries. If the same component name appears in multiple files, the including file's values take precedence. This enables included files to provide defaults that roles can override.

-- filepath: data/simulationModelSets/VR-Engage/roles/devices/radio.vehicle.lua
--
-- Shared radio configuration for vehicle roles
--
components = {
["radioLogic"] = {
componentType = "DtRadioLogic";
defaultFrequency = 30.0;
maxFrequency = 512.0;
minFrequency = 30.0;
presetCount = 10;
};
["radioAudio"] = {
componentType = "DtRadioAudioUpdater";
staticVolume = 0.3;
receiveVolume = 0.8;
};
};

Overlay configuration

Roles specify QML and GL Studio overlays that provide heads-up displays, instrument panels, and other visual feedback. Overlay configuration associates QML files with display channels and provides initial property values.

-- filepath: data/simulationModelSets/VR-Engage/roles/pilotWithHud.lua
components = {
["hudOverlay"] = {
componentType = "DtQtQuickOverlay";
qmlFile = "HUDS/pilotHud.qml";
channel = "main";
visible = true;
properties = {
showAltitude = true;
showAirspeed = true;
showHeading = true;
hudColor = "#00FF00";
};
};
["hudMapper"] = {
componentType = "DtGlStudioHudMapperLogic";
modelDefinitions = {"f16_instruments"};
};
};

The qmlFile path is resolved relative to the data/UI folder within the installation directory. For example, "HUDS/pilotHud.qml" resolves to data/UI/HUDS/pilotHud.qml.

The properties table provides initial values for QML properties exposed by the overlay. These values are accessible through the QML context and can be bound to UI elements. Changes to property values at runtime automatically update bound UI elements through Qt's property binding system.

Component groups

In the runtime system there is no special "componentGroup" keyword or type. Instead, component groups are a documentation term for reusable Lua files that export shared components tables. These files are pulled into roles through the standard include and merge mechanism, and their components become part of the role just like locally defined components.

Defining component groups

Component groups are defined in Lua files within the simulation model set. Each file exports a components table that specifies the components it contains and their default configurations. By convention, these files live in the roles/devices/ directory, though they can be placed anywhere as long as the role's includes table references the correct path.

-- filepath: data/simulationModelSets/VR-Engage/roles/devices/driverControlLogic.lua
components = {
["controlLogic"] = {
componentType = "DtDriverControlLogic";
inputConfigFile = "driverInput.lua";
joystickFunctionGroups = {"Driver"};
mouseControlSupport = true;
};
["observerUpdater"] = {
componentType = "DtDriverObserverUpdater";
};
["engineAudio"] = {
componentType = "DtEngineAudioUpdater";
masterVolume = 0.7;
};
};

Component groups are typically consumed via the role's includes table. The loader script (data/factory/scripts/loadDefinition.lua) reads the role file, loads each included Lua file with loadTableFile(), and merges the resulting tables with mergeDefinitions(). Any components entries from included files are merged into the role's own components table.

-- filepath: data/simulationModelSets/VR-Engage/roles/tankDriver.lua
includes = {
"@(vre-roles-dir)/devices/driverControlLogic.lua";
"@(vre-roles-dir)/devices/vehicleAudio.lua";
"@(vre-roles-dir)/devices/actionMenu.lua";
};
components = {
-- Additional role-specific components declared directly in the role
["thermalSight"] = {
componentType = "DtThermalSightUpdater";
enabled = true;
};
};

Parameters specified directly in the role file override parameters from included component group files. This enables roles to customize shared behavior without modifying the group definitions.

How composition is implemented

Role composition is implemented entirely in Lua by the loader script (data/factory/scripts/loadDefinition.lua). There is no special file format or runtime type for component groups; everything is regular Lua tables that get merged together.

At a high level, the loader:

  1. Resolves the role file path using resolvePath(), which expands macros like @(vre-roles-dir) and searches the active simulation model set paths.
  2. Loads the role file as a Lua table with loadTableFile().
  3. Processes includes via mergeExternalIncludeFiles(), which loads each included Lua file and merges its contents into the role definition with mergeDefinitions().
  4. Walks any inherits chain to build an inheritance list of role definitions, applying mergeExternalIncludeFiles() and expandExternalDisplayFiles() to each parent.
  5. Starts from an empty role table and repeatedly calls mergeDefinitions() to merge each definition from the inheritance chain, combining appModes, roles, displayLayouts, menuConfig, components, and connectors according to well-defined rules.

The result of this process is a fully composed role definition that the runtime uses as the source for creating player configurations.

When a player is actually created, getPlayerConfiguration() clones the composed role definition into a player table, applies any display layout and parameter overrides, sorts menus and components, and then returns the final configuration to C++.

When role definition debugging is enabled, getPlayerConfiguration() also calls savePlayerDefinition(), which serializes the fully composed player table and writes it to a debug folder under the roles directory ($(vre-roles-dir)/debug). These files are regular Lua tables and are the easiest way to see the exact set of components, menus, and parameter values that will be instantiated at runtime for a given role and display layout.

Role parameters

The role parameter system enables runtime configuration of component behavior without recompilation. Parameters can be overridden at multiple levels of the configuration hierarchy and are read during component initialization.

Reading parameters during initialization

Components read parameters from the DtInitTable passed to their initialize() method. The table contains merged values from all configuration layers with appropriate precedence.

// filepath: src/roles/driverControlLogic.cxx
#include "roles/driverControlLogic.h"
bool DtDriverControlLogic::initialize(DtPlayerStation* player, DtInitTable& config)
{
if (!DtEntityControlLogic::initialize(player, config))
{
return false;
}
// Read parameters with defaults matching the vreRoleParam declarations
myShowSpeedometer = config.findDataOr<bool>(
DriverControlLogicConfig::showSpeedometer, true);
myShowInclinometer = config.findDataOr<bool>(
DriverControlLogicConfig::showInclinometer, false);
myMaxSpeed = config.findDataOr<double>(
DriverControlLogicConfig::maxSpeed, 100.0);
myEnableCruiseControl = config.findDataOr<bool>(
DriverControlLogicConfig::enableCruiseControl, true);
mySteeringDeadzone = config.findDataOr<double>(
DriverControlLogicConfig::steeringDeadzone, 0.05);
// Initialize state attributes for UI binding
initializeStateAttributes();
return true;
}
void DtDriverControlLogic::initializeStateAttributes()
{
DtPlayerAttributeStore& attrs = playerStation()->playerAttributeStore();
// Publish configuration as state attributes for overlay access
attrs.setAttribute<bool>("driver/showSpeedometer", myShowSpeedometer);
attrs.setAttribute<bool>("driver/showInclinometer", myShowInclinometer);
attrs.setAttribute<double>("driver/maxSpeed", myMaxSpeed);
}
Defines the DtPlayerStation class for managing engaged roles.

The default values in findDataOr<bool>(), findDataOr<double>(), and similar templated methods should match the defaults declared in the \vreRoleParam tags. This ensures consistent behavior whether the parameter is explicitly configured or uses the default.

Parameter type reference

The configuration system supports several data types with corresponding lookup methods:

Type Lua Syntax C++ Lookup Method Example
bool true / false findDataOr<bool>() enabled = true
int 42 findDataOr<int>() count = 10
double 3.14 findDataOr<double>() speed = 55.5
float 1.5 findDataOr<float>() scale = 1.0
string "text" findDataOr<std::string>() name = "Player"
table { ... } findDataOr<DtInitTable>() options = { a = 1 }

String parameters require quotes in Lua configuration. Numeric values can be integers or floating-point. Boolean values are the Lua keywords true and false (lowercase). Tables enable structured configuration for complex parameters.

Entity integration

Entity files bind roles to specific vehicle types and enable per-vehicle parameter customization. The <vrEngageRoles> section within an entity definition specifies which roles are available when engaging that entity type and how those roles should be configured.

Role binding in entity files

The entity file's role section lists available roles with their configuration sources and display options.

<!-- filepath: data/simulationModelSets/VR-Engage/vrfSim/vreLeopard 2A4.entity -->
<vrEngageRoles>
<role paramName="Commander" slotName="Commander" defaultDisplayLayout="1 Screen Horizontal">
<parameterOverride paramName="observerUpdater.attachOffset">{x = 0.1, y = -0.7, z = 1.5}</parameterOverride>
@(vre-roles-dir)/commanderHatch.lua</role>
<role paramName="Driver" slotName="Driver" defaultDisplayLayout="1 Screen Horizontal">
<parameterOverride paramName="savedViewUpdater.initialView">"1 - Driver View"</parameterOverride>
<parameterOverride paramName="savedViewUpdater.savedViews">"@(vre-roles-dir)/savedViews/Leopard2A4Views.osrx"</parameterOverride>
@(vre-roles-dir)/tankDriver.lua</role>
<role paramName="Gunner" slotName="Gunner" defaultDisplayLayout="1 Screen Horizontal">
<parameterOverride paramName="controlLogic.joystickFunctionGroups">{"Gunner Input"}</parameterOverride>
<parameterOverride paramName="controlLogic.systemName">"weapon"</parameterOverride>
@(vre-roles-dir)/tankGunner.lua</role>
</vrEngageRoles>

Role binding attributes control how the role appears in the engagement interface:

Attribute Purpose Example
paramName Display name in role selection UI "Driver"
slotName Internal slot identifier for multi-crew coordination "Driver"
unlisted Hide from role selection (for internal roles) "false"
defaultDisplayLayout Initial display configuration "1 Screen Horizontal"

The role file path uses the @(vre-roles-dir) macro to locate the role definition within the simulation model set. The path is relative to the macro expansion point.

Parameter overrides

Parameter overrides enable vehicle-specific customization without creating separate role files. Each <parameterOverride> element specifies a component name, parameter name, and new value using dot notation.

<parameterOverride>
componentName.parameterName = value
</parameterOverride>

The component name corresponds to the key in the role file's components table. The parameter name matches the configuration namespace constant. Values follow Lua syntax appropriate for the parameter type.

<!-- Boolean override -->
<parameterOverride>
driverControl.enableCruiseControl = false
</parameterOverride>
<!-- Numeric override -->
<parameterOverride>
driverControl.steeringDeadzone = 0.1
</parameterOverride>
<!-- String override -->
<parameterOverride>
hudOverlay.hudColor = "#FF0000"
</parameterOverride>

Multiple overrides can target the same component. Overrides are processed in order, with later overrides taking precedence if the same parameter is specified multiple times.

Parameter precedence

When the same parameter is configured at multiple levels, the system applies a clear precedence order (highest to lowest):

  1. Entity parameterOverride — values in <parameterOverride> elements
  2. Role components table — values in the role file's components entries
  3. Component group Lua — values from component group files
  4. Included Lua files — values from other included files
  5. C++ default value — fallback specified in component code

Entity-level overrides have the highest precedence, enabling vehicle-specific tuning without modifying shared role files. C++ default values serve as the fallback when no configuration specifies a value. This layered approach balances standardization with customization flexibility.

Multi-crew coordination

VR-Engage supports multi-crew vehicles where multiple players occupy different roles on the same entity. The role system coordinates crew positions through slot assignments and provides mechanisms for switching between roles.

Slot assignments

Each role in an entity file can specify a slotName attribute that corresponds to an embarkation slot defined in the entity's <embarkationSlots> configuration. When a player engages an entity in a particular role, VR-Engage associates them with that slot. Two players can concurrently play different roles on the same vehicle—for example, one player as Driver and another as Gunner or Commander.

<!-- filepath: data/simulationModelSets/VR-Engage/vrfSim/vreGTK Boxer CRV.entity -->
<vrEngageRoles>
<role paramName="Commander" slotName="Seat 3" defaultDisplayLayout="1 Screen Horizontal">
<!-- Parameter overrides and role file reference -->
@(vre-roles-dir)/metaRole.lua
</role>
<role paramName="Driver" slotName="Seat 1" defaultDisplayLayout="1 Screen Horizontal">
@(vre-roles-dir)/boxerDriver.lua
</role>
<role paramName="Gunner" slotName="Seat 2" defaultDisplayLayout="1 Screen Horizontal">
@(vre-roles-dir)/boxerGunner.lua
</role>
</vrEngageRoles>

The slotName values reference embarkation slots defined elsewhere in the entity file. When a player embarks on a vehicle while playing a human character, VR-Engage presents available roles based on these slot configurations. For details about embarkation configuration, see Embarkation Configuration and "Appendix B. Embarkation Slot Configuration in VR-Engage" in the VR-Engage User Guide.

Role switching

Players can switch between available roles on their current vehicle without returning to the Choose Role panel. Ground vehicles configured with multiple roles allow players to change roles while embarked using the Action Menu or keyboard shortcuts ([ for previous role, ] for next role).

For end-user procedures, see "3.4.3 Switching Roles on a Vehicle" in the VR-Engage User Guide.

Meta-roles

Meta-roles combine multiple related sub-roles into a single logical role that players can select from the Choose Role panel. Once engaged in a meta-role, players can quickly switch between sub-roles using keyboard shortcuts without returning to the role selection interface.

For example, the GTK Boxer CRV Commander role is a meta-role containing Commander Hatch and Commander Sight sub-roles. Players toggle between these positions with a single key press.

<!-- filepath: data/simulationModelSets/VR-Engage/vrfSim/vreGTK Boxer CRV.entity -->
<role paramName="Commander" slotName="Seat 3" defaultDisplayLayout="1 Screen Horizontal">
<parameterOverride paramName="metaRoleControl.inputConfigFile">"commanderInput.lua"</parameterOverride>
<parameterOverride paramName="metaRoleControl.inputConfigGroup">"commander"</parameterOverride>
<parameterOverride paramName="metaRoleControl.nextSubRoleBinding">"toggle-sight-hatch"</parameterOverride>
<parameterOverride paramName="metaRoleControl.subRoles">{ "Commander Hatch", "Commander Sight" }</parameterOverride>
@(vre-roles-dir)/metaRole.lua
</role>
<role paramName="Commander Hatch" unlisted="True" defaultDisplayLayout="1 Screen Horizontal">
<!-- Sub-role configuration -->
@(vre-roles-dir)/commanderHatch2.lua
</role>
<role paramName="Commander Sight" unlisted="True" defaultDisplayLayout="1 Screen Horizontal">
<!-- Sub-role configuration, which may itself be a meta-role -->
@(vre-roles-dir)/metaRole.lua
</role>

The DtMetaRoleControlLogic component manages sub-role switching. It instantiates player station instances for each sub-role and provides input bindings to cycle between them:

Parameter Purpose
inputConfigFile Path to input configuration for meta-role bindings
inputConfigGroup Input group name within the config file
nextSubRoleBinding Input action name for switching to the next sub-role
subRoles Array of sub-role names this meta-role can switch between

Sub-roles are marked with unlisted="True" so they don't appear separately in the role selection interface. Meta-roles can be nested—a sub-role can itself be a meta-role with its own sub-roles, enabling hierarchical role structures.

For end-user documentation on meta-roles, see "Chapter 14. Adding and Editing VR-Engage Entity Models" in the VR-Engage User Guide.

Deployment and best practices

This section covers file organization, deployment patterns, and recommended practices for role configuration.

Deployment

Role configurations depend on consistent file organization and correct path resolution to load properly across different installations.

File organization

Role-related files are organized within the simulation model set directory structure:

data/simulationModelSets/VR-Engage/
├── roles/
│ ├── tankDriver.lua
│ ├── tankGunner.lua
│ ├── tankCommander.lua
│ ├── common/
│ │ ├── actionMenu.lua
│ │ └── notifications.lua
│ └── devices/
│ ├── radio.vehicle.lua
│ ├── radio.dismount.lua
│ ├── driverControlLogic.lua
│ └── gunnerControlLogic.lua
├── input/
│ ├── driverInput.lua
│ ├── gunnerInput.lua
│ └── commonInput.lua
└── vrfSim/
├── vreM1A2_Abrams.entity
└── vreLAV_III.entity

Role definitions live in the roles/ directory. Shared configuration modules are grouped in subdirectories such as common/ for general-purpose includes and devices/ for component group files. Input configuration files are stored separately in input/. Entity files that reference roles are located in vrfSim/.

QML overlay files are not stored in the simulation model set. They are located in the data/UI folder within the installation directory, as described in the Overlay configuration section.

Path macros

The @(vre-roles-dir) macro resolves to the roles directory within the active simulation model set (for example, data/simulationModelSets/VR-Engage/roles/). Use this macro in role file includes and inherits paths to ensure portability across installations.

Avoid using absolute paths in configuration files. Absolute paths break when installations are moved or when configurations are shared between machines.

Validation and testing

Before deploying role configurations, verify correct operation:

  1. Syntax validation: Load the role in VR-Engage and check for Lua parse errors in the log
  2. Component instantiation: Verify all components create successfully by checking for initialization errors
  3. Parameter binding: Confirm parameters reach components by logging values during initialization
  4. Display layout: Test each display layout configuration works correctly
  5. Input mapping: Verify all input actions trigger expected behavior
  6. Override precedence: Test that entity-level overrides correctly supersede role defaults

The VR-Engage log file contains detailed information about role loading, including parameter resolution and component instantiation. Enable verbose logging during development to diagnose configuration issues.

User Guide reference

For end-user documentation on available roles, entity configurations, and role selection procedures, see "Chapter 14. Adding and Editing VR-Engage Entity Models" in the VR-Engage User Guide.

Best practices

Effective role configuration balances reusability, maintainability, and vehicle-specific customization. Following these practices helps create configurations that are easy to understand, modify, and extend.

Maximize reuse through includes: Extract common functionality into shared include files. Radio configurations, action menus, and notification systems typically work identically across multiple roles. Creating shared files for these capabilities reduces duplication and ensures consistent behavior.

Use component groups for related components: Group components that work together into named component groups. This simplifies role definitions and makes it easier to update related components consistently. A "driverControlLogic" group might include the control logic, observer updater, and audio updater that together provide the complete driver experience.

Document all parameters: Every configurable parameter should have a corresponding \vreRoleParam declaration with a clear description. This documentation appears in the generated reference and helps users understand configuration options without examining source code.

Provide sensible defaults: Default parameter values should produce reasonable behavior for typical use cases. Users should only need to override parameters when they want non-standard behavior. Test roles with all defaults to ensure they work correctly out of the box.

Prefer parameter overrides to role duplication: When customizing roles for specific vehicles, use entity-level parameter overrides rather than creating separate role files. This keeps the number of role files manageable and ensures updates to the base role propagate to all vehicles using it.

Test across display configurations: Roles should work correctly with different display layouts. Test with single-monitor, multi-monitor, and VR configurations to ensure overlays position correctly and components handle different rendering scenarios.

See also