-
-
Notifications
You must be signed in to change notification settings - Fork 8
Contributing
Thank you for your interest in contributing to this C# project! We welcome all contributions, whether it's bug reports, feature requests, code improvements, or documentation updates.
- Git
- Visual Studio
- .NET 8 SDK
- DCS-BIOS installed in your DCS World Saved Games folder (see Home for details)
Bort or any other DCS-BIOS reference tool to help you find the right addresses and values.
This is where you get identifiers like CDU_BRT that you pass to RegisterUInt / RegisterStr / RegisterLight:
RegisterUInt("CDU_BRT", v => { /* handle v */ });
RegisterStr("UFC_LINE1", s => { /* handle s */ });- Fork this repository.
- Clone your fork locally:
git clone --recurse-submodules <your-forked-repo-url>
If you use Visual Studio, select the McduDcsBiosBridge repository
- Create a new branch for your feature or bug fix:
git checkout -b my-feature-branch
Branch naming examples:
fix-issue-123add-new-featurefeat(aircraft)/add-new-featurefix/issue-123docs/update-readme
- Follow the existing coding style and conventions.
- Target
.NET 8. -
Naming convention for private fields: prefix private
DCSBIOSOutput?fields with_(e.g._CDU_BRT,_IAS).
Aircraft are driven by a single registry and detected automatically from the DCS-BIOS MetadataStart/_ACFT_NAME value — there is no CDU menu to edit anymore.
Look up the aircraft's module number in dcs-bios_modules.txt (for example: F-14 = 16) and its _ACFT_NAME value (use Bort, or run the program and start the aircraft in DCS — the wait screen shows the name as "unsupported").
Add a class in Aircrafts/ deriving from AircraftListener. Implement two methods: wire the CDU and wire the front panels. Use RegisterUInt / RegisterStr to resolve and register in one call — no field declarations needed for single-use outputs. (See the existing Aircrafts/*_Listener.cs files for real examples.)
using WwDevicesDotNet;
namespace WCtrlDcsBiosBridge.Aircrafts;
internal class F14_Listener : AircraftListener
{
// Only declare a field when the same output is used in MORE than one method.
private DCSBIOSOutput? _CONSOLE_BRT;
public F14_Listener(UserOptions options)
: base(AircraftRegistry.F14, options)
{
}
// Only override InitializeDcsBiosOutputs when you need array loops or
// multi-use fields. Leave it out entirely for simple listeners.
protected override void InitializeDcsBiosOutputs()
{
_CONSOLE_BRT = ResolveUInt("CONSOLE_BRT");
}
// Wire CDU outputs. Runs only when a CDU is connected.
protected override void RegisterCduControls()
{
RegisterStr("PLT_CAP_DISPLAY", s =>
GetCompositor(DEFAULT_PAGE).Line(0).Green().WriteLine(s));
RegisterUInt("MASTER_CAUTION", v => SetCduLeds(fail: v == 1));
RegisterLight(_CONSOLE_BRT, v =>
{
int percent = (int)(v * 100 / _CONSOLE_BRT!.MaxValue);
SetBacklightBrightnessPercent(percent);
SetDisplayBrightnessPercent(percent);
SetLedBrightnessPercent(percent);
});
}
// Wire frontpanel outputs (FCU/EFIS, PAP3, AGP32...). Always runs, even
// with no CDU, because a frontpanel-only setup still needs the data.
protected override void RegisterFrontpanelControls()
{
// Leave empty if the aircraft has no frontpanel data, or populate
// FlightDeck, e.g.:
// RegisterUInt("IAS_US_INT", v => FlightDeck.Speed = (int)v);
}
}Add an AircraftDescriptor in Aircrafts/AircraftRegistry.cs and include it in the All list (registry order = menu order). Provide the module id, display name, JSON and font files, the HasSeatSelection flag, the DCS-BIOS name(s) for auto-detection, and the listener factory.
public static readonly AircraftDescriptor F14 = new(
16, // module id (dcs-bios_modules.txt)
"F-14", // display name
"F-14.json", // DCS-BIOS json file for this module
"resources/a10c-font-21x31.json", // a font from resources/
false, // HasSeatSelection (true only for CH-47F today)
new[] { "F-14B", "F-14A-135-GR" }, // _ACFT_NAME value(s) for auto-detection
c => new F14_Listener(c.Options)); // listener factory
// ...then add it to the All list:
public static readonly IReadOnlyList<AircraftDescriptor> All = new[]
{
A10C, AH64D, FA18C, CH47, F15E, M2000C, F16C, OH58D, F14,
};Dual-seat aircraft: set
HasSeatSelection: trueand give the listener anisPilotparameter, like the CH-47F:c => new CH47F_Listener(c.Options, c.IsPilot, c.Ch47SwitchWithSeat).
Font: start by reusing an existing resource —
resources/a10c-font-21x31.jsonorresources/ah64d-font-21x31.json. A font file maps a fixed character set to bitmap glyphs; if every character you render already looks correct, there is no point duplicating a font just to give it a new name. Create a dedicated font only when you need to design a special bitmap for a specific character code.
Only if your aircraft needs user settings (page-switch keys, toggles). You only touch two files — the options panel wires itself up from these.
a. An options class in Config/UserOptions.cs: add one property to UserOptions plus a small class.
// in UserOptions:
public F15EOptions F15E { get; set; } = new();
public class F15EOptions
{
public string ShowXxxKey { get; set; } = "NextPage";
}b. One UI section in UI/OptionsPanel.xaml: a HeaderedContentControl with the shared AircraftSection style. The Header must equal the descriptor's DisplayName — that alone gives you the title and the automatic "disabled while this aircraft is running" behaviour.
<HeaderedContentControl Style="{StaticResource AircraftSection}" Header="F-15E">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,4">
<TextBlock Text="Show Xxx Key:" VerticalAlignment="Center" Width="120"/>
<ComboBox ItemsSource="{x:Static ui:OptionsPanel.McduKeyNames}"
SelectedValue="{Binding F15E.ShowXxxKey, Mode=TwoWay}"
SelectionChanged="ComboBox_Changed" Width="150"/>
</StackPanel>
</StackPanel>
</HeaderedContentControl>UI strings live in WinUI .resw resource files, one folder per language, under Strings/:
Strings/en-us/Resources.resw (English — source of truth for keys)
Strings/fr-fr/Resources.resw (French)
Strings/de-de/Resources.resw (German)
Strings/es-es/Resources.resw (Spanish)
Every <data name="KeyName"> entry has the same name across all languages; only the <value> text differs. Strings are looked up at runtime through Common/Strings.cs (Strings.Get("KeyName")), not standard XAML x:Uid — see the comment at the top of that file for why.
- Open the
Resources.reswfor the language you want to fix (e.g.Strings/fr-fr/Resources.resw). - Find the
<data name="...">entry and edit its<value>text. Leave thenameattribute untouched — it's the lookup key shared across all languages. - Run the app and use the language toggle button (top-right, cycles System → your Windows language → the other supported languages) to switch to the language you edited, then check the affected screen.
-
New resource file: copy
Strings/en-us/Resources.reswtoStrings/<locale>/Resources.resw(e.g.Strings/it-it/) and translate every<value>, keeping allnamekeys identical to the English file. -
Enum: add a member to
LanguagePreferenceinConfig/LanguagePreference.cs. -
Detection: add it to
LanguageDetector.SupportedLanguagesand to the two-letter mapping inLanguageDetector.MatchLanguageinCommon/LanguageDetector.cs. -
Resource context: add the enum → locale-tag mapping (e.g.
"it-IT") in theswitchinsideStrings.BuildContext()inCommon/Strings.cs. -
Toggle UI: add the short code (e.g.
"IT") and tooltip case inMainWindow.xaml.cs(UpdateLanguageToggleIcon, near the existingLanguagePreference.French => "FR"cases). The tooltip needs a matchingLanguageTooltip_<Language>key added to everyResources.resw, including the new one.
No csproj changes are needed — .resw files under Strings/ are picked up automatically by the build.
| Helper | Use |
|---|---|
RegisterUInt(id, v => ...) |
Resolve + register an integer output in one call. |
RegisterUInt(id, (ctrl, v) => ...) |
Same, but passes the resolved DCSBIOSOutput as ctrl so you can read ctrl.MaxValue inside the handler. |
RegisterStr(id, s => ...) |
Resolve + register a string output in one call. |
ResolveUInt(id) |
Resolve an integer output for later use (multi-use fields or array loops). |
ResolveStr(id) |
Resolve a string output for later use. |
RegisterUInt(output, v => ...) |
Register a pre-resolved integer output. |
RegisterStr(output, s => ...) |
Register a pre-resolved string output. |
RegisterLight(id, v => ...) |
Like RegisterUInt, but skipped automatically when the user has Disable Lighting Management turned on. Use for brightness knobs and cockpit light controls. |
RegisterLight(id, (ctrl, v) => ...) |
Same, but passes the resolved DCSBIOSOutput as ctrl. |
RegisterLight(output, v => ...) |
Same, for a pre-resolved output. |
RegisterRaw(address, v => ...) |
Low-level handler for raw bitfield registers when named DCS-BIOS outputs are unavailable or have incorrect mask/shift definitions. v is the raw unmasked 16-bit register value; apply bitmasks manually. |
GetCompositor(DEFAULT_PAGE).Line(n)... |
Write a CDU line (.Green(), .White(), .WriteLine(...), ...). |
SetCduLeds(fail:, fm1:, fm2:, fm:, ind:, rdy:) |
Set CDU status LEDs. |
SetDisplayBrightnessPercent / SetBacklightBrightnessPercent / SetLedBrightnessPercent
|
CDU brightness (0–100). |
FlightDeck |
Semantic front-panel state — see table below. |
HasCdu, CduDevice
|
Whether a CDU is connected / the underlying device. |
Populate these in RegisterFrontpanelControls(). Renderers read whatever properties their device can display; leave anything your aircraft does not provide as null.
| Property | Type | Meaning |
|---|---|---|
Speed, Heading, Altitude, VerticalSpeed
|
int? |
Indicated airspeed (kt), heading (°), altitude (ft), vertical speed (ft/min). |
BaroPressure |
int? |
Barometric pressure in inHg × 100 (e.g. 2992 = 29.92 inHg). |
GearLeftDown, GearNoseDown, GearRightDown
|
bool? |
Gear down-and-locked indicators. |
GearWarning |
bool? |
Gear handle red warning light. |
ClockUtcTime |
string? |
UTC time as "HHMMSS" (e.g. "123456" = 12:34:56). |
ClockChrono |
string? |
Chronograph as "MMSS" (e.g. "0145" = 1 min 45 s). |
ClockElapsedTime |
string? |
Elapsed time as "HHMM" (e.g. "0012" = 12 min). |
ConsoleBrightness |
byte? |
Cockpit console backlight, 0–255. |
SegmentBrightnessPercent |
int |
7-segment display brightness, 0–100 (default 100). |
There is no automated test suite (most tests require the physical device). Please:
- Review your code carefully for errors or typos.
- Test with DCS running and your hardware connected.
git commit -m "Description of my changes"
git push origin my-feature-branchThen open a Pull Request on GitHub with a clear description of the changes and why they are needed.
- Adhere to the existing code style and conventions.
- Write clear, concise commit messages.
- Keep changes focused on one issue or feature.
Q: What if I found a bug? Check if the bug is already reported. If not, open a new issue with steps to reproduce it.
Q: Can I contribute to the documentation? Absolutely! Fork, clone, branch, edit the wiki or docs, and submit a PR.
Q: How do I know if my changes are acceptable? Follow the coding standards, test your changes, and ensure they are meaningful and well-explained.