Cross-mod compatibility
A patch rarely runs alone. The base game's patches, Redux's patches, and other mods' patches all touch the same assets. Writing a patch that coexists with that, instead of fighting it, is mostly a matter of using the tools from Dependencies and ordering deliberately. This page collects the practices.
Lean on namespacing
Every patch id is modId:patchName, and the mod id is prepended for you. You do not have to worry about another mod using the same patch name as you, because the namespaces keep them apart. The one thing you control is keeping your own mod id stable and identifier-safe, since everything else keys off it.
Declare what you depend on, do not assume load order
If your patch only makes sense when another mod is present, say so with :Needs. Do not rely on the other mod happening to load first, and do not let your patch error against content that is not there:
PM.Parts:Patch("RetuneTheirEngine")
:Needs("EnginePack")
:Named("their_engine_id")
:Do(function(part) ... end)With :Needs, your patch runs only when EnginePack is on. When EnginePack is not on, PatchManager removes the patch and records this in the summary. :Conflicts works the same way for a mod whose changes must not apply together with your changes.
Each campaign has its own feature set. A mod is on in a campaign when it is installed and its default feature is on in that set. Thus an installed mod that a campaign has turned off does not satisfy :Needs, and does not trigger :Conflicts.
Prefer the default pass, order only where you must
The strongest thing you can do for compatibility is to leave your patch in the Default pass and Default bucket. That keeps you in the cooperative middle, where other patches can order around you. Grabbing :Early():First() to "make sure my change wins" is the opposite: it forces you to the front and makes you the patch everyone else has to work around. Reserve the passes for their real roles (collect early, finalize late) and order against specific patches with :Before / :After only when you have a concrete reason. See The patch lifecycle.
Patch the difference, not the whole thing
A patch that sets one field stays compatible with a mod that sets a different field on the same asset, because they do not collide. A patch that replaces a whole list or object stomps anything another patch did to it. So change the narrowest thing that achieves your goal:
-- Compatible: adds to the list, leaving other entries (and other mods' additions) intact.
node.UnlockedPartsIDs:Append("my_new_part")
-- Risky: replaces the whole list, discarding anything anyone else added.
node.UnlockedPartsIDs = { "my_new_part" }Use the list and object methods (:Append, :RemoveWhere, :Patch) to make surgical changes instead of wholesale replacements when you can.
Gate on what is actually there
When you patch a broad set of assets, guard the parts that might not apply to every one with gates. :Has and :HasNo keep your patch from assuming structure that another mod may have changed, and they report a clean skip instead of an error when an asset is not in the form you expected.
Read the summary against a full modlist
The real test of compatibility is the summary of a campaign that has the other mods installed and on. It shows the result of each of your patches:
The patch applied.
A dependency or a feature removed the patch.
The patch errored on content that a different mod changed.
When you support a combination of mods, examine the summary of a campaign that has that combination on, not only your mod.