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.
- Xbox compatibility: Works on PC and Xbox.
- Persistence: All data is persisted in the
work
folder of the aircraft.
example/
aircraft/
includes a base aircraft to test in the simgauge/
includes a very simple TypeScript instrument to communicate with the WASM module
src/
ts
includes source code for the JS interface for interfacing with the WASM modulewasm
includes the Rust source code for the WASM module which handles the downloading of the database file, and interfacing with the database
-
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
-
Optional: Create a
Navigraph/config.json
file to provide additional metadata at runtime. This info will be reported to us should any error occur in the library, enabling us to directly reach out to you (the developer) to help track down the issue.- The file must follow this format:
{ "addon": { "developer": "Navigraph", "product": "Sample Aircraft" } }
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 Navigraph/BundledData
directory in PackageSources
. You can see an example here
The navigation data interface will automatically use this database by default, making it immediately available on startup.
The default location for navigation data is work/NavigationData
.
Note
This project is only meant to be tested in MSFS2020. We will add an example for MSFS2024 in the future.
Important
Before building, make sure you have properly created and set an .env
file in example/gauge
! An example can be found in the .env.example
file in that directory. Replace with your credentials.
- Download and install Bun
- Open this repository in a terminal
- Run
bun i
the first time you build, in order to install dependencies - Change directory to
example/gauge
usingcd example/gauge
- Run
bun run build
to build into thePackageSources
folder of the aircraft sample (orbun 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 instructions - Open the
example/aircraft/NavigationDataInterfaceAircraftProject.xml
file in the simulator and build there
- Create a
.env
file in the root of this repository, containing aSENTRY_URL
variable. Provide your own DSN, or leave it empty. - Run
bun run build:wasm
at the root of the repository (requires Docker)- 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
dist/wasm
. There will be two folders -2020
and2024
, for each sim version
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 (all types referenced can be found here):
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 thesrc/ts
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. Please read the CommBus documentation to determine how to interface with CommBus in your chosen language. src/ts
contains our JS wrapper, it is also a useful example for implementing a fully fleshed out wrapper.
Important
We provide a JS wrapper that handles this for you. The below is just a quick look at how it works.
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),
});
});
}