Do you have a mod which interfaces with another mod? Do you want that mod to function with or without that other mod? Do you want your mod to be an optional dependency for other mods?
Preprocessor Directives might help you out! While there is no official standard for preprocessor directives, the below code block is a script file which I have included in my mods to flag their presence.
/**
* AG0 H47Chinook Preprocessor Directives
*
* This file handles conditional compilation flags for optional mod dependencies.
* It's named with "!" prefix to ensure it's compiled before other scripts.
* Defines are only valid in the module they are defined in, thus this script is defined in Scripts/Game, so references in other modules will fail.
*
* For mod developers:
* - If your mod may interface with this one, but you don't have this mod as a dependency, wrap code which interfaces with this mod using:
*
* #ifdef AG0_H47Chinook
* owner.FindComponent(AG0_CMWS_CountermeasuresComponent)
* #endif
*
* This ensures that the code is compiled only when the flag is set. If it's not, which it won't be if this mod is not loaded,
* it will ignore that code as if it never existed.
*/
#define AG0_H47Chinook
From my understanding, and it is certainly not a fact, the cleanest way to make your mod interoperable with other mods is to define in your mod a script file which defines a preprocessor directive. A preprocessor directive is essentially a variable, an argument, or a rule which tells the compiler of your scripts whether or not to compile certain portions. A common pre-processor directive is seen below:
#ifdef WORKBENCH
Print("Run me when I am loaded in workbench!");
#endif
By using preprocessor directives, and having more mods define them, we can more easily create compatible systems without being forced to use dependency relationships. For example, with the Multifunction Display Framework, it should not be necessary to have WCS_Armament as a dependency as it may be used on vehicles that don’t have or need countermeasures. Thus - by using the ifdef directive, I can create code which will only run when that mod is loaded - assuming that mod defines a directive correctly.
It is recommended for your directive to follow established naming standards for scripts, and to keep it simple - you can use your mod name prefixed with your TAG for the file name and definition. As noted above, by prefixing script name with exclamation point, you ensure your directive is loaded prior to and compilation of other scripts which might be compiled after the directive otherwise.
⚠️ Mod Load Order Caveat
Script-only
#definedirectives are only guaranteed to be seen by files compiled after the define file within the same mod. However, if mod load order causes another mod's scripts to compile before your!-prefixed define file, those scripts will not see the define and any#ifdefblocks will be silently skipped — even if your mod is loaded.
The more reliable approach is to declare your define via Project Script Modules in Workbench project settings. Defines set there are injected at the module level before any script compilation occurs, making them immune to file and mod load order issues. This is the recommended approach for any define that other mods need to reliably detect.
To set a define via project settings: open your
.gprojfile in Workbench, navigate to Script Modules, find the relevant module (e.g.Scripts/Game), and add your define to the Defines field. Keep the script file with#defineas a fallback for developers who reference your mod directly, but treat the project setting as authoritative.
if ("TAG_ModClass".ToType())
// that mod is loaded
You can use scripting to check if a class exists, using a “soft” class type check. However, any references to that class directly, like doing the following:
TAG_ModClass.Update(timeslice)
Will result in a failure to compile, so this method is limited to being able to “see” but you can’t “touch” anything with that class. This could be used to see if a mod is loaded or not, but you can’t meaningfully interact with that mod without them having a preprocessor directive defined as explained above.
| Approach | Who edits prefab? | Hard dependency? | Works without framework? | Multi-framework support? | Use case |
|---|---|---|---|---|---|
| Script runtime detection | N/A (script only) | ❌ No | ✅ Yes (code path not taken) | ✅ Check for class/types of both | Pure script logic via ToType() or #ifdef; no prefab changes |
| Framework-side prefab overrides | Framework mod | ❌ No (soft) | ✅ Yes (override never applied) | ⚠️ Yes, but load order decides winner | Framework (AHC, NVG, etc.) patches 3rd-party prefabs when loaded |
| Consumer-side optional components | Content mod (vest, heli, etc.) | ❌ No | ✅ Yes (components just no-op) | ✅ Embed components from multiple frameworks | Content mod opts into framework features without hard dep |
| Hard dependency / compat mod | Third-party compat mod | ✅ Yes | ❌ No | ⚠️ Only via multiple compat mods | Classic A↔B bridge mod; all three must load together |
| Shared standard / API | All participants | ⚠️ Depends on design | ✅ Usually (fallback behavior) | ✅ That's the point | Common API/defines that multiple frameworks implement |
Key tradeoffs: