Skip to content

Commit

Permalink
airports
Browse files Browse the repository at this point in the history
  • Loading branch information
Pomax committed Jun 8, 2023
1 parent 6c6f86c commit ccf9517
Show file tree
Hide file tree
Showing 7 changed files with 521 additions and 71 deletions.
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
v2.0.0

Added support for airport queries:

- new special variables `NEARBY_AIRPORTS`, `ALL_AIRPORTS`, and `AIRPORT:index` where index is an ICAO code.
- new events `AIRPORTS_IN_RANGE` and `AIRPORTS_OUT_OF_RANGE`.

Removes `getSpecial` in favour of `get` with a single variable argument

v1.4.1

- [x] Camera Variables
- [x] Services Variables
- [x] Miscellaneous Variables
- Aircraft SimVars:
- [x] Aircraft Autopilot/Assistant Variables
- [x] Aircraft Brake/Landing Gear Variables
- [x] Aircraft Control Variables
- [x] Aircraft Electrics Variables
- [x] Aircraft Engine Variables
- [x] Aircraft Flight Model Variables
- [x] Aircraft Fuel Variables
- [x] Aircraft Misc. Variables
- [x] Aircraft Radio Navigation Variables
- [x] Aircraft System Variables
- [x] Helicopter Variables

---

There was no changelog prior to v1.4.1
1 change: 1 addition & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This code is free to use for non-commercial purposes. If you wish to use it in a commercial project, please file an issue to request a paid license.
77 changes: 73 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ import { SystemEvents, MSFS_API } from "./msfs-api.js";
const api = new MSFS_API();

