This page covers one aircraft part – DA_EnginePart (UDA_EnginePart).
It defines the thrust-vectoring limits and axis multipliers for each engine.
The actual deflection angle is calculated at runtime from the pilot’s flight-control input.
For ModKit thrust vectoring, this is the only Data Asset that defines the runtime deflection limits and axis multipliers.
1. Create and assign the part
- Content Browser → Add → Miscellaneous → Data Asset → class
DA_EnginePart(UDA_EnginePart). - Name – Latin characters, no spaces, for example
DA_MyPlaneEnginesDefault. - The asset goes into the mod content:
Plugins/GameFeatures/<ModName>/Content/DataAssets/.
2. Structure
- ModeGroups[] – optional mode records. For thrust vectoring, only one
Mode = VTOLrecord is used.- Mode – the record’s mode: VTOL / Plane / Ground
- Engines[] – one record per ENGINE (order = engine order in the JSBSim config)
- KinematicGroup – the config carrier for THIS engine
- GroupName – any name: an editor label (the runtime does not read it)
- BoneStates[0] – the ENGINE CONFIG; the only record that is read
- BoneName – any non-empty name: an editor label
- OpenRotationDegrees – defines the the maximum rotation applied around the engine’s X, Y, and Z axes. In FPS2, these components are exposed as Roll, Pitch, and Yaw.
- OpenTranslation – multiplier: deflection direction and scale
- BoneStates[1..] – NOT part of the deflection config: it reads the first one only
- KinematicGroup – the config carrier for THIS engine
- Engines[] – one record per ENGINE (order = engine order in the JSBSim config)
- Mode – the record’s mode: VTOL / Plane / Ground
For engines KinematicGroup is not animation but a config carrier: only its first bone record is read, and only two of its fields. The names (GroupName, BoneName) are labels for your own order in the asset: thrust vectoring matches records by position, not by name.
For VTOL this is critical. Thrust vectoring works only through KinematicGroup records: no Mode = VTOL record, or no Engines[i] record for an engine – physics has nothing to read and the engine will not deflect.
3. Maximum deflection angles – OpenRotationDegrees
A 3D vector representing angular limits in degrees (X = Roll, Y = Pitch, Z = Yaw).
These values define the maximum deflection for each axis, not a static rotation. Neutral stick produces zero deflection, while full stick drives each axis toward its configured limit, subject to the runtime thrust-vectoring envelope.
The runtime flight model calculates the instantaneous angle each frame based on pilot input.
| Component | Axis | What it sets |
|---|---|---|
| X | Roll | Maximum thrust vector deflection on roll command |
| Y | Pitch | Maximum thrust vector deflection on pitch command |
| Z | Yaw | Maximum deflection on yaw command (differential tilt on paired engines produces a yaw moment) |
What matters:
- The configured value is the maximum angle for that axis, subject to the runtime thrust-vectoring envelope.
- The system enforces a conical gimbal envelope constrained by the effective pitch limit (Y × OpenTranslation.Y). Consequently, if the pitch limit resolves to zero, the total angular envelope collapses, preventing any yaw vectoring as well.
(0, 0, 0)– the engine does not deflect at all (normal for fixed/mid engines).- The validator does not impose a range on these values.
4. The multiplier – OpenTranslation
Despite its name, OpenTranslation is not a position or translation value. In the engine configuration it acts as a per-axis multiplier.
| Value | What it does |
|---|---|
1 | as is |
−1 | mirrored: deflection in the opposite direction on that axis |
0.5, 2, … | scales the resulting deflection angle |
0 | the engine does not deflect on that axis |
Formula: Actual deflection angle = normalized stick input × maximum angle × axis multiplier.
The multiplier is how paired engines are differentiated: Z = −1 on one and Z = 1 on the other gives differential yaw.
With symmetric engines and equal thrust, equal Z signs make the engines vector in the same yaw direction, so they do not produce a differential yaw moment.
5. The deflection config comes from the first bone only
The thrust vectoring config is read from exactly one record of the group – BoneStates[0]: its OpenRotationDegrees and OpenTranslation. Records after the first take no part in that config: they belong to other bones of the engine (nacelle petals, for example) with their own angles and do not affect thrust vectoring.
Why this matters:
- Limits and multipliers placed outside the first record of the group are invisible to physics: the engine will not deflect, and no error appears – the asset stays valid.
- A
KinematicGrouprepresents one engine. EachEngines[i]entry must have its own group. - An engine equals its own
Engines[i]record with its ownKinematicGroup.
For thrust vectoring only the first record of the group matters: the order of the remaining records does not affect it.
6. Order is critical
Engines[i] is engine #i in the order of your aircraft’s JSBSim config (the engines section of Propulsion.xml). Matching is by record position, not by name: neither GroupName nor BoneName affects it.
- Open the aircraft’s JSBSim config (
.../Resources/aircraft/<JSBSimConfigName>/Propulsion.xml). - Determine the order in which the engines are declared in
Propulsion.xml. - Create the
Engines[]records in exactly that order.
Get the order wrong and the limits and signs go to the wrong engine: the wrong engine receives the deflection parameters, and the corresponding nacelle animation will also be incorrect.
The order of the mode records themselves does not matter: the required record is looked up by the Mode field.
7. How it works
[your DA_EnginePart asset]
-> when the aircraft is granted to a player: the aircraft's server-side record (a copy of your groups)
-> when the flight model initializes: physics takes the config ONLY from the Mode = VTOL record,
one config per engine
-> every frame: actual angle = stick × maximum angle × multiplier
-> the calculated orientation is applied to the engine's thrust vector in JSBSim
and into the animation state: the same calculated orientation is used by the animation system to rotate the nacelle
- The part provides limits and multipliers, not animation poses: the pose is computed every frame by the flight model from the player’s current stick position.
- The config is captured once when the flight model initializes (and when it is recreated). Editing the asset “on the fly” for an already granted aircraft will not be picked up – respawn or recreate the aircraft to reload the configuration.
- The very same angle goes to both physics and visuals: the nacelle always shows the real thrust vector direction.
8. Plane mode: no record is required
A record with Mode = Plane is not needed, and its absence is normal: no error appears.
- Thrust vectoring physics reads the config only from the
Mode = VTOLrecord. - The Plane mode engine layer does not use
DA_EnginePartfor engine vectoring.
So a Plane record, if you add one, affects nothing. Engine/nacelle animation in Plane mode is controlled by the AnimBP, not by DA_EnginePart.
9. Visuals are not here
Nacelles are driven by the animation graph: Get Engine State (Index – engine number) → FinalRotation. Maximum angles and multipliers are already accounted for inside that angle.
The AnimBP must read FinalRotation and apply it to the nacelle.
See the AnimBlueprint page for details.
10. Validation
| Error | What is wrong |
|---|---|
Mode = None | A mode record has no mode selected |
duplicate Mode | More than one record with the same Mode |
| mode record without engines | Engines holds no records |
empty GroupName | The KinematicGroup has no name |
| group without bones | BoneStates is empty |
empty BoneName | A bone record has no name |
The following are not errors: an empty ModeGroups (an empty part is valid), zero and any other OpenRotationDegrees / OpenTranslation values, duplicate bone names (only a non-empty name is required).
Contract validation is separate: the part’s AircraftIds must contain the contract’s AircraftId.
11. Verify
Verify functionality by observing physics and animation in-game: switch the aircraft to VTOL mode and deflect the flight control sticks.
| What you see | Cause | What to do |
|---|---|---|
| Engines do not vector | Aircraft is not in VTOL mode | Switch flight mode to VTOL |
| One engine remains static | Missing `Engines[i]` array entry | Add the corresponding engine entry |
| Neither pitch nor yaw deflection | Pitch limit resolves to zero (Y × OpenTranslation.Y = 0) | Set non-zero `Y` rotation and multiplier |
| Wrong engine vectors | Array order does not match JSBSim | Reorder `Engines[]` entries to match `Propulsion.xml` |
| Engines vector in sync, but no yaw is produced | Paired engines share identical Z signs | Invert one side: set Z = -1 on one and Z = 1 on the other |
| Nacelles do not rotate visually | AnimBP missing state reading node | Add Get Engine State to the AnimGraph |
| Changes not reflected in-game | Asset modified after aircraft spawned | Respawn or recreate the aircraft to reload the configuration. |
The nacelle shows the actual angle, not the maximum from the part: if at full stick it does not reach the expected angle, the engine-vectoring configuration is the first thing to check (limit too small, zero or wrong multiplier, no record) – not the animation.
12. Example: full stick – 45°
| Where | Value |
|---|---|
ModeGroups[0].Mode | VTOL |
Engines[0].KinematicGroup.GroupName | Engine_FR |
Engines[0].KinematicGroup.BoneStates[0].OpenRotationDegrees | 45, 45, 45 |
Engines[0].KinematicGroup.BoneStates[0].OpenTranslation | 1, 1, −1 |
Engines[1].KinematicGroup.GroupName | Engine_FL |
Engines[1].KinematicGroup.BoneStates[0].OpenRotationDegrees | 45, 45, 45 |
Engines[1].KinematicGroup.BoneStates[0].OpenTranslation | 1, 1, 1 |
The result:
- Pitch – both engines deflect 45° in the same direction.
- Yaw – the engines deflect in opposite directions, producing a differential yawing moment.
- Roll – the configured roll component reaches 45° at full input.
Example part in the kit: /ModExample/DataAssets/DA_ModExampleEngine_Default – one VTOL record and two engine records.
13. Checklist
- The
DA_EnginePartasset exists and is assigned in the contract (Engine Part). AircraftIdscontains the contract’sAircraftId.- A
Mode = VTOLrecord exists (exactly one). - It holds one record per engine in the JSBSim config order.
- Every record has its first bone filled in:
OpenRotationDegreesandOpenTranslation. - No
Plane/Groundrecords are added, and none are needed. - Part and contract validation pass without errors.
- In VTOL, the nacelles follow the calculated thrust-vector deflection and reach the configured maximum at full input.
