Skip to content

Extract airfield data (airbases, runways, parking) from DCS at runtime #5

@mitch10593

Description

@mitch10593

Summary

Building on the existing runtime extraction pipeline (a DO SCRIPT Lua trigger writes tagged lines to dcs.log, then a Python pipeline parses/exports them — currently used to calibrate each map's projection), we can extract airfield data with the same mechanism:

  • Airbases — name, callsign, position, category, ID
  • Runways — heading, length, width, position
  • Parking — parking spots (type, position, distance to runway)

This is a feasibility-confirmed proposal. Frequencies / nav beacons are explicitly out of scope here (different mechanism — see below).

Motivation

The data above is static per map and broadly useful (airbase coordinates, runway headings & dimensions, parking layouts) for tooling, briefings, kneeboards, GIS overlays, etc. It fits the project's existing runtime-extraction approach with no new tech, and is actually simpler than the current map calibration because no model-fitting / calibration step is needed — the data is read directly.

What's extractable at runtime (verified against the DCS scripting API)

Entry point: world.getAirbases() → all airbases (+ ships + FARPs) on the map. Per Airbase object:

Data Method Content
Airbase getName(), getCallsign() name / ATC callsign (e.g. "Batumi")
getPoint() {x=North, y=alt, z=East} → lat/lon via coord.LOtoLL()
getID() scripting ID (stable join key for runways/parking)
getCategory() AIRDROME / HELIPAD / SHIP (lets us filter out ships & FARPs)
getDesc() descriptor (attributes, …)
Runways getRunways() (DCS 2.7+) list of {Name, course, position{x,y,z}, length, width}
Parking getParking([available]) (2.5.2+) list of {Term_Index, Term_Type, vTerminalPos{x,y,z}, fDistToRW, TO_AC}

Notes on the structures:

  • Runway course is in radians (multiply by -1, then convert to degrees); it is a true heading. Name (e.g. 08/26) is the magnetic designator provided by DCS. length/width in metres; position is the runway centre.
  • Parking Term_Type is an enum (16/40/68/72/100/104 — helipad / parking / takeoff point…; mapping is community-documented). fDistToRW = distance to the takeoff point.

How it fits the existing pipeline

DCS (Mission Editor)                Python
+------------------------+         +----------------------+     +-----------------+
| tools/export_airbases  |         | parse tagged lines   |     | export 4 formats |
| .lua  (DO SCRIPT ONCE) |  --->   | from dcs.log         | --> | yaml/json/md/py  |
| world.getAirbases()    | dcs.log | (regex, like         |     | (reuse export.py |
| + coord.LOtoLL()       |         |  DCSXFORM_RE)        |     |  writers)        |
+------------------------+         +----------------------+     +-----------------+
        NO calibration step  <-- key difference vs. maps coordinates
  • Reuse the exact runtime mechanism (env.info into dcs.log, no MissionScripting.lua de-sanitisation needed — only env.info and coord.LOtoLL, always allowed).
  • The calibrate.py stage disappears for this data — it's read directly.
  • Emit lat/lon directly from Lua via coord.LOtoLL(point), exactly like today's DCSXFORM lines. Bonus: also emitting raw x/z gives a free cross-check of the calibrated tmerc projection (convert.py) against DCS's own LOtoLL (expect < 1 m error).

Proposed flat, tagged log format (parseable by a regex, like DCSXFORM):

DCSAB;THEATRE;Caucasus
DCSAB;AIRBASE;<id>;<category>;<name>;<callsign>;<lat>;<lon>;<alt>
DCSAB;RUNWAY;<airbase_id>;<name>;<course_deg>;<length>;<width>;<lat>;<lon>
DCSAB;PARKING;<airbase_id>;<term_index>;<term_type>;<dist_rw>;<lat>;<lon>

(Lua has no native JSON in the mission env; flat tagged lines are the most robust. Escape the delimiter if a name can contain ;.)

Proposed shape (non-prescriptive)

  • tools/export_airbases.lua — new runtime export script (twin of export_points.lua).
  • a Python parsing module (modeled on ingest.py / DCSXFORM_RE).
  • new data file(s) + a generator reusing the export.py multi-format writers (to_yaml/json/md/python).
  • optionally a dedicated CLI subcommand (e.g. dcs-coords airbases).

Candidate schema (per map, nested):

Caucasus:
  airbases:
    - id: 12
      name: Batumi
      category: AIRDROME
      lat: 41.6103
      lon: 41.5997
      alt: 9.0
      runways:
        - name: "13"
          heading_true: 126.0
          length_m: 2438
          width_m: 45
          lat: ...
          lon: ...
      parking:        # large volume — consider a separate file
        - index: 100
          type: 104
          lat: ...
          lon: ...

Out of scope: frequencies & nav beacons (separate future work)

  • The scripting engine does not expose ATC frequencies at runtime (you can silence the ATC but not read its frequency — that's why SRS/LotAtc ship their own frequency tables).
  • Nav beacons (TACAN, ILS, VOR, NDB, PRMG, RSBN) and frequencies live in terrain data files: <DCS>/Mods/terrains/<Theatre>/Beacons.lua (+ Scripts/World/Radio/BeaconSites.lua / BeaconTypes.lua).
  • Getting these programmatically means parsing those .lua files offline, not runtime extraction → a separate, complementary track. Out of scope for this issue.

Caveats / notes

  • getRunways() requires DCS 2.7+; getParking() has been marked WIP since 2.5.2 (structure may evolve).
  • world.getAirbases() also returns ships and FARPs → filter on getCategory().
  • No magnetic declination is available at runtime (no API); the magnetic runway designator is the Name field.
  • Parking volume is large (hundreds of slots per map x ~14 maps) → consider a separate file / compact representation so the airbase+runway file stays light.

Acceptance criteria / validation

  • tools/export_airbases.lua emits tagged DCSAB;… lines for airbases, runways, parking.
  • Python parses the log and produces structured per-map records.
  • Multi-format export (yaml/json/md/py) generated, mirroring the maps export.
  • Validated on at least one map (e.g. Caucasus): airbase count & positions match known reference data; lat/lon cross-checked via convert.py (< 1 m vs coord.LOtoLL).
  • Ships/FARPs filtered out (or clearly categorised).

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions