Preprocessor Directives

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.

Check for Type

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.


Design Space Overview

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: