Aller au contenu

Référence Pipeline

Cette page documente les étapes optionnelles du pipeline de build que veaf-tools mission build peut exécuter après la génération de veaf-config.lua. Chaque étape injecte des données dans le fichier .miz à partir d'un fichier de configuration YAML séparé.


Vue d'ensemble

Le pipeline exécute les étapes optionnelles suivantes, dans cet ordre :

Étape Fichier config Ce qu'elle fait
presets src/presets.yaml Injecte les préréglages de fréquences radio dans les groupes d'avions pilotés par des humains
waypoints src/waypoints.yaml ou waypoints.yaml Injecte des modèles de points de cheminement dans les groupes d'avions pilotés par des humains
spawnable_aircrafts src/spawnables.yaml Injecte les groupes d'avions spawnables (préfixe veafSpawn-, clonés par veafSpawn)
dynamic_slot_templates src/dynamic-slot-templates.yaml Injecte les modèles de slot dynamique (dynSpawnTemplate = true, consommés par DCS)
warehouses src/warehouses.yaml Configure les warehouses pour les slots dynamiques (Dynamic Slots)
spawn_data src/spawn-groups.yaml (optionnel) Injecte la base de données de spawn (_spawn unit/_spawn group) ; toujours active (les données du framework sont embarquées)
weather src/versions.yaml ou versions.yaml Crée plusieurs variantes de mission avec différentes météos et heures

Chaque étape est auto-détectée : elle s'exécute si son fichier de config par défaut existe. Vous pouvez modifier ce comportement dans mission.yaml. Exception : spawn_data s'exécute toujours (même sans fichier mission) afin d'embarquer la base de spawn du framework ; le fichier src/spawn-groups.yaml ne sert qu'à l'étendre.


Contrôle du pipeline (mission.yaml)

pipeline:
  presets: false                        # ignoré même si src/presets.yaml existe
  waypoints: true                       # auto-détection : exécuté seulement si le fichier existe
  spawnable_aircrafts:
    file: src/my-spawnables.yaml        # chemin de fichier non-standard
    mode: replace                       # add (défaut) | replace
  dynamic_slot_templates: false         # ignorer l'injection des modèles de slot dynamique
  spawn_data: false                     # désactiver l'injection de la base de spawn (framework inclus)
  weather: false                        # ignorer les variantes météo

Champs de pipeline:

Champ Type Défaut Requis Description
presets bool | objet auto Non true/non défini = auto-détection (exécuté si fichier trouvé), false = toujours ignorer, objet = options personnalisées
waypoints bool | objet auto Non true/non défini = auto-détection (exécuté si fichier trouvé), false = toujours ignorer, objet = options personnalisées
spawnable_aircrafts bool | objet auto Non true/non défini = auto-détection (exécuté si fichier trouvé), false = toujours ignorer, objet = options personnalisées
dynamic_slot_templates bool | objet auto Non true/non défini = auto-détection (exécuté si fichier trouvé), false = toujours ignorer, objet = options personnalisées
spawn_data bool | objet toujours Non true/non défini = toujours exécuté (données framework embarquées), false = désactiver complètement, objet {file: …} = fichier mission non-standard
warehouses bool | objet auto Non true/non défini = auto-détection (exécuté si src/warehouses.yaml est trouvé), false = toujours ignorer, objet = options personnalisées
weather bool | objet auto Non true/non défini = auto-détection (exécuté si fichier trouvé), false = toujours ignorer, objet = options personnalisées

Quand la valeur est un objet, les sous-champs suivants s'appliquent :