api.connect({
retries: 2Infinity,
retries: Infinity,
retryInterval: 5,
onConnect: () => {
api.on(SystemEvents.PAUSED, () => {
Expand All @@ -85,7 +85,7 @@ Note that the event names are keys from the `SystemEvents` object, using UPPER_S
##### Special Events
There are currently two "unofficial" events that can be listened to:
There are currently two non-simconnect events that can be listened to:
- `AIRPORTS_IN_RANGE`, registers a listener for notifications about airports coming into range of our airplane (or rather, coming into range of "the current Sim bubble", which is all world tiles currently loaded and active in the sim).
- `AIRPORTS_OUT_OF_RANGE`, registers a listener for notifications about airports dropping out of range of our airplane (with the same note as above).
Expand All @@ -98,11 +98,80 @@ Stop listening for a specific simconnect event with a specific handler. You'll t
Accepts a list of simvars (with spaces or underscores) and async-returns a key/value pair object with each simvar as key (with spaces replaced by underscores).
#### `getSpecial(propName)`
##### special (non-simconnect) variables
There are a number of special variables that can only be retrieved using a get call with a single variable name, yielding data that is not services by SimConnect's own variables (or data that requires a considerable amount of low-level event handling).
A special get function for getting individual values that secretly require a whole bunch of complex SimConnect code. There is currently only one such value available:
There are currently three variables:
- `NEARBY_AIRPORTS`, which yields the list of airports that are currently in range of our airplane (or rather, in range of "the current Sim bubble", which is all world tiles currently loaded and active in the sim).
- `ALL_AIRPORTS`, which yields the list of all airports known to MSFS.
Both calls return objects of the following type:
```
FacilityAirport {
icao: four character ICAO code
latitude: number in degrees
longitude: number in degrees
altitude: number in meters
}
```
Pay special attention to the altitude, which is *not* in feet, it is in meters.
- `AIRPORT:index`, which yields an airport's information (including runway information), with `index` being the airport's ICAO code.
This call returns objects of the following type:
```
{
latitude: number in degrees
longitude: number in degrees
altitude: number in meters
declination: number in degree
name: airport name as a string with at most 32 characters
name64: airport name as a string with at most 64 characters
ICAO: four character ICAO code for this airport
region: the ICAO region for this airport as string
runwayCount: number of runways at this airport
runways: array of runway objects
}
```
Again, pay special attention to the altitude, which is *not* in feet, it is in meters.
Runway objects are of the following type:
```
{
latitude: number in degrees, marking the center of the runway
longitude: number in degrees, marking the center of the runway
altitude: number in meters
heading: number in degrees
length: number in meters
width: number in meters
patternAltitude: number in meters
slope: number in degrees
slopeTrue: number in degrees
surface: surface material, as string
approach: array of runway approaches
}
```
Approaches are of the following type:
```
{
designation: runway designation as string
marking: runway marking, as string (can be a number, or cardinal direction)
ILS: {
type: ILS type as string
ICAO": ICAO code for this approach's ILS
region": ICAO region for this approach's ILS
}
}
```
#### `schedule(handler, interval, ...propNames)`
Expand Down
76 changes: 24 additions & 52 deletions msfs-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,22 @@ import {

// imports used by the API
import { SimVars } from "./simvars/index.js";
import { SystemEvents as SysEvents } from "./system-events/index.js";
import {
SystemEvents as AirportEvents,
airportGetHandler,
} from "./special/airports.js";

// Special import for working with airport data
import { SystemEvents as SysEvents } from "./system-events/index.js";
const SIMCONNECT_FACILITY_LIST_TYPE_AIRPORT = 0;
const { AIRPORTS_IN_RANGE, AIRPORTS_OUT_OF_RANGE } = SysEvents;

const SIMCONNECT_FACILITY_LIST_TYPE_AIRPORT = 0;
const SIMCONNECT_FACILITY_AIRPORT = 1000;

const codeSafe = (string) => string.replaceAll(` `, `_`);

// direct export for downstream users:
export const SystemEvents = SysEvents;
export const SystemEvents = Object.assign({}, SysEvents, AirportEvents);

/**
* API:
Expand All @@ -35,6 +41,9 @@ export class MSFS_API {
// set up a listener list for simconnect event handling:
this.eventListeners = {};

// set up a list for special (non-simconnect) get handlers
this.specialGetHandlers = [airportGetHandler];

// set up an event/data/request id counter:
this.id = 1;
this.reserved = new Set();
Expand Down Expand Up @@ -168,21 +177,7 @@ export class MSFS_API {
console.trace();
return;
}

const { name: eventName } = eventDefinition;

// special case handling
const airports = [AIRPORTS_IN_RANGE.name, AIRPORTS_OUT_OF_RANGE.name];
if (airports.includes(eventName)) {
return this.__subscribeToAirports(eventName, eventHandler);
}

this.addEventListener(eventName, eventHandler);
return () => this.off(eventName, eventHandler);
}

// Special case handler for getting "airports nearby" data.
__subscribeToAirports(eventName, eventHandler) {
this.addEventListener(eventName, eventHandler);
return () => this.off(eventName, eventHandler);
}
Expand Down Expand Up @@ -288,46 +283,23 @@ export class MSFS_API {
const DATA_ID = this.nextId();
const REQUEST_ID = DATA_ID;
propNames = propNames.map((s) => s.replaceAll(`_`, ` `));

// see if this is a special, non-simconnect variable:
if (propNames.length === 1) {
const [propName] = propNames;
for (const get of this.specialGetHandlers) {
if (get.supports(propName)) {
return get(this, propName);
}
}
}

// if not, regular lookup.
const defs = propNames.map((propName) => SimVars[propName]);
this.addDataDefinitions(DATA_ID, propNames, defs);
return this.generateGetPromise(DATA_ID, REQUEST_ID, propNames, defs);
}

/**
* Get a special value. Currently supported values:
* - [x] NEARBY_AIRPORTS, the list of airports around the plane inside the sim's "reality bubble".
* - [ ] ALL_AIRPORTS, the list of literally every airport known to the sim.
*/
getSpecial(propName) {
propName.replaceAll(` `, `_`);
if (propName === `NEARBY_AIRPORTS`) {
return new Promise((resolve) => {
const getID = this.nextId();
const handler = (data) => {
if (data.requestID === getID) {
handle.off("airportList", handler);
this.releaseId(getID);
resolve({ NEARBY_AIRPORTS: data.airports ?? data.aiports });
}
};
const { handle } = this;
handle.on("airportList", handler);
handle.requestFacilitiesListEx1(
SIMCONNECT_FACILITY_LIST_TYPE_AIRPORT,
getID
);
});
}
if (propName === `ALL_AIRPORTS`) {
console.warn(`getSpecial(ALL_AIRPORTS) is not currently supported.`);
if (!this.AirportDB) return [];
return new Promise((resolve) => {
// TODO: load sqlite db from this.AirportDB and convert to an array of {icao, latitude, longitude, elevation }
resolve([]);
});
}
}

/**
* Set a simconnect variable.
*
Expand Down
Loading

0 comments on commit ccf9517

Please sign in to comment.