Migrating a Mission to VEAF MCT v6¶
This guide covers two scenarios:
- From VEAF MCT v5.xx — your mission already uses VEAF MCT scripts but predates the v6 toolchain
- From a vanilla DCS mission — your mission has no VEAF MCT scripts at all
In both cases the end result is a VEAF MCT v6 mission folder that you manage with veaf-tools.exe.
flowchart TD
V5[VEAF MCT v5 mission] -->|veaf-tools convert v5| FOLDER[v6 mission folder]
VAN[Vanilla DCS .miz] -->|veaf-tools mission extract| FOLDER
FOLDER --> CFG[Edit mission.yaml]
CFG --> BUILD[veaf-tools mission build]
BUILD --> MIZ[v6 .miz ready to fly]
Before You Start¶
Terminology¶
| Term | Meaning |
|---|---|
| Mission folder | The directory managed by veaf-tools — contains source files, config, and the .miz |
.miz file |
The DCS mission file (a ZIP archive); the output of the build step |
published/ |
Where veaf-tools-updater.exe installs the VEAF scripts |
src/ |
Your mission-specific source files (scripts, data) |
Prerequisites¶
- Install
veaf-tools-updater.exe— download from the latest GitHub release
Windows security: Windows may block
.exefiles downloaded from the internet. If the file doesn't run, right-click it → Properties → General tab → check Unblock at the bottom → OK.
- Run the updater once to install
veaf-tools.exeand all VEAF scripts:
.\veaf-tools-updater.exe
- Have your v5 mission folder on hand
The
.\is required. The default Windows terminal is PowerShell, which does not search the current directory — on purpose.cmd.exeaccepts both forms, so.\works everywhere. See PowerShell or Command Prompt?.Tip — Global User Configuration: Before starting, create
~/veafmct.yaml(i.e.C:\Users\YourName\veafmct.yamlon Windows) to set persistent defaults for all your VEAF projects on this machine — for example your language preference (lang: fr). See Global User Configuration for the full reference and CLI commands.
Migrating from VEAF MCT v5.xx¶
What Changed in v6¶
| Area | v5 | v6 |
|---|---|---|
| DCS trigger | Manual DO SCRIPT FILE triggers pointing at each .lua file |
Single trigger injected automatically by veaf-tools mission build; no manual trigger work |
| Build toolchain | No build step — scripts loaded directly from disk at mission start | .\veaf-tools.exe mission build assembles the .miz from src/mission/ + src/scripts/ |
| Build script | Complex build.cmd with one line per inject command |
No build.cmd — just run .\veaf-tools-updater.exe then .\veaf-tools.exe mission build |
| Auto-inject pipeline | Each inject command (inject-presets, inject-waypoints, etc.) had to be added manually to build.cmd |
veaf-tools mission build auto-detects and runs each step when the matching file is present in src/ |
| Tool updates | NPM (npm install) — scripts distributed as a versioned package |
veaf-tools-updater.exe — downloads and verifies the latest release in one command |
| Build-time config | No build-time config file | mission.yaml — controls log levels, module enable/disable, pipeline step overrides |
| Module enable/disable | Edit missionConfig.lua (or simply omit the initialize() call) |
mission.yaml → modules: block; generates veaf-config.lua automatically |
| Module configuration | Direct assignment: veafSpawn.SpawnKeyphrase = "_spawn" in missionConfig.lua |
Same direct assignment still works in mission-script.lua; or veaf.setConfig("MODULE_ID", "key", value) for config-driven overrides |
| Module init pattern | Bare veafXxx.initialize() calls |
Auto-generated into veaf-config.lua by veaf-tools mission build; no manual initialize() calls needed |
| Config location | Initialization scattered in DCS trigger scripts or a separate Lua file | mission.yaml generates veaf-config.lua at build time; optional custom Lua in mission-script.lua |
| Config migration | Manual rewrite | .\veaf-tools.exe convert v5 — one command converts missionConfig.lua, pipeline files (presets, waypoints, weather, aircraft groups), and generates mission.yaml + mission-script.lua. Use migrate-config only to migrate missionConfig.lua alone. |
| Module log levels | Set per-module by assigning veafXxx.LogLevel before init |
mission.yaml → modules: → MODULE_ID: logLevel: or --log-modules CLI flag |
| Skynet / CTLD / CSAR / QRA | Separate external_modules: and qra: sections |
All under the modules: block (modules.SKYNET, modules.CSAR with a settings: sub-block, modules.QRA with silence_all + definitions:). modules.CTLD is a plain boolean: CTLD 2 is configured in a ctld-config.yaml next to mission.yaml, and a settings: block there is rejected by validate — you edit it with ctld-tools, a tool shipped with CTLD that you download separately. The external_modules: and qra: sections no longer exist — see ADR 0001. convert-v5 emits the new shape directly. |
Step-by-step Migration¶
1. Create a new mission folder and copy your v5 source files¶
Create a new empty folder for your v6 mission project, then copy the src/ folder from your v5 mission into it. Starting fresh prevents old v5 artefacts from interfering and gives you a single clean copy of your source files:
# Adapt these paths to your setup
New-Item -ItemType Directory "C:\path\to\my-new-v6-mission"
Copy-Item -Recurse "C:\path\to\your-v5-mission\src" "C:\path\to\my-new-v6-mission\"
Set-Location "C:\path\to\my-new-v6-mission"
Tip: You can also do this in Windows Explorer — create a new folder, copy the
src/folder from your v5 mission into it, then open a terminal there.
2. Install VEAF MCT v6¶
Copy veaf-tools-updater.exe into the folder and run:
.\veaf-tools-updater.exe
This creates the published/ directory with all scripts and tools. Your existing src/ files are not touched.
3. Convert the mission folder to v6¶
Run the all-in-one converter:
.\veaf-tools.exe convert v5 .
This single command handles everything in one pass:
missionConfig.luamigration — comments outdoFile()calls that load VEAF scripts (the builder injects them automatically), wraps bareveafXxx.initialize()calls inif veafXxx then … endguards.- Pipeline config conversion — converts v5 config files (radio presets, waypoints, weather, aircraft groups) from Lua to v6 YAML format.
mission.yamlgeneration — createsmission.yamlwith the correctmodules:andpipeline:sections.src/mission/promotion to v6 — rewrites the exploded.miz(src/mission/) to v6: a base build migrates the legacy v5 triggers on disk, after backing up the original tobackup_v5/src/mission/. On by default; all editor content (groups, routes, units) is preserved — only the legacy v5 trigger layer is purged. Use--no-promoteto skip it.- Leftover v5 file triage — obsolete v5 tooling (
*.cmd,*.ps1,package.json,yarn.lock,configuration.json, …) is moved tobackup_v5/; regenerable artifacts (node_modules/,build/,cache/) are deleted; any other unmanaged file is just listed in the report for you to decide.configuration.jsonis flagged because it may hold a v5 API key (unused in v6: real weather goes throughavwx-engine, no key). - Conversion report — saves
convert-v5-report.mdwith all actions taken and any items requiring manual review.
If your pipeline contains realweather weather versions, supply the ICAO airport code via the --icao option to embed it in the generated config. If you omit it, the conversion still succeeds: the tool writes airport_icao: TODO into the generated config (versions.yaml) and prints a warning. Set it afterwards either by editing the TODO in versions.yaml, or by re-running convert-v5 --icao UGGG --force:
.\veaf-tools.exe convert v5 . --icao UGGG
Old DCS DO SCRIPT FILE triggers are removed automatically by veaf-tools mission build in the next step — no manual action needed.
src/mission/promotion to v6 (on by default):convert-v5finishes by rewritingsrc/mission/to v6 (base build + extract), making the v6 switch definitive and avoiding a re-migration of the v5 triggers on every build. The original is backed up tobackup_v5/src/mission/. If you'd rather review the generated configs and build yourself first, disable the step with--no-promote; you can re-runconvert-v5later to promote.If you only need to migrate
missionConfig.luawithout converting pipeline files, use.\veaf-tools.exe convert migrate-config src\scripts\missionConfig.luadirectly.
4. Check removed v5 patterns¶
What each v5 construct becomes — some were renamed, others are unchanged and therefore need no migration at all:
| v5 | v6 |
|---|---|
veaf.SecurityDisabled = true |
Both spellings work: veafSecurity.SecurityDisabled is the recommended name, veaf.SecurityDisabled is still honoured. Nothing urgent to change |
veafSpawn.Keyphrase set at top-level |
Still veafSpawn.Keyphrase — unchanged |
veafAssets.Assets inline table |
Same table format — unchanged |
Loading individual .lua files via DO SCRIPT FILE |
Automatic — do not add these triggers manually |
IADS scripts loaded manually |
Load them via src/scripts/ — they are picked up automatically |
5. Verify with a test build¶
.\veaf-tools.exe mission build
Open the resulting .miz in DCS, load the mission, and confirm:
- No duplicate DO SCRIPT FILE triggers in the trigger editor
- The v6 VEAF MCT loader trigger is present (named something like VEAF scripts loader)
- Radio menus and marker commands work as expected
6. Set up version control¶
git init
git add src/ .gitignore
git commit -m "feat: migrate my-mission to VEAF MCT v6"
Add published/ and *.miz to .gitignore — they are build artifacts.
A mission with its own script layer¶
When your v5 mission loads scripts of its own through the scriptsToLoad list of veafDynamicConfig.lua, convert v5 also:
- writes that list into
custom_scripts:, in the same order (missionConfig.luaexcepted, since it is migrated); - reads every script of
src/scripts, not onlymissionConfig.lua: a module one of them calls into is enabled, and a module one of them starts (veafXxx.initialize(…), or the carrier'sinitializeCarrierGroups) is enabled withinitialized_by_mission: true, so the build does not start it a second time — CSAR and Skynet included (CTLD is only enabled: its v6 start stays with VEAF); - says apart, among the settings it cannot carry, those your script computes (read from data, a function call) rather than writes as a value.
The whole method is in Porting a mission with its own script layer.
Integrating VEAF MCT into a Vanilla DCS Mission¶
A vanilla mission has no VEAF MCT scripts, no special triggers, and was built entirely with the DCS Mission Editor.
Step-by-step Integration¶
1. Create the mission folder¶
mkdir my-mission
cd my-mission
2. Install VEAF MCT v6¶
.\veaf-tools-updater.exe
3. Extract the vanilla .miz, then build¶
Extract your vanilla .miz into the source folder, then run the build, which injects the VEAF scripts and rebuilds a new .miz:
.\veaf-tools.exe mission extract "C:\path\to\vanilla.miz" .
.\veaf-tools.exe mission build
This:
1. Extracts vanilla.miz into src/mission/
2. Creates default mission.yaml and src/scripts/mission-script.lua
3. Injects the v6 VEAF loader trigger
4. Rebuilds a new .miz next to the folder
4. Optionally: prepare the folder with defaults only¶
If you want to set up the folder structure without converting a mission yet, use prepare:
.\veaf-tools.exe mission prepare .
Then copy your .miz as mission.miz and run:
.\veaf-tools.exe mission extract mission.miz .
.\veaf-tools.exe mission build
5. Configure which modules to enable¶
Edit mission.yaml to enable the modules you want. A set of common modules is active by default — radio, spawn, shortcuts, CAS, transport, weather… — adjust to taste:
mission:
name: My Vanilla Mission
modules:
RADIO:
enabled: true
SPAWN:
enabled: true
# Uncomment to enable CAS missions:
# CASMISSION:
# enabled: true
# Uncomment to enable carrier ops:
# CARRIER:
# enabled: true
For custom Lua (advanced module calls, custom aliases, etc.), edit src/scripts/mission-script.lua.
See the YAML reference and the individual script guides in scripts/ for all options.
6. Keep your existing mission content¶
Everything you built in the DCS Mission Editor (units, triggers, waypoints, zones) is preserved. VEAF does not remove or overwrite mission content — it only: - Adds a single loader trigger at mission start - Adds F10 radio menu entries at runtime - Responds to F10 map marker commands
Your custom triggers, statics, and groups are untouched.
7. Test and iterate¶
# Rebuild after every config change
.\veaf-tools.exe mission build
Each build produces a dated .miz file (e.g. mission_20260516.miz). Open it in DCS and test.
Mission Folder Reference¶
After migration, your folder should look like this:
my-mission/
├── src/
│ ├── mission/ ← extracted DCS mission data (commit this)
│ │ ├── mission ← main mission Lua dictionary
│ │ ├── options
│ │ └── warehouses
│ ├── scripts/
│ │ ├── mission-script.lua ← custom Lua code (commit this)
│ │ └── veafDynamicConfig.lua ← optional dynamic script-loading config (dev)
│ ├── presets.yaml ← radio presets config (optional)
│ ├── spawnables.yaml ← custom spawnable groups (optional)
│ └── waypoints.yaml ← custom waypoints (optional)
├── mission.yaml ← module config and pipeline settings (commit this)
├── published/ ← installed by veaf-tools-updater (do NOT commit)
│ ├── veaf-scripts.lua
│ └── ...
├── veaf-tools.exe ← installed by veaf-tools-updater (do NOT commit)
├── veaf-tools-updater.exe ← commit this
└── mission_20260516.miz ← build output (do NOT commit)
Recommended .gitignore¶
published/
*.miz
*.log
__pycache__/
mission-script.lua Reference¶
mission-script.lua is an optional file for custom Lua code that runs after all VEAF modules are initialized. Use it for advanced configuration that cannot yet be expressed in mission.yaml — custom shortcuts, per-module parameter overrides, custom assets, etc.
A minimal example:
-- Optional: override a module parameter
veafSpawn.SpawnKeyphrase = "_spawn"
-- Custom alias
veafShortcuts.AddAlias(
VeafAlias:new()
:setName("-myalias")
:setVeafCommand("_spawn group, name my-template")
)
Module enable/disable is configured in mission.yaml → modules: — not in this file. See the YAML reference for the full mission.yaml syntax.
Common Issues¶
"cannot load the presets file" after a conversion¶
A src/presets.yaml already present before the conversion could be written against the v5
schema: same name, same file format, but a different inner layout (presets_definition: instead
of presets_collection:, one extra coalitions: level, radios defined inline inside each preset).
convert-v5 left it alone — it was in the right place — and the build then failed on the next step.
convert-v5 now detects that case by the file's structure and rewrites it in place, keeping the
original as backup_v5/src/presets.yaml. The conversion report says so, with a warning for anything
it could not settle on its own (a radio whose channels straddle two bands, for instance).
If you edit that file by hand, note that the loader now refuses a section it does not recognise instead of ignoring it in silence, and names the offending key, what it found there and what it expected.
"VEAF scripts loader" trigger appears twice¶
An old manual DO SCRIPT FILE trigger coexists with the v6 auto-injected one. veaf-tools mission build removes the old v5 triggers automatically (--migrate-from-v5 option, on by default) — rebuilding is enough. Removing the trigger by hand in the DCS Mission Editor is only needed if you explicitly disabled that migration (--no-migrate-from-v5).
Radio menus don't appear¶
Confirm RADIO is enabled in mission.yaml:
modules:
RADIO:
enabled: true
Rebuild with .\veaf-tools.exe mission build after any mission.yaml change.
Marker commands don't work¶
Confirm SPAWN is enabled in mission.yaml:
modules:
SPAWN:
enabled: true
Then check the DCS log (Saved Games\DCS\Logs\dcs.log) for VEAF errors — filter on VEAF or ERROR.
Reading the logs¶
All VEAF messages go to Saved Games\DCS\Logs\dcs.log. To find them quickly:
- Klogg (recommended): open
dcs.log, use the search bar to filter onVEAF. A VEAF highlight profile ships with the repository attools/klogg/veaf.conf— load it via File > Import highlights…. - Notepad++: open
dcs.log→ Search → Find (Ctrl+F) → search forVEAF.
Build fails with "VEAF scripts file not found"¶
Run .\veaf-tools-updater.exe first — the published/ folder is missing or outdated.
See Also¶
- Mission Maker Guide — general mission making workflow
- Scripts Reference — all available modules
- CLI Reference — all 25
veaf-toolscommands, arguments and options