The Navigraph Navigation Data Interface enables developers to download and integrate navigation data from Navigraph directly into add-on aircraft in MSFS.
- Navigraph DFD Format: Leverage specialized support for Navigraph's DFD format, based on SQLite, which includes an SQL interface on the commbus for efficient data handling.
- Javascript and WASM support: The navdata interface is accessible from both Javascript (Coherent) and WASM, providing flexibility for developers.
- Supports updating of custom data formats.
- Xbox compatibility: Works on PC and Xbox.
- Persistence: All data is persisted in the
work
folder of the aircraft.
Here's an overview on the structure of this repository, which is designed to be as simple as possible to use
examples/
- Contains sample implementations for using the navigation data interface
aircraft/
includes a base aircraft to test in the simgauge/
includes a very simple TypeScript instrument to communicate with the WASM module
src/
database
Includes rust source code for interfacing with a DFD sqlite file (not WASM specific)js
Includes source code for the JS interface for using the sdktest
Includes code for testing the JS and Rust code using a Node runtimewasm
includes the Rust source code for the WASM module which handles the downloading of the database file, and interfacing with the database implementation
- You'll need to either build the WASM module yourself (not recommended, but documented further down) or download it from the latest release (alternatively you can download it off of a commit by looking at the uploaded artifacts).
- Add the WASM module into your
panel
folder inPackageSources
- Add the following entry into
panel.cfg
(make sure to replaceNN
with the properVCockpit
ID):[VCockpitNN] size_mm=0,0 pixel_size=0,0 texture=NO_TEXTURE htmlgauge00=WasmInstrument/WasmInstrument.html?wasm_module=msfs_navigation_data_interface.wasm&wasm_gauge=navigation_data_interface,0,0,1,1
- Note that if you already have a
VCockpit
withNO_TEXTURE
you can just add anotherhtmlgauge
to it, while making sure to increase the index
- Note that if you already have a
If you bundle outdated navigation data in your aircraft and you want this module to handle updating it for users with subscriptions, place the navigation data into the NavigationData
directory in PackageSources
. You can see an example here
The default location for navigation data is work/NavigationData
. If you have bundled navigation data, its located in the NavigationData
folder in the root of your project. (although it gets copied into the work
directory at runtime)
Before building, make sure you have properly created and set an .env
file in examples/gauge
! An example can be found in the .env.example
file in that directory. Replace with your credentials
- Download and install Node.js
- Open the
msfs-navigation-data-interface
folder in a terminal - Run
npm i
the first time you build, in order to install dependencies - Change directory to
src/js
usingcd src/js
- Run
npm run build
to build the interface. - Change directory to
examples/gauge
usingcd ../../examples/gauge/
- Run
npm run build
to build into thePackageSources
folder of the aircraft sample (ornpm run dev
to build into thePackages
folder of the aircraft and listen to changes in the source). - Make sure the WASM module is included in the
panel
folder! Look at either Including in Your Aircraft or Building the WASM Module Yourself for info on that - Open the
examples/aircraft/NavigationDataInterfaceAircraftProject.xml
file in the simulator and build there
- Download Docker Desktop
- Run
npm run build:wasm
(must be on Windows)- This will take a while to download and build the first time, but subsequent runs will be quicker
- The compiled WASM module will be copied to
out
andexamples/aircraft/PackageSources/SimObjects/Airplanes/Navigraph_Navigation_Data_Interface_Aircraft/panel
The navigation data interface acts as its own WASM gauge in sim, so in order to communicate with it, you must use the CommBus.
The gauge communicates using the following event names:
(Any types referenced can be found in wasm/src/json_structs.rs
)
NAVIGRAPH_CallFunction
: This event is received by the interface and is used to trigger one of the interfaces functions. It takes in arguments of typeCallFunction
. The available functions and their expected parameters can be found in thejson_structs.rs
fileNAVIGRAPH_FunctionResult
: This event is sent by the interface as a response to a previously triggered function. Its result will have the typeFunctionResult
, with the data field containing the expected return type of the function.NAVIGRAPH_Event
: This event is sent by the interface to give indications of progress or that the interface is running correctly.
Below is an example of communicating with the interface in JS. (We provide a JS wrapper, the code below is just a basic example to show how it works). Please read the CommBus documentation to determine how to interface with CommBus in your chosen language. src/js
contains our JS wrapper, it is also a useful example for implementing a fully fleshed out wrapper.
const queue = []
const listener = RegisterCommBusListener(() => {
listener.on("NAVIGRAPH_FunctionResult", jsonArgs => {
const args = JSON.parse(jsonArgs)
// When a FunctionResult is received, find the item in queue which matches the id, and resolve or reject it
const queueItem = queue.find(m => m.id === args.id)
if (queueItem) {
queue.splice(queue.indexOf(queueItem), 1)
const data = args.data
if (args.status === FunctionResultStatus.Success) {
queueItem.resolve(data)
} else {
queueItem.reject(new Error(typeof data === "string" ? data : "Unknown error"))
}
}
})
}) // RegisterCommBusListener is a function provided by sim
function getAirport(ident) {
const id = Utils.generateGUID() // Utils is a class provided by sim
const args = {
function: "GetAirport", // The name of the function being called
id, // CallFunctions and FunctionResults are tied together with the id field
data: {
// The parameters of the function
ident,
},
}
listener.callWasm("NAVIGRAPH_CallFunction", JSON.stringify(args))
return new Promise((resolve, reject) => {
queue.push({
id,
resolve: response => resolve(response),
reject: error => reject(error),
})
})
}
function executeSql(sql, params) {
const id = Utils.generateGUID() // Utils is a class provided by sim
const args = {
function: "ExecuteSQLQuery", // The name of the function being called
id, // CallFunctions and FunctionResults are tied together with the id field
data: {
// The parameters of the function
sql,
params,
},
}
listener.callWasm("NAVIGRAPH_CallFunction", JSON.stringify(args))
return new Promise((resolve, reject) => {
queue.push({
id,
resolve: response => resolve(response),
reject: error => reject(error),
})
})
}