Interaction with MSFS
This section explains the mechanism prepared to control Microsoft Flight Simulator (MSFS) from fsmapper.
Basic Concept
The functionality prepared by fsmapper for integration with MSFS serves to achieve two main objectives.
- Reflect the operations of external devices or similar on the various controls within the cockpit of aircraft in MSFS.
- Mirror the status of cockpit instruments onto external devices or similar.
These actions are similar to what aircraft mod creators for MSFS do when defining behaviors for the cockpit's 3D models:
- Reflecting mouse or controller operations onto the simulator's internal state or cockpit animations.
- Reflecting the simulator's internal state onto gauge needle angles or lamp status.
As mentioned in the Microsoft Flight Simulator SDK documentation, in MSFS, these actions are defined in the XML <Behaviors>
element, linking components to their internal states using Reverse Polish Notation (RPN).
fsmapper leverages the MobiFlight WASM Module to execute RPN through execute_calculator_code()
in the Gauge API. This enables Lua scripts to describe what aircraft mods are performing internally within MSFS.
Moving forward, the explanation on altering the internal state of MSFS from Lua scripts and retrieving the internal state of MSFS using Lua Scripts will be provided.
When the initial version of fsmapper was launched in 2021, interaction with the internal state of MSFS was done through SimVars and Event IDs. Although functions for these interactions are still retained for compatibility with legacy scripts, it is not recommended to use them. Interactions via RPN are much more flexible and cover a broader range.
This section does not provide explanations for these deprecated functions.
Changing MSFS's Internal State
fsmapper provides the function msfs.mfwasm.execute_rpn()
to run RPN within MSFS and msfs.mfwasm.rpn_executer()
to generate a native-action for executing RPN.
Here's a code snippet that increases the VOR1 OBI setting by 10 degrees in many aircraft.
mapper.mfwasm.execute_rpn('(>K:VOR1_OBI_FAST_INC)')
Although RPN itself is very powerful in terms of expressive capability,
due to the limitations of execute_calculator_code()
in the Gauge API,
it cannot access B variables, meaning it cannot get or set values from an Input Event. fsmapper provides separate functions for setting value of an Input Event (i.e., issuing an Input Event).
For details on how to issue an Input Event, refer to Issuing an Input Event.
Retrieving MSFS's Internal State
fsmapper provides a mechanism to monitor the evaluated values of RPN and notify any changes in values as Events for referencing the internal state of MSFS.
You can register the monitored RPN expressions by specifying an array of tables following the definitions below in msfs.mfwasm.add_observed_data()
.
Key | Type | Description |
---|---|---|
event | number | Event ID for the event triggered when the monitored data changes |
rpn | string | RPN expression representing the monitored data |
initial_value | number | The initial value of the monitored data. fsmapper trigers an event with the initial value as the Event Value. This parameter is optional. The default is 0 . |
epsilon | number | If the change in the monitored data does not exceed this value, no event will be triggered. Choosing an appropriate value helps prevent unnecessary event generation, reducing system load. This parameter is optional. The default is 0 |
The following code snippet enables notification of changes in the aircraft's heading as the HEADING event, and the corresponding action can display the heading in the message console.
local hdg_event = mapper.register_event('HEADING')
msfs.mfwasm.add_observed_data{
{
event = hdg_event,
rpn='(A:HEADING INDICATOR, Degrees)',
epsilon=0.5
}
}
mapper.add_primary_mappings{
{
event = hdg_event,
action = function (event_id, value)
mapper.print('Heading: ' .. value)
end
}
}
Issueing an Input Event
Input Events is a system in MSFS used to define the behavior of cockpit interactable objects when accessed with a mouse. While it is possible to implement cockpit behavior without defining Input Events, in most cases, Input Events are defined for each type of interaction with objects such as switches and knobs.
Therefore, using Input Events to link the operations of physical devices or virtual cockpit controls with the operations in the MSFS cockpit is a logical strategy.
However, due to the limitations of execute_calculator_code()
in the Gauge API, RPN scripts that issue Input Events do not function correctly.
To address this, fsmapper provides separate functions for issuing an Input Event.
Similar to the functions for executing RPN, there is msfs.execute_input_event()
for issuing an Input Event and msfs.input_event_executer()
which returns the Native Event for issuing an Input Event.
-- definition of event-action mappings to issue Input Events
local mappings = {
{
event = joystick.button1.down,
action = function () msfs.execute_input_event('LIGHTING_LANDING_0', 1) end,
},
{
event = joystick.button2.down,
action = msfs.input_event_executer('LIGHTING_LANDING_0', 0),
},
}