Sous-champ Type Défaut Description
file string (voir défauts par étape) Chemin vers le fichier de config, relatif au dossier mission
mode add | replace add (étapes d'injection de groupes uniquement) add conserve les groupes existants ; replace met à jour les groupes de même nom
enabled bool true Désactive l'étape sans perdre les autres sous-champs — c'est la forme longue de <étape>: false
kneeboards bool true (étape presets uniquement) false conserve l'injection des fréquences et ne génère aucune planchette PNG

Auto-détection (quand non défini ou true) : l'étape ne s'exécute que si son fichier par défaut est trouvé. L'absence du fichier ignore silencieusement l'étape.


Étape 1 — Préréglages radio (presets.yaml)

Injecte des préréglages de fréquences radio dans chaque groupe d'aéronefs contenant au moins un pilote humain (compétence Client/Player). Génère également des images de kneeboard PNG pour chaque préréglage.

Désactiver les planchettes (kneeboards) : la forme mapping de l'étape accepte un sous-champ kneeboards (défaut true). Passer pipeline: { presets: { enabled: true, kneeboards: false } } permet de conserver l'injection des fréquences radio tout en ne générant aucune planchette PNG (KNEEBOARD/<type>/IMAGES/presets[-<coalition>].png).

Emplacement par défaut

<dossier-mission>/src/presets.yaml

Deux formats d'auteur

Depuis ADR 0010, presets.yaml accepte deux couches, qui coexistent :

  • channel_lists (recommandé) : le mission-maker déclare une seule fois par coalition ses listes de canaux, par rôle radio fonctionnel (UHF principal, VHF principal, FM…), et le build projette automatiquement chaque liste sur les radios physiques de chaque type d'aéronef, en tenant compte de ses particularités matérielles (canal 0, slots réservés, canaux spéciaux en dur, fusion de radios — AJS-37, OH-58D, Mi-24P…). Une seule modification de fréquence se propage à toute la flotte. Le détail de ces règles de projection par type est documenté côté développeur : Projection des presets radio par type.
  • radios_collection / presets_collection / presets_assignments (historique) : le mission-maker définit lui-même, radio par radio, le contenu de chaque préréglage puis l'assigne explicitement par type d'appareil. Ce format reste entièrement supporté et sert désormais de mécanisme de surcharge manuelle : une affectation explicite dans presets_assignments pour un type donné l'emporte toujours sur la projection automatique de channel_lists — y compris la valeur spéciale none (aucune injection).

Dans tous les cas, channels_collection (les fréquences) reste la source commune aux deux formats.

convert-v5 nomme les fréquences automatiquement. À la conversion d'une mission v5, les fréquences en dur sont remplacées par des noms dans presets.yaml — aérodromes du théâtre (Gudauta, Batumi…) et indicatifs VEAF (Guard, Archer, Texaco-1…) — et le channels_collection correspondant est inséré pour les résoudre. Une fréquence sans nom connu reste en clair. La copie fidèle presets.v5.yaml conserve, elle, les fréquences brutes.

Une fréquence d'aérodrome ne se tape pas. Les collections airports-<théâtre> du presets.yaml par défaut sont générées depuis DCS (les fréquences que montre la vue F10, et le TACAN) : référencez un aérodrome par son nom (02: Batumi). Pour choisir les bases qui méritent un canal et écrire la collection bases d'une mission avec leurs vraies fréquences : content airfield-channels.

Schéma — channel_lists (modèle recommandé)

# ── Définitions de canaux (commun aux deux formats) ────────────────────────
channels_collection:
  <nom-ensemble>:                       # groupe logique de canaux (ex: airports-caucasus)
    <nom-canal>:                        # identifiant du canal
      title: "Batumi / 16X"            # libellé lisible par l'humain
      freqs:
        uhf: 260                        # fréquence UHF (MHz)
        vhf: 131                        # fréquence VHF-AM (MHz)
        fm: 40.4                        # fréquence FM (MHz)

# ── Listes de canaux par rôle radio ─────────────────────────────────────────
channel_lists:
  <coalition>:                          # blue | red
    primary_1:                          # 1re radio V/UHF (bande uhf)
      01: Guard
      02: Batumi
    primary_2:                          # 2e radio V/UHF (bande vhf) ; aussi la radio unique des warbirds
      01: Guard
      02: Batumi
    fm_supplement:                      # FM en 3e radio, en plus de deux radios primaires (ex: A-10C)
      01: 30
    fm_substitute:                      # FM en 2e radio, à la place d'une 2e radio primaire (ex: hélicoptères)
      01: 30
    fm_secondary:                       # 2e radio FM supplémentaire (ex: OH-58D) ; par défaut, copie de fm_supplement
      01: 31

Rôles radio (vocabulaire fixe) :

Rôle Bande Usage
primary_1 uhf 1re radio V/UHF
primary_2 vhf 2e radio V/UHF ; radio unique des warbirds
fm_substitute fm FM à la place d'une 2e radio primaire (hélicoptères à une seule radio primaire)
fm_supplement fm FM en plus de deux radios primaires (appareils d'attaque, ex: A-10C)
fm_secondary fm 2e radio FM supplémentaire (ex: OH-58D) ; par défaut, copie de fm_supplement si non déclaré

Le build assigne automatiquement chaque radio physique de chaque type d'aéronef au rôle qui lui correspond (déduit de ses plages de fréquences matérielles), puis y projette la liste de canaux déclarée pour ce rôle. Un canal qui n'a pas de fréquence pour la bande du rôle est ignoré silencieusement (signalé par validate).

Le canal 1 de la première radio devient aussi la fréquence du groupe : c'est sur lui que le vol démarre. Le plan livré ne met donc pas Guard en canal 1, ni ailleurs : chaque appareil atteint Guard par sa propre commande, et un vol démarrait sur la fréquence de détresse.

Schéma — format historique (surcharge manuelle)

# ── Définitions de radios ──────────────────────────────────────────────────
radios_collection:
  <nom-ensemble>:                       # groupe logique de radios (ex: blue_radios)
    <nom-radio>:                        # identifiant référencé dans presets_collection
      title: "UHF"                      # libellé affiché sur le kneeboard
      type: uhf                         # uhf | vhf | fm
      channels:
        01: Guard                       # numéro de canal → nom-canal (depuis channels_collection)
        02: Batumi
        10: Stennis

# ── Définitions de préréglages ────────────────────────────────────────────
presets_collection:
  <nom-ensemble>:                       # groupe logique de préréglages (ex: blue_presets)
    <nom-préréglage>:                   # identifiant référencé dans presets_assignments
      title: "Coalition bleue - UHF/VHF/FM"
      radios:
        radio_1: <nom-radio>            # slot → nom-radio (depuis radios_collection)
        radio_2: <nom-radio>
        radio_3: <nom-radio>

# ── Règles d'affectation (surcharge manuelle des channel_lists) ────────────
presets_assignments:
  <coalition>:                          # blue | red
    <catégorie>:                        # plane | helicopter
      all: <nom-préréglage>            # préréglage par défaut pour tous les aéronefs de ce type
      <type-aéronef>: <nom-préréglage> # surcharge pour un type DCS exact (ex: A-10C_2) ou un pattern regex (ex: A[-]10C.*)
      <type-aéronef>: none              # désactive toute injection pour ce type (aucun équivalent en channel_lists)

Exemple minimal

channels_collection:
  common:
    Guard:
      title: Guard
      freqs:
        uhf: 243.0
        vhf: 121.5

channel_lists:
  blue:
    primary_1:
      01: Guard

Valeur d'un canal

Un canal peut être défini de trois façons, dans channel_lists comme dans radios_collection :

  • un nom de canal (alias résolu depuis channels_collection) : 01: Guard ;
  • une fréquence directe (MHz) : 01: 243.0 ;
  • un objet : 01: { freq: 243.0, mod: 1 }, où mod est la modulation (0 = AM, 1 = FM). Le champ mod est optionnel ; absent, DCS utilise sa valeur par défaut.

Priorité et couleur d'un canal (planchettes)

Sur une entrée du plan (forme objet), deux attributs facultatifs enrichissent la planchette (ADR 0012) :

  • priority: <n> — met le canal en évidence sur toute planchette (marqueur Pn + cellules Name/Freq surlignées en orange). Sur l'AJS-37 (Viggen) uniquement, les priorités 1 à 4 alimentent en plus les raccourcis FR22 Special 1/2/3 et FR24 H. À déclarer dans channel_lists (une seule entrée par valeur de priorité).
  • color: <couleur> — colorise la cellule CH pour regrouper visuellement des canaux. Valeur : un nom de couleur (green, blue…) ou #RRGGBBAA. Accepté dans channel_lists et dans channels_collection (l'entrée du plan l'emporte sur la définition du canal).
channel_lists:
  blue:
    primary_1:
      01: { channel: Guard, priority: 4, color: red }   # Pn + surlignage ; sur Viggen → FR24 H
      02: { channel: Texaco-1, priority: 1 }             # sur Viggen → FR22 Special 1
      03: { channel: Batumi, color: "#2E7D32" }          # regroupement visuel (cellule CH)

Les planchettes sont générées une par type d'aéronef injecté, dans le dossier DCS du type (KNEEBOARD/<type>/IMAGES/).

Conversion v5 : deux fichiers (convert-v5)

Depuis ADR 0010, convert-v5 produit deux fichiers de préréglages :

  • presets.yaml — plan simplifié (par défaut, chargé par le build) : channel_lists seul (plus, le cas échéant, les rares surcharges que le packer ne peut pas projeter du tout). Le build projette automatiquement la cristallisation sur chaque aéronef, warbirds compris (radios compatibles VHF/FM), en écartant les canaux hors bande. C'est le fichier qui exploite pleinement le modèle preset-plan.
  • presets.v5.yaml — copie fidèle (référence / repli, non chargée par le build) : la conversion iso-fonctionnelle complète (channel_lists + un préréglage dédié {coalition}_{aéronef} par agencement sur mesure, reproduisant exactement la carte canal → fréquence et les mod, voir ADR 0003).

Attention : le plan peut faire diverger certaines fréquences de la mission v5 d'origine — les warbirds passent sur les canaux de la coalition, et les radios fusionnées/à modulations des jets (F-14, AV8B…) sont projetées au mieux (partiellement) tant qu'aucune entrée dcs-radio-layouts.yaml dédiée n'existe pour leur type. convert-v5 avertit quels aéronefs sont projetés au mieux. Vérifiez et éditez presets.yaml ; en cas de doute, la reproduction exacte du v5 reste dans presets.v5.yaml (à copier dans presets.yaml pour revenir au comportement iso-fonctionnel).

Validation des fréquences

Lors de l'injection, chaque fréquence assignée à un aéronef est vérifiée par rapport aux spécifications matérielles de ses radios.

Comportement par défaut (build normal) :

  • Appareils critiques (dcs_rejects_on_load: true dans les specs) : si une fréquence est hors plage, un WARNING est émis dans le log. Ce sont les appareils pour lesquels DCS lance une erreur au chargement de la mission.
  • Autres appareils : la validation est silencieuse — DCS stocke les fréquences mais ne les utilise pas pour les radios hors plage, sans crasher.

Rapport automatique :

Après chaque injection de presets, un fichier presets-validation-report.md est automatiquement créé dans le dossier mission si au moins un appareil (critique ou non) présente des fréquences hors plage. Ce fichier liste tous les problèmes avec les valeurs invalides et un extrait YAML pour les désactiver temporairement. Si aucun problème n'est détecté, le fichier est supprimé.

Le rapport, et le journal du build, listent aussi chaque AWACS et ravitailleur IA dont la fréquence n'est sur aucun preset injecté pour sa coalition : ses pilotes ne le trouveraient ni sur leurs radios ni sur leur planchette. C'est le signe qu'on a gardé le plan de canaux livré au lieu de celui de la mission ; ajoutez son canal dans src/presets.yaml. Une coalition qui n'a reçu aucun preset n'est pas contrôlée.

<dossier-mission>/presets-validation-report.md

Le rapport se committe sans bruit : il ne porte ni date ni chemin de la machine. Le fichier de presets y est nommé depuis le dossier de mission (src/presets.yaml) et la mission par son nom, sans la date du .miz ; deux builds des mêmes presets, depuis deux dossiers ou deux jours différents, écrivent le même fichier.

Désactiver temporairement l'injection pour un appareil :

Pendant que vous corrigez les presets, vous pouvez désactiver l'injection pour un type d'appareil en lui affectant la valeur none dans presets_assignments :

presets_assignments:
  blue:
    plane:
      MiG-19P: none   # DCS rejetera les fréquences standard — à corriger

Une fois les presets corrigés, supprimez la ligne none pour réactiver l'injection.

Les specs couvrent 100 aéronefs pilotables et sont issues de dcs-lua-datamine. Si un aéronef n'est pas dans la base, la vérification est silencieusement ignorée.

Voir aussi : doc/mission-maker/dcs-radio-specs.md — table de référence complète des plages de fréquences valides et liste des appareils critiques.
Pour régénérer après une mise à jour DCS : poetry run update-radio-specs


Étape 2 — Points de cheminement (waypoints.yaml)

Injecte des modèles de points de cheminement dans les groupes d'aéronefs pilotés par des humains. Seuls les groupes avec au moins une unité Client/Player sont modifiés.

Emplacement par défaut

<dossier-mission>/src/waypoints.yaml

Aussi accepté : waypoints.yaml  (racine du dossier mission)

Schéma

# ── Définitions de waypoints ───────────────────────────────────────────────
waypoints:
  <NOM_WAYPOINT>:
    type: "Turning Point"               # type de waypoint DCS
    action: "Turning Point"             # action de waypoint DCS
    alt: 6096                           # altitude en mètres
    alt_type: "BARO"                    # BARO | RADIO
    speed: 200                          # vitesse en m/s
    speed_type: "TAS"                   # TAS | IAS
    x: 75869                            # coordonnée X mission
    y: 48674                            # coordonnée Y mission
    name: "POTI"                        # ce qu'affiche le cockpit (optionnel, la clé sinon)
    ETA: 364.89                         # temps d'arrivée estimé en secondes (optionnel)
    ETA_locked: false                   # verrouiller l'ETA (optionnel)

# ── Affectations de plans de vol ───────────────────────────────────────────
settings:
  <NOM_PLAN>:
    category: "plane"                   # plane | helicopter (filtre optionnel)
    coalition: "blue"                   # blue | red (filtre optionnel)
    type: "F-16C_50"                    # type d'aéronef DCS (filtre optionnel)
    country: "USA"                      # nom du pays (filtre optionnel)
    waypoints:                          # les CLÉS des waypoints, dans l'ordre du vol
      - <NOM_WAYPOINT>

Un plan prend ses waypoints par clé

Un waypoint a une clé (<NOM_WAYPOINT>) et un name:. Un plan le désigne par sa clé ; le cockpit affiche son name:, ou sa clé s'il n'en a pas. Deux waypoints peuvent partager un nom, jamais une clé : POTI à 10 000 ft pour les avions et POTI_LOW à 500 ft sol pour les hélicoptères, affichés tous deux POTI.

Un plan liste ses waypoints sous forme d'une liste de clés. L'ancienne forme en mapping — HOLDING_POINT: "HOLDING_POINT" — se charge toujours, mais seules ses clés sont lues : la valeur est ignorée, donc POTI: "POTI_LOW" mène à POTI. Le build prévient quand une valeur nomme un autre waypoint.

Le build ajoute aussi à chaque plan de vol un waypoint BULLSEYE, au bullseye de la mission : ne pas en déclarer.

Priorité de correspondance

Les plans de vol sont associés aux groupes selon cet ordre de priorité : 1. Type d'aéronef (type) 2. Catégorie d'aéronef (category) 3. Coalition (coalition) 4. Pays (country) 5. Tous les autres groupes (sans filtre = joker)

Exemple minimal

waypoints:
  POTI:
    type: "Turning Point"
    action: "Turning Point"
    alt: 3048
    alt_type: "BARO"
    speed: 180
    speed_type: "TAS"
    x: -295152
    y: 617091

settings:
  AVIONS_BLEUS:
    category: "plane"
    coalition: "blue"
    waypoints:
      - POTI

Étape 3 — Groupes d'aéronefs : spawnables (B) et modèles de slot dynamique (C)

Deux usages distincts de groupes d'aéronefs injectés, gérés par deux étapes indépendantes (voir ADR 0002) :

  • (B) groupes spawnables (src/spawnables.yaml, étape spawnable_aircrafts) : vrais groupes cachés, clonés à la demande en jeu par veafSpawn. Marqueur : préfixe de nom veafSpawn-.
  • (C) modèles de slot dynamique (src/dynamic-slot-templates.yaml, étape dynamic_slot_templates) : groupes servant de modèle aux Dynamic Slots DCS, consommés nativement par le moteur. Marqueur : flag DCS dynSpawnTemplate = true.

À l'extraction (extract-aircraft-groups), chaque groupe est routé vers l'une des deux familles selon ce critère (le flag prime sur le préfixe) ; les autres groupes sont ignorés. Par défaut, l'extraction produit les deux fichiers ; l'option --kind spawnable|dynamic-template restreint la production à un seul. L'ancien tri par nom .*[tT]emplate.* est abandonné (il aiguillait à tort un spawnable nommé « … Template … »).

Emplacements par défaut

<dossier-mission>/src/spawnables.yaml              # (B) spawnable_aircrafts
<dossier-mission>/src/dynamic-slot-templates.yaml  # (C) dynamic_slot_templates

Rupture v6 : les anciens noms src/aircraft-templates.yaml / src/templates.yaml et l'étape aircraft_groups ne sont plus utilisés. convert-v5 produit directement les deux nouveaux fichiers.

Repli sur le catalogue livré

Ces deux étapes sont les seules du pipeline à avoir un repli : leur entrée est un catalogue, dont l'essentiel n'est édité par personne. prepare ne dépose donc plus de copie — il écrit un fichier vide — et la résolution se fait dans cet ordre :

  1. le fichier du dossier de mission, s'il contient au moins un groupe ;
  2. sinon le catalogue livré, sous published/src/defaults/mission-folder/src/.

Un fichier absent ou vide veut dire « je n'ajoute rien au catalogue livré », pas « je ne veux rien injecter ». Deux conséquences à connaître :

  • spawnable_aircrafts: false / dynamic_slot_templates: false reste le seul moyen de désactiver l'étape, et le repli ne la ressuscite pas ;
  • un file: explicite est pris au mot : si le chemin nommé n'existe pas, l'étape est ignorée plutôt que repliée sur le catalogue livré — une faute de frappe ne doit pas injecter un catalogue que personne n'a demandé.

Quand le repli joue, le compte rendu de build le dit. Pour récupérer sélectivement les entrées du catalogue livré dans un fichier qui en a déjà, voir pull-aircraft-groups.

Modes d'injection

Mode Comportement
add (défaut) Ajoute tous les groupes du fichier ; les groupes existants sont conservés
replace Les groupes portant le même nom dans la mission sont mis à jour ; les autres sont conservés

Schéma

airplanes:
  coalitions:
    <coalition>:                        # blue | red
      <Nom Pays>:                       # nom de pays DCS (ex: "France", "USA")
        <Nom Groupe>:
          name: "Nom Groupe"            # REQUIS — doit correspondre à la clé
          type: "M-2000C"               # REQUIS — type d'aéronef DCS principal
          units:                        # REQUIS — au moins une unité
            - type: "M-2000C"
              name: "Pilote-1"
            - type: "M-2000C"
              name: "Pilote-2"

helicopters:
  coalitions:
    <coalition>:
      <Nom Pays>:
        <Nom Groupe>:
          name: "Nom Groupe"
          type: "UH-1H"
          units:
            - type: "UH-1H"
              name: "Helo-1"

Exemple minimal

airplanes:
  coalitions:
    blue:
      France:
        Vol-Mirage:
          name: "Vol-Mirage"
          type: "M-2000C"
          units:
            - type: "M-2000C"
              name: "Mirage-1"
            - type: "M-2000C"
              name: "Mirage-2"

Étape 4 — Warehouses Dynamic-Slot (warehouses.yaml)

Configure les Dynamic Slots DCS par coalition. S'exécute après l'injection des aéronefs (pour que les groupes dynSpawnTemplate existent déjà) et modifie les warehouses de la mission : active dynamicSpawn sur les aérodromes choisis, fixe carburant / munitions et le stock d'aéronefs, et lie chaque type d'aéronef proposé à son groupe-modèle via linkDynTempl.

Emplacement par défaut

src/warehouses.yaml (auto-activé si présent ; désactiver avec pipeline: { warehouses: false }).

Schéma

<coalition>:                 # blue | red | neutral. Une coalition non déclarée est laissée intacte.
  defaults:                  # appliqué à chaque aérodrome sélectionné
    fuel: unlimited          # optionnel -> unlimitedFuel
    weapons: unlimited       # optionnel -> unlimitedMunitions
    aircrafts:               # types d'aéronefs proposés en slot dynamique
      <type DCS>: { amount: unlimited | <entier>, template: "<nom de groupe>" }
  airports:                  # optionnel. Absent -> TOUS les aérodromes de la coalition reçoivent `defaults`.
    <nom ou id>: { }                        # defaults seuls
    <nom ou id>: { aircrafts: { ... } }     # defaults + override par aérodrome
  exclude_airports:          # optionnel. Ces aérodromes ne reçoivent JAMAIS de slot, listés ou non.
    - <nom ou id>
  • exclude_airports est ce que l'action MCP set_airbase_coalition(…, dynamic_spawn: false) écrit : sans lui, un dynamicSpawn = false dans les warehouses de la mission était réactivé au build pour toute base d'une coalition déclarée sans liste airports: (mesuré sur GermanyCW-v6 : 61 aérodromes ouverts au lieu de 12). Une base à la fois listée et exclue reste fermée, avec un avertissement.

  • template référence un groupe-modèle par nom ; omettez-le pour l'auto-matcher à un groupe-modèle du même type d'aéronef (même coalition).

  • Les aérodromes ne peuvent être nommés que sur les théâtres installés présents dans la table versionnée (veaf-build update-dcs-data --airdromes) ; sinon utilisez l'id numérique (visible dans les warehouses de la mission : airports[<id>]).

Exemple minimal

blue:
  defaults:
    fuel: unlimited
    aircrafts:
      UH-1H: { amount: unlimited, template: "DST - UH-1H" }
  airports:
    Senaki-Kolkhi: {}

D'où vient la liste d'appareils proposés sur une base ?

C'est la question la plus fréquente sur les slots dynamiques, et la réponse n'est écrite nulle part dans warehouses.yaml : la liste est calculée au build.

Une base propose les appareils qui possèdent, dans la mission, un groupe-modèle de slot dynamique (dynSpawnTemplate) de sa coalition. Concrètement :

  1. vous placez dans l'éditeur de mission un groupe par type d'appareil, coché « modèle de slot dynamique » (ou vous le laissez faire par l'étape 3, dynamic-slot-templates.yaml) ;
  2. au build, l'étape warehouses recense ces groupes-modèles par coalition ;
  3. chaque aérodrome sélectionné reçoit tous ceux de sa coalition, en stock illimité, et un lien linkDynTempl vers le groupe-modèle correspondant.

C'est pourquoi un warehouses.yaml de trois lignes suffit à ouvrir toute la carte : la liste ne vient pas du fichier, elle vient des groupes-modèles présents dans la mission. Pour ajouter un appareil, ajoutez son groupe-modèle ; pour en retirer un, retirez le groupe-modèle.

Une liste aircrafts: explicite (dans defaults: ou dans l'override d'un aérodrome) remplace ce choix automatique : seuls les types que vous listez sont mis en stock.

DCS ne propose que ce que l'aérodrome peut garer

Même avec un stock et un groupe-modèle corrects, DCS ne propose un appareil que s'il existe une place de parking capable de l'accueillir. C'est une limite du terrain, pas de l'outil : un terrain qui n'a que des plots hélicoptères ne proposera jamais un avion, quoi que dise le stock.

Exemple mesuré sur la Open Training Syria (2026-08-31), toutes bases bleues avec dynamicSpawn actif et les modèles liés :

Aérodrome Places de parking Proposé
Akrotiri 41 places avion + 4 plots hélico avions et hélicoptères (vu en jeu)
Lakatamia 8 plots hélico seulement hélicoptères seulement (vu en jeu)
Naqoura 9 plots hélico seulement (pas de piste) hélicoptères seulement (vu en jeu)
Taftanaz 48 plots hélico seulement hélicoptères seulement (d'après les données)

Ce que fait l'outil. Il interroge le terrain avant de remplir : un aérodrome ne reçoit en stock que les catégories qu'il peut garer, et le stock devenu injouable (écrit par un build précédent) est retiré. Cela vaut aussi pour une liste aircrafts: explicite — DCS ignorerait de toute façon ce qu'il ne peut pas garer. Le filtrage est silencieux : aucun avertissement au build.

Portée. Les données de parking sont embarquées pour toutes les cartes sauf Iraq, Kola et Nevada. Sur ces trois théâtres — et sur un aérodrome absent des données — rien n'est filtré, le comportement est inchangé.

Comment le vérifier en jeu. Lancez la mission, choisissez le camp, ouvrez le sélecteur de slot sur l'aérodrome concerné : la liste proposée est celle que DCS peut réellement faire apparaître. Si un avion manque sur un terrain qui n'a que des plots hélicoptères, c'est le comportement attendu ; la solution est de choisir un autre aérodrome, pas de modifier le stock.


Étape 5 — Données de spawn (spawn-groups.yaml)

Les commandes marqueurs _spawn unit <alias> et _spawn group <alias> s'appuient sur deux tables Lua (veafUnits.UnitsDatabase et veafUnits.GroupsDatabase). Depuis la v6, ces tables ne sont plus codées en dur dans veafUnits.lua : elles proviennent d'un YAML, sont rendues en Lua et injectées dans le .miz au build de la mission (DCS ne sait pas lire du YAML à l'exécution). Voir ADR 0005.

Toujours active

Contrairement aux autres étapes, spawn_data s'exécute toujours (même sans fichier mission) car la base de spawn du framework doit être embarquée pour que _spawn fonctionne. Pour la désactiver entièrement :

pipeline:
  spawn_data: false

Étendre la base (src/spawn-groups.yaml)

Un fichier src/spawn-groups.yaml (optionnel) permet d'ajouter ou de redéfinir des unités/groupes pour une mission donnée. Il est fusionné par-dessus les données du framework :

  • un alias inédit est ajouté ;
  • un alias déjà présent dans le framework remplace l'entrée correspondante (override).

Schéma

units:                              # -> _spawn unit <alias>
  - aliases: [myaaa]                # un ou plusieurs alias (insensibles à la casse)
    unitType: ZSU-23-4 Shilka       # un type d'unité DCS

groups:                             # -> _spawn group <alias>
  - aliases: [mysam]
    disposition: {h: 3, w: 3}       # grille de placement en cellules (10m x 10m)
    units:
      - {type: ZSU-23-4 Shilka, cell: 1}
      - {type: Ural-375, random: true}                       # placé aléatoirement dans sa cellule
      - {type: Soldier M4, number: {min: 2, max: 4}, random: true}
    description: Mon site SAM
    groupName: MySAM

Champs d'une unité de groupe : type (requis), cell (cellule préférée), number (quantité, ou {min, max} aléatoire), hdg (cap), size (taille de cellule fixe en m), random (placement aléatoire dans la cellule), fitToUnit (cellule ajustée à l'emprise exacte de l'unité).

La base du framework est définie dans veaf_libs/data/veaf-units.yaml (embarqué dans l'outil).


Étape 6 — Variantes météo & horaire (versions.yaml)

Crée plusieurs variantes .miz à partir d'une mission de base, chacune avec une configuration de temps et/ou de météo différente.

Emplacement par défaut

<dossier-mission>/src/versions.yaml

Aussi accepté : versions.yaml  (racine du dossier mission)

Schéma

# ── Position géographique pour les calculs solaires (facultatif) ──────────
# Absente : un point par théâtre, sur la carte de la mission (vers Batoumi sur le Caucase…).
position:
  latitude: 33.5                        # degrés décimaux, -90 à 90
  longitude: 35.5                       # degrés décimaux, -180 à 180
  timezone: "Asia/Damascus"             # fuseau IANA, repli pour un théâtre inconnu (sinon : horloge DCS du théâtre)

# ── Date de base pour toutes les versions ─────────────────────────────────
base_date: "2024-03-15"                 # ISO 8601 (AAAA-MM-JJ)

# ── Variantes de mission ───────────────────────────────────────────────────
versions:
  - name: aube                          # REQUIS — nom de la variante (suffixe du fichier de sortie)
    time: "sunrise+30*60"               # expression horaire (voir ci-dessous)
    date: "today"                       # expression de date (voir ci-dessous, optionnel)
    metar: "METAR OSDI 151420Z 27015G25KT 9999 SKC 15/10 Q1018"  # optionnel

  - name: midi
    time: "12:00"
    weather:                            # météo manuelle (alternative au metar)
      temperature: 25.0                 # °C, plage -50..50
      wind_speed: 8.0                   # m/s, voulu à 10 m au-dessus du terrain de référence
      wind_direction: 270.0             # degrés (0=Nord)
      visibility: 9999                  # mètres
      cloud_type: "clear"               # clear | few | scattered | broken | overcast
      cloud_height: 2000                # base des nuages en mètres
      fog_enabled: false                # activer l'effet de brouillard

Champs de versions[]

Champ Type Requis Description
name string Oui Nom de la variante. Dans mission build, la sortie est missions/<NomDeBase>_<name>.miz (ex: aube → Ma-Mission_aube.miz) ; la forme nue <name>.miz n'existe qu'avec inject-weather autonome
time string Non Expression horaire — voir ci-dessous
date string Non Expression de date — voir ci-dessous
metar string Non Chaîne METAR complète — analysée pour les données météo, et affichable dans le briefing via ${METAR}
airport_icao string Non Code OACI dont la météo réelle est récupérée en ligne (utilisé sans metar)
weather objet Non Surcharge météo manuelle (utilisée sans metar ni airport_icao)
clearsky booléen Non Plafonne la météo à des conditions de vol à vue : nuages au plus FEW, vent simulé au sol du terrain de référence sous 15 kt, sans rafales, visibilité de 10 km ou plus, ni pluie ni brouillard. Garde la vraie météo d'un airport_icao tout en restant pilotable à vue ; le ${METAR} du briefing décrit le ciel plafonné. Défaut false

Afficher la météo dans le briefing : ${METAR}

Écrivez ${METAR} dans le briefing de la mission (dans l'éditeur DCS : Situation, ou l'une des tâches par camp) et le build le remplace par la météo de cette variante. Sept variantes météo donnent donc sept briefings différents, sans rien retaper.

Situation : vol de reconnaissance au nord du théâtre.

Météo au départ : ${METAR}

C'était l'objet de #40 : une mission étant reconstruite depuis ses sources à chaque build, tout ce qu'on tape à la main dans le briefing est écrasé au build suivant. La substitution résout ça en posant la valeur pendant le build.

Ce que ${METAR} vaut selon la variante :

La variante déclare ${METAR} affiche
metar: "..." la chaîne telle que vous l'avez écrite
airport_icao: LFRS le METAR réel récupéré pour cette station
metar: ou airport_icao:, avec clearsky: true un METAR recomposé depuis la météo plafonnée que vole la mission, construit comme pour weather: ci-dessous mais en gardant la station du relevé, sa température et son QNH — METAR LTAG 150203Z 35006KT 9999 FEW090 19/// Q1015. Toujours recomposé, même quand les plafonds ne changent rien : un TEMPO TSRA laissé dans le texte publié annoncerait un orage que le ciel n'aura jamais
seulement weather: un METAR composé à partir d'elle : vent, visibilité, pluie et brouillard, nébulosité et base (celle que vole DCS, qui ramène la base dans la plage de son preset de nuages), température (sans point de rosée : écrit ///), QNH de la mission, daté de la date et de l'heure de la variante en UTC, sans station — METAR 150900Z 27010KT 9999 SKC Q1013. Avec clearsky: true, ce sont les valeurs plafonnées
aucune météo rien — il n'existe aucun METAR à afficher, donc le texte ${METAR} reste tel quel et un avertissement le dit dans le log

Un METAR publié garde son heure

Un metar: écrit dans le fichier ou celui récupéré pour un airport_icao est affiché tel que publié, groupe horaire compris : un relevé récupéré le 2 à 18 h 20Z se lit 021820Z dans une variante qui commence à l'aube d'une autre date. Seul un METAR composé ou recomposé (weather:, ou clearsky: true) est daté de la date et de l'heure de la variante.

Un ${...} inconnu n'est jamais effacé

${METRA} reste écrit ${METRA} dans le briefing. C'est délibéré : un briefing est lu par des joueurs, et un trou à la place du texte se lit comme si le build avait mangé votre prose, alors qu'un nom visiblement mal orthographié vous dit quoi corriger.

Aucun appel réseau si vous ne l'utilisez pas

La récupération du METAR d'un OACI n'a lieu que si le briefing contient réellement ${METAR}.


Expressions horaires

Format Exemple Signification
HH:MM 14:30 Heure absolue (14h30 heure locale)
sunrise sunrise Heure du lever du soleil (à position:, sinon au point du théâtre)
sunset sunset Heure du coucher du soleil (à position:, sinon au point du théâtre)
Expression sunrise+30*60 Arithmétique — décalage en secondes
Secondes 54000 Secondes brutes depuis minuit

Expressions de date

Format Exemple Signification
ISO 8601 2024-03-15 Date spécifique
Mot-clé today, tomorrow, yesterday Relatif à la date d'exécution
Relatif +1, -7 Jours depuis base_date

Champs de l'objet weather

Champ Type Description
temperature nombre Température de l'air en °C
wind_speed nombre Vent voulu à 10 m au-dessus du terrain de référence, en m/s — pas le réglage de l'éditeur, que DCS multiplie jusqu'à 2,1 : le build écrit le réglage qui le donne (le vent)
wind_direction nombre Direction d'où vient le vent, en degrés (0 = Nord), comme dans un METAR
visibility nombre Visibilité en mètres ; 9 000 m ou plus s'écrit au maximum de DCS, 80 km — le 9999 d'un METAR, « 10 km ou plus »
cloud_type string clear | few | scattered | broken | overcast
cloud_height nombre Altitude de la base des nuages en mètres
fog_enabled booléen Activer l'effet de brouillard
precipitation booléen Pluie : choisit un preset de nuages pluvieux de DCS (RainyPreset…)
reference_airfield string Terrain où le vent est voulu (nom DCS) ; la station du METAR sur la carte l'emporte, le départ du premier groupe joueur est le défaut, le niveau de la mer le dernier recours
wind_gust nombre Rafale en m/s, changée en turbulence DCS (écart à la moyenne / 0,62, plafonné à 3 m/s)
turbulence nombre Turbulence en m/s, comme l'éditeur l'affiche ; l'emporte sur wind_gust
wind_veer nombre Rotation du vent vers la droite entre le sol et 2 000 m, de 0 à 30° (20 par défaut)
wind_speed_2000 / wind_direction_2000 nombre Vent à 2 000 m réglé à la main (m/s, d'où il vient) ; défaut : 2,2 fois le réglage au sol, tourné de wind_veer
wind_speed_8000 / wind_direction_8000 nombre Vent à 8 000 m réglé à la main ; défaut : celui de 2 000 m plus 3 m/s

La couverture et la base choisissent un preset de nuages DCS, le seul rendu depuis DCS 2.7 : le premier preset de cette couverture dont la plage d'altitude contient la base, sinon la base est ramenée dans la plage du plus proche (plages lues dans Config/Effects/clouds.lua de DCS). Un METAR fournit en plus la pression (Q1018, A2992), la pluie (RA, DZ, TS…) et le brouillard (FG).

Exemple minimal

position:
  latitude: 42.3
  longitude: 43.4
  timezone: "Asia/Tbilisi"

base_date: "2024-06-01"

versions:
  - name: aube
    time: "sunrise+20*60"
    metar: "METAR UGTB 010500Z 27010KT 9999 FEW030 18/10 Q1016"

  - name: après-midi
    time: "15:00"
    weather:
      temperature: 28.0
      wind_speed: 5.0
      wind_direction: 180.0
      cloud_type: "few"
      cloud_height: 2500


Voir aussi