Skip to content

Module Manager Handbook

Lisias T edited this page Mar 17, 2024 · 1 revision

Module Manager Handbook

This section covers the most basic applications of Module Manager, which tend to be the most asked questions in the Module Manager Official Thread. It goes through the main operations in a quick and simple way. For a more detailed description, see Module Manager Syntax.

Keep in mind the following nomenclatures:

  • NODE - Content is written between curly brackets:
    • MODULE { }
    • RESOURCE { }
    • PROP { }
  • Key - Items that can have a value after it:
    • name = mk2LanderCabin
    • maxThrust = 1500
    • description = The mobile processing lab was developed to (...)

Operations

Common Syntax

  • Operators
    • "nothing", for creating a new node
    • @ for edit
    • + or $ for copy
    • - or ! for delete
    • % for edit-or-create.
  • Filters
    • * for any number of alphanumeric chars
    • ? for any single alphanumeric character. This is also applied in case of "space" or special chars.
    • @ for including nodes in filter
    • - or ! for excluding nodes from filter
    • # for including keys in filter
    • ~ for excluding keys from filter
    • :HAS[<node>] for searching only files that have in filter
    • :NEEDS[<modname>] Patch is applied only if given mod is installed.
  • Additional
    • & or , for "AND"
    • | for "OR"
    • :Final forces the patch to be applied lastly (in case multiple files edit the same node)

Note that HAS blocks currently do not support the usage of OR or |. Situations where a patch needs to apply to two seperate requirements will require two seperate patches.

Examples and details

Creating or editing using operators:

// Edit a PART node named "SomePart"
@PART[SomePart]
{
// Change SomePart's mass to 0.625
@mass = 0.625
// Change the description to a new text
@description = SomePart: now uses Xenon!
// Edit SomePart's node MODULE named "ModuleEngines"
@MODULE[ModuleEngines]
{
// Change maxThrust to 225
@maxThrust = 2.25
// Edit SomePart's node PROPELLANT named "LiquidFuel"
@PROPELLANT[LiquidFuel]
{
// Change the PROPELLANT node name from LiquidFuel to XenonGas
@name = XenonGas
// Change the ratio value
@ratio = 1.0
}
// Edit SomePart's node atmosphereCurve. Note that this node doesn't have a name.
@atmosphereCurve
{
// Edit the FIRST "key" Key from the "atmosphereCurve"
@key,0 = 0 390
// Edit the SECOND "key" Key from the "atmosphereCurve" property
@key,1 = 1 320
}
// Remove the node PROPELLANT named "Oxidizer" from the PART
!PROPELLANT[Oxidizer] {}
}
// Create a new node RESOURCE in the PART
RESOURCE
{
// Add a name to the node RESOURCE
name = ElectricCharge
// Add "amount" and its value to this node
amount = 100
// Add "maxAmount" and its value to this node
maxAmount = 100
}
}

If you make a .cfg file with an entry that looks like this:

PART
{
name = myPart
...(stuff)
}

You're defining a new part named "myPart". Then, if another .cfg file somewhere does this:

@PART[myPart]
{
...(stuff)
}

That is saying: "at the PART named 'myPart', edit the following additional stuff...". If you don't put the @ operator before the NODE, instead of editing an existent one, you will create a new one:

PART[myPart]
{
...(stuff)
}

This way, now you have two PARTs named "myPart".

Filtering by numbers

It's also possible to filter Nodes and Keys by numbers. This is useful when there's multiple and nameless (or under the same name) nodes and Keys on a config file.

Keys

If there are two or more Keys with the same name, you can refer to them like this:

@example,0 = <...> finds the first "example" Key or on the list (this is the same as @example = <...>)

@example,1 = <...> finds the second one.

@example,2 = <...> finds the third, and so on.

@example,* = <...> finds all the "example" Keys, and edits all of them.

@example,-1 = <...> finds the last "example" Key.

The same thing works for !example,0, etc.

Nodes

The same is applied to nodes without names, as follows:

!EXAMPLE,0 {}

Looks for the first "EXAMPLE" node in the section and deletes it.

@EXAMPLE,*
{
...(stuff)
}

Looks and edits all the "EXAMPLE" nodes in the section.

@MODULE[Example],1
{
...(stuff)
}

Looks for all the "Example" MODULES. Filters the second one and edits it. Note that this is a named MODULE, but this doesn't prevent you from filtering them by numbers.

Editing Multiple Parts

You can apply changes to multiple parts at the same time, using the * filter.

Specific names

@PART[B9_*]
{
...(stuff)
}

This will edit all the PART nodes that has a name beginning with "B9_", and have anything else after it.

@PART[B9_*]
{
@MODULE[Module*Drill]
{
...(stuff)
}
}

This will edit only ONE module in all beginning with "B9_" parts. If you want to edit all modules in all parts, use:

@PART[B9_*]
{
@MODULE[Module*Drill],*
{
...(stuff)
}
}

Specific nodes

@PART[*]:HAS[@MODULE[ModuleEngines]]
{
...(stuff)
}

This will look for all PART nodes, but will filter for only those who contain ModuleEngines MODULE.

@PART[*]:HAS[!MODULE[ModuleCommand]]
{
...(stuff)
}

Like the previous one, this will look for all PART nodes, but will filter for only those who don't contain ModuleCommand MODULE.

Specific Keys

@PART[*]:HAS[#category[Utility]]
{
...(stuff)
}

This will look for all PART nodes, and filter for those who have a category = Utility Key. Note that this category must not be inside any other node. It must be directly inside the mentioned PART.

@PART[*]:HAS[~TechRequired[]]
{
...(stuff)
}

This will look for all PARTs that DON'T have any TechRequired = Key.

@PART[*]:HAS[#TechRequired]
{
...(stuff)
}

This will look for all PARTs that DO have TechRequired = Key with any value

Specific Configuration

@PART[*]:HAS[@RESOURCE[MonoPropellant]:HAS[#maxAmount[750]]]
{
...(stuff)
}

This will look for all PARTs that have the MonoPropellant RESOURCE. And from these, it will filter again for only those RESOURCE nodes that have a maxAmount = 750 Key.

@PART[*]:HAS[@MODULE[ModuleEngines]:HAS[@PROPELLANT[XenonGas]]]
{
...(stuff)
}

This will look for all PARTs who have a ModuleEngines MODULE using XenonGas as a propellant.

Combined Search

@PART[*]:HAS[@MODULE[ModuleEngines] , @RESOURCE[SolidFuel]] {
...(stuff)
}

This filters for all PARTs who have a ModuleEngines MODULE and have a SolidFuel RESOURCE at the same time.

@PART[*]:HAS[ @MODULE[ModuleEngines] :HAS [ @PROPELLANT[XenonGas] , @PROPELLANT[ElectricCharge] ] ]
{
...(stuff)
}

This goes for all PART thats have ModuleEngines containing XenonGas, and ElectricCharge at the same time. (Space added for clarity)

Even deeper

@PART[*]:HAS[!RESOURCE[ElectricCharge],@RESOURCE[*]]
{
...(stuff)
}

All PARTs without ElectricCharge as a resource but with any other.

Arrays

Take 7th number in an array, separated by ,, and set it to 4

// node_stack_top = 0.0, .9, 0.0, 0.0, 1.0, 0.0, 2
@node_stack_top[6] = 4

Take second numbers in an array, separated by , in all key keys, and multiply by 2

@TemperatureModifier
{
//key = 0 150000 //key = 750 75000 @key,*[1, ] *= 2
}

Some useful examples

@PART[*]:HAS[~TechRequired[]]:Final
{
TechRequired = advScienceTech
}

Adds a tech level to all PARTs who don't have any.

@PART[*]:HAS[@MODULE[ModuleCommand],!MODULE[MechJebCore]]:Final
{ MODULE
{
name = MechJebCore
MechJebLocalSettings {
MechJebModuleCustomWindowEditor {unlockTechs = flightControl}
MechJebModuleSmartASS {unlockTechs = flightControl}
MechJebModuleManeuverPlanner {unlockTechs = advFlightControl}
MechJebModuleNodeEditor {unlockTechs = advFlightControl}
MechJebModuleTranslatron {unlockTechs = advFlightControl}
MechJebModuleWarpHelper {unlockTechs = advFlightControl}
MechJebModuleAttitudeAdjustment {unlockTechs = advFlightControl}
MechJebModuleThrustWindow {unlockTechs = advFlightControl}
MechJebModuleRCSBalancerWindow {unlockTechs = advFlightControl}
MechJebModuleRoverWindow {unlockTechs = fieldScience}
MechJebModuleAscentGuidance {unlockTechs = unmannedTech}
MechJebModuleLandingGuidance {unlockTechs = unmannedTech}
MechJebModuleSpaceplaneGuidance {unlockTechs = unmannedTech}
MechJebModuleDockingGuidance {unlockTechs = advUnmanned}
MechJebModuleRendezvousAutopilotWindow {unlockTechs = advUnmanned}
MechJebModuleRendezvousGuidance {unlockTechs = advUnmanned}
}
}
}

Enables MechJeb on all pods and probes. Respects the Tech-tree.

@EXPERIMENT_DEFINITION[*]:HAS[#id[gravityScan]]
{
@baseValue = 5
@scienceCap = 10
}

Most examples use PARTs, but it works on other nodes too.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Module Manager Handbook · KSP-ModularManagement/ModuleManager Wiki · GitHub
Skip to content

Module Manager Handbook

Lisias T edited this page Mar 17, 2024 · 1 revision

Module Manager Handbook

This section covers the most basic applications of Module Manager, which tend to be the most asked questions in the Module Manager Official Thread. It goes through the main operations in a quick and simple way. For a more detailed description, see Module Manager Syntax.

Keep in mind the following nomenclatures:

  • NODE - Content is written between curly brackets:
    • MODULE { }
    • RESOURCE { }
    • PROP { }
  • Key - Items that can have a value after it:
    • name = mk2LanderCabin
    • maxThrust = 1500
    • description = The mobile processing lab was developed to (...)

Operations

Common Syntax

  • Operators
    • "nothing", for creating a new node
    • @ for edit
    • + or $ for copy
    • - or ! for delete
    • % for edit-or-create.
  • Filters
    • * for any number of alphanumeric chars
    • ? for any single alphanumeric character. This is also applied in case of "space" or special chars.
    • @ for including nodes in filter
    • - or ! for excluding nodes from filter
    • # for including keys in filter
    • ~ for excluding keys from filter
    • :HAS[<node>] for searching only files that have in filter
    • :NEEDS[<modname>] Patch is applied only if given mod is installed.
  • Additional
    • & or , for "AND"
    • | for "OR"
    • :Final forces the patch to be applied lastly (in case multiple files edit the same node)

Note that HAS blocks currently do not support the usage of OR or |. Situations where a patch needs to apply to two seperate requirements will require two seperate patches.

Examples and details

Creating or editing using operators:

// Edit a PART node named "SomePart"
@PART[SomePart]
{
// Change SomePart's mass to 0.625
@mass = 0.625
// Change the description to a new text
@description = SomePart: now uses Xenon!
// Edit SomePart's node MODULE named "ModuleEngines"
@MODULE[ModuleEngines]
{
// Change maxThrust to 225
@maxThrust = 2.25
// Edit SomePart's node PROPELLANT named "LiquidFuel"
@PROPELLANT[LiquidFuel]
{
// Change the PROPELLANT node name from LiquidFuel to XenonGas
@name = XenonGas
// Change the ratio value
@ratio = 1.0
}
// Edit SomePart's node atmosphereCurve. Note that this node doesn't have a name.
@atmosphereCurve
{
// Edit the FIRST "key" Key from the "atmosphereCurve"
@key,0 = 0 390
// Edit the SECOND "key" Key from the "atmosphereCurve" property
@key,1 = 1 320
}
// Remove the node PROPELLANT named "Oxidizer" from the PART
!PROPELLANT[Oxidizer] {}
}
// Create a new node RESOURCE in the PART
RESOURCE
{
// Add a name to the node RESOURCE
name = ElectricCharge
// Add "amount" and its value to this node
amount = 100
// Add "maxAmount" and its value to this node
maxAmount = 100
}
}

If you make a .cfg file with an entry that looks like this:

PART
{
name = myPart
...(stuff)
}

You're defining a new part named "myPart". Then, if another .cfg file somewhere does this:

@PART[myPart]
{
...(stuff)
}

That is saying: "at the PART named 'myPart', edit the following additional stuff...". If you don't put the @ operator before the NODE, instead of editing an existent one, you will create a new one:

PART[myPart]
{
...(stuff)
}

This way, now you have two PARTs named "myPart".

Filtering by numbers

It's also possible to filter Nodes and Keys by numbers. This is useful when there's multiple and nameless (or under the same name) nodes and Keys on a config file.

Keys

If there are two or more Keys with the same name, you can refer to them like this:

@example,0 = <...> finds the first "example" Key or on the list (this is the same as @example = <...>)

@example,1 = <...> finds the second one.

@example,2 = <...> finds the third, and so on.

@example,* = <...> finds all the "example" Keys, and edits all of them.

@example,-1 = <...> finds the last "example" Key.

The same thing works for !example,0, etc.

Nodes

The same is applied to nodes without names, as follows:

!EXAMPLE,0 {}

Looks for the first "EXAMPLE" node in the section and deletes it.

@EXAMPLE,*
{
...(stuff)
}

Looks and edits all the "EXAMPLE" nodes in the section.

@MODULE[Example],1
{
...(stuff)
}

Looks for all the "Example" MODULES. Filters the second one and edits it. Note that this is a named MODULE, but this doesn't prevent you from filtering them by numbers.

Editing Multiple Parts

You can apply changes to multiple parts at the same time, using the * filter.

Specific names

@PART[B9_*]
{
...(stuff)
}

This will edit all the PART nodes that has a name beginning with "B9_", and have anything else after it.

@PART[B9_*]
{
@MODULE[Module*Drill]
{
...(stuff)
}
}

This will edit only ONE module in all beginning with "B9_" parts. If you want to edit all modules in all parts, use:

@PART[B9_*]
{
@MODULE[Module*Drill],*
{
...(stuff)
}
}

Specific nodes

@PART[*]:HAS[@MODULE[ModuleEngines]]
{
...(stuff)
}

This will look for all PART nodes, but will filter for only those who contain ModuleEngines MODULE.

@PART[*]:HAS[!MODULE[ModuleCommand]]
{
...(stuff)
}

Like the previous one, this will look for all PART nodes, but will filter for only those who don't contain ModuleCommand MODULE.

Specific Keys

@PART[*]:HAS[#category[Utility]]
{
...(stuff)
}

This will look for all PART nodes, and filter for those who have a category = Utility Key. Note that this category must not be inside any other node. It must be directly inside the mentioned PART.

@PART[*]:HAS[~TechRequired[]]
{
...(stuff)
}

This will look for all PARTs that DON'T have any TechRequired = Key.

@PART[*]:HAS[#TechRequired]
{
...(stuff)
}

This will look for all PARTs that DO have TechRequired = Key with any value

Specific Configuration

@PART[*]:HAS[@RESOURCE[MonoPropellant]:HAS[#maxAmount[750]]]
{
...(stuff)
}

This will look for all PARTs that have the MonoPropellant RESOURCE. And from these, it will filter again for only those RESOURCE nodes that have a maxAmount = 750 Key.

@PART[*]:HAS[@MODULE[ModuleEngines]:HAS[@PROPELLANT[XenonGas]]]
{
...(stuff)
}

This will look for all PARTs who have a ModuleEngines MODULE using XenonGas as a propellant.

Combined Search

@PART[*]:HAS[@MODULE[ModuleEngines] , @RESOURCE[SolidFuel]] {
...(stuff)
}

This filters for all PARTs who have a ModuleEngines MODULE and have a SolidFuel RESOURCE at the same time.

@PART[*]:HAS[ @MODULE[ModuleEngines] :HAS [ @PROPELLANT[XenonGas] , @PROPELLANT[ElectricCharge] ] ]
{
...(stuff)
}

This goes for all PART thats have ModuleEngines containing XenonGas, and ElectricCharge at the same time. (Space added for clarity)

Even deeper

@PART[*]:HAS[!RESOURCE[ElectricCharge],@RESOURCE[*]]
{
...(stuff)
}

All PARTs without ElectricCharge as a resource but with any other.

Arrays

Take 7th number in an array, separated by ,, and set it to 4

// node_stack_top = 0.0, .9, 0.0, 0.0, 1.0, 0.0, 2
@node_stack_top[6] = 4

Take second numbers in an array, separated by , in all key keys, and multiply by 2

@TemperatureModifier
{
//key = 0 150000 //key = 750 75000 @key,*[1, ] *= 2
}

Some useful examples

@PART[*]:HAS[~TechRequired[]]:Final
{
TechRequired = advScienceTech
}

Adds a tech level to all PARTs who don't have any.

@PART[*]:HAS[@MODULE[ModuleCommand],!MODULE[MechJebCore]]:Final
{ MODULE
{
name = MechJebCore
MechJebLocalSettings {
MechJebModuleCustomWindowEditor {unlockTechs = flightControl}
MechJebModuleSmartASS {unlockTechs = flightControl}
MechJebModuleManeuverPlanner {unlockTechs = advFlightControl}
MechJebModuleNodeEditor {unlockTechs = advFlightControl}
MechJebModuleTranslatron {unlockTechs = advFlightControl}
MechJebModuleWarpHelper {unlockTechs = advFlightControl}
MechJebModuleAttitudeAdjustment {unlockTechs = advFlightControl}
MechJebModuleThrustWindow {unlockTechs = advFlightControl}
MechJebModuleRCSBalancerWindow {unlockTechs = advFlightControl}
MechJebModuleRoverWindow {unlockTechs = fieldScience}
MechJebModuleAscentGuidance {unlockTechs = unmannedTech}
MechJebModuleLandingGuidance {unlockTechs = unmannedTech}
MechJebModuleSpaceplaneGuidance {unlockTechs = unmannedTech}
MechJebModuleDockingGuidance {unlockTechs = advUnmanned}
MechJebModuleRendezvousAutopilotWindow {unlockTechs = advUnmanned}
MechJebModuleRendezvousGuidance {unlockTechs = advUnmanned}
}
}
}

Enables MechJeb on all pods and probes. Respects the Tech-tree.

@EXPERIMENT_DEFINITION[*]:HAS[#id[gravityScan]]
{
@baseValue = 5
@scienceCap = 10
}

Most examples use PARTs, but it works on other nodes too.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Module Manager Handbook · KSP-ModularManagement/ModuleManager Wiki · GitHub
Skip to content

Module Manager Handbook

Lisias T edited this page Mar 17, 2024 · 1 revision

Module Manager Handbook

This section covers the most basic applications of Module Manager, which tend to be the most asked questions in the Module Manager Official Thread. It goes through the main operations in a quick and simple way. For a more detailed description, see Module Manager Syntax.

Keep in mind the following nomenclatures:

  • NODE - Content is written between curly brackets:
    • MODULE { }
    • RESOURCE { }
    • PROP { }
  • Key - Items that can have a value after it:
    • name = mk2LanderCabin
    • maxThrust = 1500
    • description = The mobile processing lab was developed to (...)

Operations

Common Syntax

  • Operators
    • "nothing", for creating a new node
    • @ for edit
    • + or $ for copy
    • - or ! for delete
    • % for edit-or-create.
  • Filters
    • * for any number of alphanumeric chars
    • ? for any single alphanumeric character. This is also applied in case of "space" or special chars.
    • @ for including nodes in filter
    • - or ! for excluding nodes from filter
    • # for including keys in filter
    • ~ for excluding keys from filter
    • :HAS[<node>] for searching only files that have in filter
    • :NEEDS[<modname>] Patch is applied only if given mod is installed.
  • Additional
    • & or , for "AND"
    • | for "OR"
    • :Final forces the patch to be applied lastly (in case multiple files edit the same node)

Note that HAS blocks currently do not support the usage of OR or |. Situations where a patch needs to apply to two seperate requirements will require two seperate patches.

Examples and details

Creating or editing using operators:

// Edit a PART node named "SomePart"
@PART[SomePart]
{
// Change SomePart's mass to 0.625
@mass = 0.625
// Change the description to a new text
@description = SomePart: now uses Xenon!
// Edit SomePart's node MODULE named "ModuleEngines"
@MODULE[ModuleEngines]
{
// Change maxThrust to 225
@maxThrust = 2.25
// Edit SomePart's node PROPELLANT named "LiquidFuel"
@PROPELLANT[LiquidFuel]
{
// Change the PROPELLANT node name from LiquidFuel to XenonGas
@name = XenonGas
// Change the ratio value
@ratio = 1.0
}
// Edit SomePart's node atmosphereCurve. Note that this node doesn't have a name.
@atmosphereCurve
{
// Edit the FIRST "key" Key from the "atmosphereCurve"
@key,0 = 0 390
// Edit the SECOND "key" Key from the "atmosphereCurve" property
@key,1 = 1 320
}
// Remove the node PROPELLANT named "Oxidizer" from the PART
!PROPELLANT[Oxidizer] {}
}
// Create a new node RESOURCE in the PART
RESOURCE
{
// Add a name to the node RESOURCE
name = ElectricCharge
// Add "amount" and its value to this node
amount = 100
// Add "maxAmount" and its value to this node
maxAmount = 100
}
}

If you make a .cfg file with an entry that looks like this:

PART
{
name = myPart
...(stuff)
}

You're defining a new part named "myPart". Then, if another .cfg file somewhere does this:

@PART[myPart]
{
...(stuff)
}

That is saying: "at the PART named 'myPart', edit the following additional stuff...". If you don't put the @ operator before the NODE, instead of editing an existent one, you will create a new one:

PART[myPart]
{
...(stuff)
}

This way, now you have two PARTs named "myPart".

Filtering by numbers

It's also possible to filter Nodes and Keys by numbers. This is useful when there's multiple and nameless (or under the same name) nodes and Keys on a config file.

Keys

If there are two or more Keys with the same name, you can refer to them like this:

@example,0 = <...> finds the first "example" Key or on the list (this is the same as @example = <...>)

@example,1 = <...> finds the second one.

@example,2 = <...> finds the third, and so on.

@example,* = <...> finds all the "example" Keys, and edits all of them.

@example,-1 = <...> finds the last "example" Key.

The same thing works for !example,0, etc.

Nodes

The same is applied to nodes without names, as follows:

!EXAMPLE,0 {}

Looks for the first "EXAMPLE" node in the section and deletes it.

@EXAMPLE,*
{
...(stuff)
}

Looks and edits all the "EXAMPLE" nodes in the section.

@MODULE[Example],1
{
...(stuff)
}

Looks for all the "Example" MODULES. Filters the second one and edits it. Note that this is a named MODULE, but this doesn't prevent you from filtering them by numbers.

Editing Multiple Parts

You can apply changes to multiple parts at the same time, using the * filter.

Specific names

@PART[B9_*]
{
...(stuff)
}

This will edit all the PART nodes that has a name beginning with "B9_", and have anything else after it.

@PART[B9_*]
{
@MODULE[Module*Drill]
{
...(stuff)
}
}

This will edit only ONE module in all beginning with "B9_" parts. If you want to edit all modules in all parts, use:

@PART[B9_*]
{
@MODULE[Module*Drill],*
{
...(stuff)
}
}

Specific nodes

@PART[*]:HAS[@MODULE[ModuleEngines]]
{
...(stuff)
}

This will look for all PART nodes, but will filter for only those who contain ModuleEngines MODULE.

@PART[*]:HAS[!MODULE[ModuleCommand]]
{
...(stuff)
}

Like the previous one, this will look for all PART nodes, but will filter for only those who don't contain ModuleCommand MODULE.

Specific Keys

@PART[*]:HAS[#category[Utility]]
{
...(stuff)
}

This will look for all PART nodes, and filter for those who have a category = Utility Key. Note that this category must not be inside any other node. It must be directly inside the mentioned PART.

@PART[*]:HAS[~TechRequired[]]
{
...(stuff)
}

This will look for all PARTs that DON'T have any TechRequired = Key.

@PART[*]:HAS[#TechRequired]
{
...(stuff)
}

This will look for all PARTs that DO have TechRequired = Key with any value

Specific Configuration

@PART[*]:HAS[@RESOURCE[MonoPropellant]:HAS[#maxAmount[750]]]
{
...(stuff)
}

This will look for all PARTs that have the MonoPropellant RESOURCE. And from these, it will filter again for only those RESOURCE nodes that have a maxAmount = 750 Key.

@PART[*]:HAS[@MODULE[ModuleEngines]:HAS[@PROPELLANT[XenonGas]]]
{
...(stuff)
}

This will look for all PARTs who have a ModuleEngines MODULE using XenonGas as a propellant.

Combined Search

@PART[*]:HAS[@MODULE[ModuleEngines] , @RESOURCE[SolidFuel]] {
...(stuff)
}

This filters for all PARTs who have a ModuleEngines MODULE and have a SolidFuel RESOURCE at the same time.

@PART[*]:HAS[ @MODULE[ModuleEngines] :HAS [ @PROPELLANT[XenonGas] , @PROPELLANT[ElectricCharge] ] ]
{
...(stuff)
}

This goes for all PART thats have ModuleEngines containing XenonGas, and ElectricCharge at the same time. (Space added for clarity)

Even deeper

@PART[*]:HAS[!RESOURCE[ElectricCharge],@RESOURCE[*]]
{
...(stuff)
}

All PARTs without ElectricCharge as a resource but with any other.

Arrays

Take 7th number in an array, separated by ,, and set it to 4

// node_stack_top = 0.0, .9, 0.0, 0.0, 1.0, 0.0, 2
@node_stack_top[6] = 4

Take second numbers in an array, separated by , in all key keys, and multiply by 2

@TemperatureModifier
{
//key = 0 150000 //key = 750 75000 @key,*[1, ] *= 2
}

Some useful examples

@PART[*]:HAS[~TechRequired[]]:Final
{
TechRequired = advScienceTech
}

Adds a tech level to all PARTs who don't have any.

@PART[*]:HAS[@MODULE[ModuleCommand],!MODULE[MechJebCore]]:Final
{ MODULE
{
name = MechJebCore
MechJebLocalSettings {
MechJebModuleCustomWindowEditor {unlockTechs = flightControl}
MechJebModuleSmartASS {unlockTechs = flightControl}
MechJebModuleManeuverPlanner {unlockTechs = advFlightControl}
MechJebModuleNodeEditor {unlockTechs = advFlightControl}
MechJebModuleTranslatron {unlockTechs = advFlightControl}
MechJebModuleWarpHelper {unlockTechs = advFlightControl}
MechJebModuleAttitudeAdjustment {unlockTechs = advFlightControl}
MechJebModuleThrustWindow {unlockTechs = advFlightControl}
MechJebModuleRCSBalancerWindow {unlockTechs = advFlightControl}
MechJebModuleRoverWindow {unlockTechs = fieldScience}
MechJebModuleAscentGuidance {unlockTechs = unmannedTech}
MechJebModuleLandingGuidance {unlockTechs = unmannedTech}
MechJebModuleSpaceplaneGuidance {unlockTechs = unmannedTech}
MechJebModuleDockingGuidance {unlockTechs = advUnmanned}
MechJebModuleRendezvousAutopilotWindow {unlockTechs = advUnmanned}
MechJebModuleRendezvousGuidance {unlockTechs = advUnmanned}
}
}
}

Enables MechJeb on all pods and probes. Respects the Tech-tree.

@EXPERIMENT_DEFINITION[*]:HAS[#id[gravityScan]]
{
@baseValue = 5
@scienceCap = 10
}

Most examples use PARTs, but it works on other nodes too.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Module Manager Handbook · KSP-ModularManagement/ModuleManager Wiki · GitHub
Skip to content

Module Manager Handbook

Lisias T edited this page Mar 17, 2024 · 1 revision

Module Manager Handbook

This section covers the most basic applications of Module Manager, which tend to be the most asked questions in the Module Manager Official Thread. It goes through the main operations in a quick and simple way. For a more detailed description, see Module Manager Syntax.

Keep in mind the following nomenclatures:

  • NODE - Content is written between curly brackets:
    • MODULE { }
    • RESOURCE { }
    • PROP { }
  • Key - Items that can have a value after it:
    • name = mk2LanderCabin
    • maxThrust = 1500
    • description = The mobile processing lab was developed to (...)

Operations

Common Syntax

  • Operators
    • "nothing", for creating a new node
    • @ for edit
    • + or $ for copy
    • - or ! for delete
    • % for edit-or-create.
  • Filters
    • * for any number of alphanumeric chars
    • ? for any single alphanumeric character. This is also applied in case of "space" or special chars.
    • @ for including nodes in filter
    • - or ! for excluding nodes from filter
    • # for including keys in filter
    • ~ for excluding keys from filter
    • :HAS[<node>] for searching only files that have in filter
    • :NEEDS[<modname>] Patch is applied only if given mod is installed.
  • Additional
    • & or , for "AND"
    • | for "OR"
    • :Final forces the patch to be applied lastly (in case multiple files edit the same node)

Note that HAS blocks currently do not support the usage of OR or |. Situations where a patch needs to apply to two seperate requirements will require two seperate patches.

Examples and details

Creating or editing using operators:

// Edit a PART node named "SomePart"
@PART[SomePart]
{
// Change SomePart's mass to 0.625
@mass = 0.625
// Change the description to a new text
@description = SomePart: now uses Xenon!
// Edit SomePart's node MODULE named "ModuleEngines"
@MODULE[ModuleEngines]
{
// Change maxThrust to 225
@maxThrust = 2.25
// Edit SomePart's node PROPELLANT named "LiquidFuel"
@PROPELLANT[LiquidFuel]
{
// Change the PROPELLANT node name from LiquidFuel to XenonGas
@name = XenonGas
// Change the ratio value
@ratio = 1.0
}
// Edit SomePart's node atmosphereCurve. Note that this node doesn't have a name.
@atmosphereCurve
{
// Edit the FIRST "key" Key from the "atmosphereCurve"
@key,0 = 0 390
// Edit the SECOND "key" Key from the "atmosphereCurve" property
@key,1 = 1 320
}
// Remove the node PROPELLANT named "Oxidizer" from the PART
!PROPELLANT[Oxidizer] {}
}
// Create a new node RESOURCE in the PART
RESOURCE
{
// Add a name to the node RESOURCE
name = ElectricCharge
// Add "amount" and its value to this node
amount = 100
// Add "maxAmount" and its value to this node
maxAmount = 100
}
}

If you make a .cfg file with an entry that looks like this:

PART
{
name = myPart
...(stuff)
}

You're defining a new part named "myPart". Then, if another .cfg file somewhere does this:

@PART[myPart]
{
...(stuff)
}

That is saying: "at the PART named 'myPart', edit the following additional stuff...". If you don't put the @ operator before the NODE, instead of editing an existent one, you will create a new one:

PART[myPart]
{
...(stuff)
}

This way, now you have two PARTs named "myPart".

Filtering by numbers

It's also possible to filter Nodes and Keys by numbers. This is useful when there's multiple and nameless (or under the same name) nodes and Keys on a config file.

Keys

If there are two or more Keys with the same name, you can refer to them like this:

@example,0 = <...> finds the first "example" Key or on the list (this is the same as @example = <...>)

@example,1 = <...> finds the second one.

@example,2 = <...> finds the third, and so on.

@example,* = <...> finds all the "example" Keys, and edits all of them.

@example,-1 = <...> finds the last "example" Key.

The same thing works for !example,0, etc.

Nodes

The same is applied to nodes without names, as follows:

!EXAMPLE,0 {}

Looks for the first "EXAMPLE" node in the section and deletes it.

@EXAMPLE,*
{
...(stuff)
}

Looks and edits all the "EXAMPLE" nodes in the section.

@MODULE[Example],1
{
...(stuff)
}

Looks for all the "Example" MODULES. Filters the second one and edits it. Note that this is a named MODULE, but this doesn't prevent you from filtering them by numbers.

Editing Multiple Parts

You can apply changes to multiple parts at the same time, using the * filter.

Specific names

@PART[B9_*]
{
...(stuff)
}

This will edit all the PART nodes that has a name beginning with "B9_", and have anything else after it.

@PART[B9_*]
{
@MODULE[Module*Drill]
{
...(stuff)
}
}

This will edit only ONE module in all beginning with "B9_" parts. If you want to edit all modules in all parts, use:

@PART[B9_*]
{
@MODULE[Module*Drill],*
{
...(stuff)
}
}

Specific nodes

@PART[*]:HAS[@MODULE[ModuleEngines]]
{
...(stuff)
}

This will look for all PART nodes, but will filter for only those who contain ModuleEngines MODULE.

@PART[*]:HAS[!MODULE[ModuleCommand]]
{
...(stuff)
}

Like the previous one, this will look for all PART nodes, but will filter for only those who don't contain ModuleCommand MODULE.

Specific Keys

@PART[*]:HAS[#category[Utility]]
{
...(stuff)
}

This will look for all PART nodes, and filter for those who have a category = Utility Key. Note that this category must not be inside any other node. It must be directly inside the mentioned PART.

@PART[*]:HAS[~TechRequired[]]
{
...(stuff)
}

This will look for all PARTs that DON'T have any TechRequired = Key.

@PART[*]:HAS[#TechRequired]
{
...(stuff)
}

This will look for all PARTs that DO have TechRequired = Key with any value

Specific Configuration

@PART[*]:HAS[@RESOURCE[MonoPropellant]:HAS[#maxAmount[750]]]
{
...(stuff)
}

This will look for all PARTs that have the MonoPropellant RESOURCE. And from these, it will filter again for only those RESOURCE nodes that have a maxAmount = 750 Key.

@PART[*]:HAS[@MODULE[ModuleEngines]:HAS[@PROPELLANT[XenonGas]]]
{
...(stuff)
}

This will look for all PARTs who have a ModuleEngines MODULE using XenonGas as a propellant.

Combined Search

@PART[*]:HAS[@MODULE[ModuleEngines] , @RESOURCE[SolidFuel]] {
...(stuff)
}

This filters for all PARTs who have a ModuleEngines MODULE and have a SolidFuel RESOURCE at the same time.

@PART[*]:HAS[ @MODULE[ModuleEngines] :HAS [ @PROPELLANT[XenonGas] , @PROPELLANT[ElectricCharge] ] ]
{
...(stuff)
}

This goes for all PART thats have ModuleEngines containing XenonGas, and ElectricCharge at the same time. (Space added for clarity)

Even deeper

@PART[*]:HAS[!RESOURCE[ElectricCharge],@RESOURCE[*]]
{
...(stuff)
}

All PARTs without ElectricCharge as a resource but with any other.

Arrays

Take 7th number in an array, separated by ,, and set it to 4

// node_stack_top = 0.0, .9, 0.0, 0.0, 1.0, 0.0, 2
@node_stack_top[6] = 4

Take second numbers in an array, separated by , in all key keys, and multiply by 2

@TemperatureModifier
{
//key = 0 150000 //key = 750 75000 @key,*[1, ] *= 2
}

Some useful examples

@PART[*]:HAS[~TechRequired[]]:Final
{
TechRequired = advScienceTech
}

Adds a tech level to all PARTs who don't have any.

@PART[*]:HAS[@MODULE[ModuleCommand],!MODULE[MechJebCore]]:Final
{ MODULE
{
name = MechJebCore
MechJebLocalSettings {
MechJebModuleCustomWindowEditor {unlockTechs = flightControl}
MechJebModuleSmartASS {unlockTechs = flightControl}
MechJebModuleManeuverPlanner {unlockTechs = advFlightControl}
MechJebModuleNodeEditor {unlockTechs = advFlightControl}
MechJebModuleTranslatron {unlockTechs = advFlightControl}
MechJebModuleWarpHelper {unlockTechs = advFlightControl}
MechJebModuleAttitudeAdjustment {unlockTechs = advFlightControl}
MechJebModuleThrustWindow {unlockTechs = advFlightControl}
MechJebModuleRCSBalancerWindow {unlockTechs = advFlightControl}
MechJebModuleRoverWindow {unlockTechs = fieldScience}
MechJebModuleAscentGuidance {unlockTechs = unmannedTech}
MechJebModuleLandingGuidance {unlockTechs = unmannedTech}
MechJebModuleSpaceplaneGuidance {unlockTechs = unmannedTech}
MechJebModuleDockingGuidance {unlockTechs = advUnmanned}
MechJebModuleRendezvousAutopilotWindow {unlockTechs = advUnmanned}
MechJebModuleRendezvousGuidance {unlockTechs = advUnmanned}
}
}
}

Enables MechJeb on all pods and probes. Respects the Tech-tree.

@EXPERIMENT_DEFINITION[*]:HAS[#id[gravityScan]]
{
@baseValue = 5
@scienceCap = 10
}

Most examples use PARTs, but it works on other nodes too.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Module Manager Handbook · KSP-ModularManagement/ModuleManager Wiki · GitHub
Skip to content

Module Manager Handbook

Lisias T edited this page Mar 17, 2024 · 1 revision

Module Manager Handbook

This section covers the most basic applications of Module Manager, which tend to be the most asked questions in the Module Manager Official Thread. It goes through the main operations in a quick and simple way. For a more detailed description, see Module Manager Syntax.

Keep in mind the following nomenclatures:

  • NODE - Content is written between curly brackets:
    • MODULE { }
    • RESOURCE { }
    • PROP { }
  • Key - Items that can have a value after it:
    • name = mk2LanderCabin
    • maxThrust = 1500
    • description = The mobile processing lab was developed to (...)

Operations

Common Syntax

  • Operators
    • "nothing", for creating a new node
    • @ for edit
    • + or $ for copy
    • - or ! for delete
    • % for edit-or-create.
  • Filters
    • * for any number of alphanumeric chars
    • ? for any single alphanumeric character. This is also applied in case of "space" or special chars.
    • @ for including nodes in filter
    • - or ! for excluding nodes from filter
    • # for including keys in filter
    • ~ for excluding keys from filter
    • :HAS[<node>] for searching only files that have in filter
    • :NEEDS[<modname>] Patch is applied only if given mod is installed.
  • Additional
    • & or , for "AND"
    • | for "OR"
    • :Final forces the patch to be applied lastly (in case multiple files edit the same node)

Note that HAS blocks currently do not support the usage of OR or |. Situations where a patch needs to apply to two seperate requirements will require two seperate patches.

Examples and details

Creating or editing using operators:

// Edit a PART node named "SomePart"
@PART[SomePart]
{
// Change SomePart's mass to 0.625
@mass = 0.625
// Change the description to a new text
@description = SomePart: now uses Xenon!
// Edit SomePart's node MODULE named "ModuleEngines"
@MODULE[ModuleEngines]
{
// Change maxThrust to 225
@maxThrust = 2.25
// Edit SomePart's node PROPELLANT named "LiquidFuel"
@PROPELLANT[LiquidFuel]
{
// Change the PROPELLANT node name from LiquidFuel to XenonGas
@name = XenonGas
// Change the ratio value
@ratio = 1.0
}
// Edit SomePart's node atmosphereCurve. Note that this node doesn't have a name.
@atmosphereCurve
{
// Edit the FIRST "key" Key from the "atmosphereCurve"
@key,0 = 0 390
// Edit the SECOND "key" Key from the "atmosphereCurve" property
@key,1 = 1 320
}
// Remove the node PROPELLANT named "Oxidizer" from the PART
!PROPELLANT[Oxidizer] {}
}
// Create a new node RESOURCE in the PART
RESOURCE
{
// Add a name to the node RESOURCE
name = ElectricCharge
// Add "amount" and its value to this node
amount = 100
// Add "maxAmount" and its value to this node
maxAmount = 100
}
}

If you make a .cfg file with an entry that looks like this:

PART
{
name = myPart
...(stuff)
}

You're defining a new part named "myPart". Then, if another .cfg file somewhere does this:

@PART[myPart]
{
...(stuff)
}

That is saying: "at the PART named 'myPart', edit the following additional stuff...". If you don't put the @ operator before the NODE, instead of editing an existent one, you will create a new one:

PART[myPart]
{
...(stuff)
}

This way, now you have two PARTs named "myPart".

Filtering by numbers

It's also possible to filter Nodes and Keys by numbers. This is useful when there's multiple and nameless (or under the same name) nodes and Keys on a config file.

Keys

If there are two or more Keys with the same name, you can refer to them like this:

@example,0 = <...> finds the first "example" Key or on the list (this is the same as @example = <...>)

@example,1 = <...> finds the second one.

@example,2 = <...> finds the third, and so on.

@example,* = <...> finds all the "example" Keys, and edits all of them.

@example,-1 = <...> finds the last "example" Key.

The same thing works for !example,0, etc.

Nodes

The same is applied to nodes without names, as follows:

!EXAMPLE,0 {}

Looks for the first "EXAMPLE" node in the section and deletes it.

@EXAMPLE,*
{
...(stuff)
}

Looks and edits all the "EXAMPLE" nodes in the section.

@MODULE[Example],1
{
...(stuff)
}

Looks for all the "Example" MODULES. Filters the second one and edits it. Note that this is a named MODULE, but this doesn't prevent you from filtering them by numbers.

Editing Multiple Parts

You can apply changes to multiple parts at the same time, using the * filter.

Specific names

@PART[B9_*]
{
...(stuff)
}

This will edit all the PART nodes that has a name beginning with "B9_", and have anything else after it.

@PART[B9_*]
{
@MODULE[Module*Drill]
{
...(stuff)
}
}

This will edit only ONE module in all beginning with "B9_" parts. If you want to edit all modules in all parts, use:

@PART[B9_*]
{
@MODULE[Module*Drill],*
{
...(stuff)
}
}

Specific nodes

@PART[*]:HAS[@MODULE[ModuleEngines]]
{
...(stuff)
}

This will look for all PART nodes, but will filter for only those who contain ModuleEngines MODULE.

@PART[*]:HAS[!MODULE[ModuleCommand]]
{
...(stuff)
}

Like the previous one, this will look for all PART nodes, but will filter for only those who don't contain ModuleCommand MODULE.

Specific Keys

@PART[*]:HAS[#category[Utility]]
{
...(stuff)
}

This will look for all PART nodes, and filter for those who have a category = Utility Key. Note that this category must not be inside any other node. It must be directly inside the mentioned PART.

@PART[*]:HAS[~TechRequired[]]
{
...(stuff)
}

This will look for all PARTs that DON'T have any TechRequired = Key.

@PART[*]:HAS[#TechRequired]
{
...(stuff)
}

This will look for all PARTs that DO have TechRequired = Key with any value

Specific Configuration

@PART[*]:HAS[@RESOURCE[MonoPropellant]:HAS[#maxAmount[750]]]
{
...(stuff)
}

This will look for all PARTs that have the MonoPropellant RESOURCE. And from these, it will filter again for only those RESOURCE nodes that have a maxAmount = 750 Key.

@PART[*]:HAS[@MODULE[ModuleEngines]:HAS[@PROPELLANT[XenonGas]]]
{
...(stuff)
}

This will look for all PARTs who have a ModuleEngines MODULE using XenonGas as a propellant.

Combined Search

@PART[*]:HAS[@MODULE[ModuleEngines] , @RESOURCE[SolidFuel]] {
...(stuff)
}

This filters for all PARTs who have a ModuleEngines MODULE and have a SolidFuel RESOURCE at the same time.

@PART[*]:HAS[ @MODULE[ModuleEngines] :HAS [ @PROPELLANT[XenonGas] , @PROPELLANT[ElectricCharge] ] ]
{
...(stuff)
}

This goes for all PART thats have ModuleEngines containing XenonGas, and ElectricCharge at the same time. (Space added for clarity)

Even deeper

@PART[*]:HAS[!RESOURCE[ElectricCharge],@RESOURCE[*]]
{
...(stuff)
}

All PARTs without ElectricCharge as a resource but with any other.

Arrays

Take 7th number in an array, separated by ,, and set it to 4

// node_stack_top = 0.0, .9, 0.0, 0.0, 1.0, 0.0, 2
@node_stack_top[6] = 4

Take second numbers in an array, separated by , in all key keys, and multiply by 2

@TemperatureModifier
{
//key = 0 150000 //key = 750 75000 @key,*[1, ] *= 2
}

Some useful examples

@PART[*]:HAS[~TechRequired[]]:Final
{
TechRequired = advScienceTech
}

Adds a tech level to all PARTs who don't have any.

@PART[*]:HAS[@MODULE[ModuleCommand],!MODULE[MechJebCore]]:Final
{ MODULE
{
name = MechJebCore
MechJebLocalSettings {
MechJebModuleCustomWindowEditor {unlockTechs = flightControl}
MechJebModuleSmartASS {unlockTechs = flightControl}
MechJebModuleManeuverPlanner {unlockTechs = advFlightControl}
MechJebModuleNodeEditor {unlockTechs = advFlightControl}
MechJebModuleTranslatron {unlockTechs = advFlightControl}
MechJebModuleWarpHelper {unlockTechs = advFlightControl}
MechJebModuleAttitudeAdjustment {unlockTechs = advFlightControl}
MechJebModuleThrustWindow {unlockTechs = advFlightControl}
MechJebModuleRCSBalancerWindow {unlockTechs = advFlightControl}
MechJebModuleRoverWindow {unlockTechs = fieldScience}
MechJebModuleAscentGuidance {unlockTechs = unmannedTech}
MechJebModuleLandingGuidance {unlockTechs = unmannedTech}
MechJebModuleSpaceplaneGuidance {unlockTechs = unmannedTech}
MechJebModuleDockingGuidance {unlockTechs = advUnmanned}
MechJebModuleRendezvousAutopilotWindow {unlockTechs = advUnmanned}
MechJebModuleRendezvousGuidance {unlockTechs = advUnmanned}
}
}
}

Enables MechJeb on all pods and probes. Respects the Tech-tree.

@EXPERIMENT_DEFINITION[*]:HAS[#id[gravityScan]]
{
@baseValue = 5
@scienceCap = 10
}

Most examples use PARTs, but it works on other nodes too.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Module Manager Handbook · KSP-ModularManagement/ModuleManager Wiki · GitHub
Skip to content

Module Manager Handbook

Lisias T edited this page Mar 17, 2024 · 1 revision

Module Manager Handbook

This section covers the most basic applications of Module Manager, which tend to be the most asked questions in the Module Manager Official Thread. It goes through the main operations in a quick and simple way. For a more detailed description, see Module Manager Syntax.

Keep in mind the following nomenclatures:

  • NODE - Content is written between curly brackets:
    • MODULE { }
    • RESOURCE { }
    • PROP { }
  • Key - Items that can have a value after it:
    • name = mk2LanderCabin
    • maxThrust = 1500
    • description = The mobile processing lab was developed to (...)

Operations

Common Syntax

  • Operators
    • "nothing", for creating a new node
    • @ for edit
    • + or $ for copy
    • - or ! for delete
    • % for edit-or-create.
  • Filters
    • * for any number of alphanumeric chars
    • ? for any single alphanumeric character. This is also applied in case of "space" or special chars.
    • @ for including nodes in filter
    • - or ! for excluding nodes from filter
    • # for including keys in filter
    • ~ for excluding keys from filter
    • :HAS[<node>] for searching only files that have in filter
    • :NEEDS[<modname>] Patch is applied only if given mod is installed.
  • Additional
    • & or , for "AND"
    • | for "OR"
    • :Final forces the patch to be applied lastly (in case multiple files edit the same node)

Note that HAS blocks currently do not support the usage of OR or |. Situations where a patch needs to apply to two seperate requirements will require two seperate patches.

Examples and details

Creating or editing using operators:

// Edit a PART node named "SomePart"
@PART[SomePart]
{
// Change SomePart's mass to 0.625
@mass = 0.625
// Change the description to a new text
@description = SomePart: now uses Xenon!
// Edit SomePart's node MODULE named "ModuleEngines"
@MODULE[ModuleEngines]
{
// Change maxThrust to 225
@maxThrust = 2.25
// Edit SomePart's node PROPELLANT named "LiquidFuel"
@PROPELLANT[LiquidFuel]
{
// Change the PROPELLANT node name from LiquidFuel to XenonGas
@name = XenonGas
// Change the ratio value
@ratio = 1.0
}
// Edit SomePart's node atmosphereCurve. Note that this node doesn't have a name.
@atmosphereCurve
{
// Edit the FIRST "key" Key from the "atmosphereCurve"
@key,0 = 0 390
// Edit the SECOND "key" Key from the "atmosphereCurve" property
@key,1 = 1 320
}
// Remove the node PROPELLANT named "Oxidizer" from the PART
!PROPELLANT[Oxidizer] {}
}
// Create a new node RESOURCE in the PART
RESOURCE
{
// Add a name to the node RESOURCE
name = ElectricCharge
// Add "amount" and its value to this node
amount = 100
// Add "maxAmount" and its value to this node
maxAmount = 100
}
}

If you make a .cfg file with an entry that looks like this:

PART
{
name = myPart
...(stuff)
}

You're defining a new part named "myPart". Then, if another .cfg file somewhere does this:

@PART[myPart]
{
...(stuff)
}

That is saying: "at the PART named 'myPart', edit the following additional stuff...". If you don't put the @ operator before the NODE, instead of editing an existent one, you will create a new one:

PART[myPart]
{
...(stuff)
}

This way, now you have two PARTs named "myPart".

Filtering by numbers

It's also possible to filter Nodes and Keys by numbers. This is useful when there's multiple and nameless (or under the same name) nodes and Keys on a config file.

Keys

If there are two or more Keys with the same name, you can refer to them like this:

@example,0 = <...> finds the first "example" Key or on the list (this is the same as @example = <...>)

@example,1 = <...> finds the second one.

@example,2 = <...> finds the third, and so on.

@example,* = <...> finds all the "example" Keys, and edits all of them.

@example,-1 = <...> finds the last "example" Key.

The same thing works for !example,0, etc.

Nodes

The same is applied to nodes without names, as follows:

!EXAMPLE,0 {}

Looks for the first "EXAMPLE" node in the section and deletes it.

@EXAMPLE,*
{
...(stuff)
}

Looks and edits all the "EXAMPLE" nodes in the section.

@MODULE[Example],1
{
...(stuff)
}

Looks for all the "Example" MODULES. Filters the second one and edits it. Note that this is a named MODULE, but this doesn't prevent you from filtering them by numbers.

Editing Multiple Parts

You can apply changes to multiple parts at the same time, using the * filter.

Specific names

@PART[B9_*]
{
...(stuff)
}

This will edit all the PART nodes that has a name beginning with "B9_", and have anything else after it.

@PART[B9_*]
{
@MODULE[Module*Drill]
{
...(stuff)
}
}

This will edit only ONE module in all beginning with "B9_" parts. If you want to edit all modules in all parts, use:

@PART[B9_*]
{
@MODULE[Module*Drill],*
{
...(stuff)
}
}

Specific nodes

@PART[*]:HAS[@MODULE[ModuleEngines]]
{
...(stuff)
}

This will look for all PART nodes, but will filter for only those who contain ModuleEngines MODULE.

@PART[*]:HAS[!MODULE[ModuleCommand]]
{
...(stuff)
}

Like the previous one, this will look for all PART nodes, but will filter for only those who don't contain ModuleCommand MODULE.

Specific Keys

@PART[*]:HAS[#category[Utility]]
{
...(stuff)
}

This will look for all PART nodes, and filter for those who have a category = Utility Key. Note that this category must not be inside any other node. It must be directly inside the mentioned PART.

@PART[*]:HAS[~TechRequired[]]
{
...(stuff)
}

This will look for all PARTs that DON'T have any TechRequired = Key.

@PART[*]:HAS[#TechRequired]
{
...(stuff)
}

This will look for all PARTs that DO have TechRequired = Key with any value

Specific Configuration

@PART[*]:HAS[@RESOURCE[MonoPropellant]:HAS[#maxAmount[750]]]
{
...(stuff)
}

This will look for all PARTs that have the MonoPropellant RESOURCE. And from these, it will filter again for only those RESOURCE nodes that have a maxAmount = 750 Key.

@PART[*]:HAS[@MODULE[ModuleEngines]:HAS[@PROPELLANT[XenonGas]]]
{
...(stuff)
}

This will look for all PARTs who have a ModuleEngines MODULE using XenonGas as a propellant.

Combined Search

@PART[*]:HAS[@MODULE[ModuleEngines] , @RESOURCE[SolidFuel]] {
...(stuff)
}

This filters for all PARTs who have a ModuleEngines MODULE and have a SolidFuel RESOURCE at the same time.

@PART[*]:HAS[ @MODULE[ModuleEngines] :HAS [ @PROPELLANT[XenonGas] , @PROPELLANT[ElectricCharge] ] ]
{
...(stuff)
}

This goes for all PART thats have ModuleEngines containing XenonGas, and ElectricCharge at the same time. (Space added for clarity)

Even deeper

@PART[*]:HAS[!RESOURCE[ElectricCharge],@RESOURCE[*]]
{
...(stuff)
}

All PARTs without ElectricCharge as a resource but with any other.

Arrays

Take 7th number in an array, separated by ,, and set it to 4

// node_stack_top = 0.0, .9, 0.0, 0.0, 1.0, 0.0, 2
@node_stack_top[6] = 4

Take second numbers in an array, separated by , in all key keys, and multiply by 2

@TemperatureModifier
{
//key = 0 150000 //key = 750 75000 @key,*[1, ] *= 2
}

Some useful examples

@PART[*]:HAS[~TechRequired[]]:Final
{
TechRequired = advScienceTech
}

Adds a tech level to all PARTs who don't have any.

@PART[*]:HAS[@MODULE[ModuleCommand],!MODULE[MechJebCore]]:Final
{ MODULE
{
name = MechJebCore
MechJebLocalSettings {
MechJebModuleCustomWindowEditor {unlockTechs = flightControl}
MechJebModuleSmartASS {unlockTechs = flightControl}
MechJebModuleManeuverPlanner {unlockTechs = advFlightControl}
MechJebModuleNodeEditor {unlockTechs = advFlightControl}
MechJebModuleTranslatron {unlockTechs = advFlightControl}
MechJebModuleWarpHelper {unlockTechs = advFlightControl}
MechJebModuleAttitudeAdjustment {unlockTechs = advFlightControl}
MechJebModuleThrustWindow {unlockTechs = advFlightControl}
MechJebModuleRCSBalancerWindow {unlockTechs = advFlightControl}
MechJebModuleRoverWindow {unlockTechs = fieldScience}
MechJebModuleAscentGuidance {unlockTechs = unmannedTech}
MechJebModuleLandingGuidance {unlockTechs = unmannedTech}
MechJebModuleSpaceplaneGuidance {unlockTechs = unmannedTech}
MechJebModuleDockingGuidance {unlockTechs = advUnmanned}
MechJebModuleRendezvousAutopilotWindow {unlockTechs = advUnmanned}
MechJebModuleRendezvousGuidance {unlockTechs = advUnmanned}
}
}
}

Enables MechJeb on all pods and probes. Respects the Tech-tree.

@EXPERIMENT_DEFINITION[*]:HAS[#id[gravityScan]]
{
@baseValue = 5
@scienceCap = 10
}

Most examples use PARTs, but it works on other nodes too.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Module Manager Handbook · KSP-ModularManagement/ModuleManager Wiki · GitHub
Skip to content

Module Manager Handbook

Lisias T edited this page Mar 17, 2024 · 1 revision

Module Manager Handbook

This section covers the most basic applications of Module Manager, which tend to be the most asked questions in the Module Manager Official Thread. It goes through the main operations in a quick and simple way. For a more detailed description, see Module Manager Syntax.

Keep in mind the following nomenclatures:

  • NODE - Content is written between curly brackets:
    • MODULE { }
    • RESOURCE { }
    • PROP { }
  • Key - Items that can have a value after it:
    • name = mk2LanderCabin
    • maxThrust = 1500
    • description = The mobile processing lab was developed to (...)

Operations

Common Syntax

  • Operators
    • "nothing", for creating a new node
    • @ for edit
    • + or $ for copy
    • - or ! for delete
    • % for edit-or-create.
  • Filters
    • * for any number of alphanumeric chars
    • ? for any single alphanumeric character. This is also applied in case of "space" or special chars.
    • @ for including nodes in filter
    • - or ! for excluding nodes from filter
    • # for including keys in filter
    • ~ for excluding keys from filter
    • :HAS[<node>] for searching only files that have in filter
    • :NEEDS[<modname>] Patch is applied only if given mod is installed.
  • Additional
    • & or , for "AND"
    • | for "OR"
    • :Final forces the patch to be applied lastly (in case multiple files edit the same node)

Note that HAS blocks currently do not support the usage of OR or |. Situations where a patch needs to apply to two seperate requirements will require two seperate patches.

Examples and details

Creating or editing using operators:

// Edit a PART node named "SomePart"
@PART[SomePart]
{
// Change SomePart's mass to 0.625
@mass = 0.625
// Change the description to a new text
@description = SomePart: now uses Xenon!
// Edit SomePart's node MODULE named "ModuleEngines"
@MODULE[ModuleEngines]
{
// Change maxThrust to 225
@maxThrust = 2.25
// Edit SomePart's node PROPELLANT named "LiquidFuel"
@PROPELLANT[LiquidFuel]
{
// Change the PROPELLANT node name from LiquidFuel to XenonGas
@name = XenonGas
// Change the ratio value
@ratio = 1.0
}
// Edit SomePart's node atmosphereCurve. Note that this node doesn't have a name.
@atmosphereCurve
{
// Edit the FIRST "key" Key from the "atmosphereCurve"
@key,0 = 0 390
// Edit the SECOND "key" Key from the "atmosphereCurve" property
@key,1 = 1 320
}
// Remove the node PROPELLANT named "Oxidizer" from the PART
!PROPELLANT[Oxidizer] {}
}
// Create a new node RESOURCE in the PART
RESOURCE
{
// Add a name to the node RESOURCE
name = ElectricCharge
// Add "amount" and its value to this node
amount = 100
// Add "maxAmount" and its value to this node
maxAmount = 100
}
}

If you make a .cfg file with an entry that looks like this:

PART
{
name = myPart
...(stuff)
}

You're defining a new part named "myPart". Then, if another .cfg file somewhere does this:

@PART[myPart]
{
...(stuff)
}

That is saying: "at the PART named 'myPart', edit the following additional stuff...". If you don't put the @ operator before the NODE, instead of editing an existent one, you will create a new one:

PART[myPart]
{
...(stuff)
}

This way, now you have two PARTs named "myPart".

Filtering by numbers

It's also possible to filter Nodes and Keys by numbers. This is useful when there's multiple and nameless (or under the same name) nodes and Keys on a config file.

Keys

If there are two or more Keys with the same name, you can refer to them like this:

@example,0 = <...> finds the first "example" Key or on the list (this is the same as @example = <...>)

@example,1 = <...> finds the second one.

@example,2 = <...> finds the third, and so on.

@example,* = <...> finds all the "example" Keys, and edits all of them.

@example,-1 = <...> finds the last "example" Key.

The same thing works for !example,0, etc.

Nodes

The same is applied to nodes without names, as follows:

!EXAMPLE,0 {}

Looks for the first "EXAMPLE" node in the section and deletes it.

@EXAMPLE,*
{
...(stuff)
}

Looks and edits all the "EXAMPLE" nodes in the section.

@MODULE[Example],1
{
...(stuff)
}

Looks for all the "Example" MODULES. Filters the second one and edits it. Note that this is a named MODULE, but this doesn't prevent you from filtering them by numbers.

Editing Multiple Parts

You can apply changes to multiple parts at the same time, using the * filter.

Specific names

@PART[B9_*]
{
...(stuff)
}

This will edit all the PART nodes that has a name beginning with "B9_", and have anything else after it.

@PART[B9_*]
{
@MODULE[Module*Drill]
{
...(stuff)
}
}

This will edit only ONE module in all beginning with "B9_" parts. If you want to edit all modules in all parts, use:

@PART[B9_*]
{
@MODULE[Module*Drill],*
{
...(stuff)
}
}

Specific nodes

@PART[*]:HAS[@MODULE[ModuleEngines]]
{
...(stuff)
}

This will look for all PART nodes, but will filter for only those who contain ModuleEngines MODULE.

@PART[*]:HAS[!MODULE[ModuleCommand]]
{
...(stuff)
}

Like the previous one, this will look for all PART nodes, but will filter for only those who don't contain ModuleCommand MODULE.

Specific Keys

@PART[*]:HAS[#category[Utility]]
{
...(stuff)
}

This will look for all PART nodes, and filter for those who have a category = Utility Key. Note that this category must not be inside any other node. It must be directly inside the mentioned PART.

@PART[*]:HAS[~TechRequired[]]
{
...(stuff)
}

This will look for all PARTs that DON'T have any TechRequired = Key.

@PART[*]:HAS[#TechRequired]
{
...(stuff)
}

This will look for all PARTs that DO have TechRequired = Key with any value

Specific Configuration

@PART[*]:HAS[@RESOURCE[MonoPropellant]:HAS[#maxAmount[750]]]
{
...(stuff)
}

This will look for all PARTs that have the MonoPropellant RESOURCE. And from these, it will filter again for only those RESOURCE nodes that have a maxAmount = 750 Key.

@PART[*]:HAS[@MODULE[ModuleEngines]:HAS[@PROPELLANT[XenonGas]]]
{
...(stuff)
}

This will look for all PARTs who have a ModuleEngines MODULE using XenonGas as a propellant.

Combined Search

@PART[*]:HAS[@MODULE[ModuleEngines] , @RESOURCE[SolidFuel]] {
...(stuff)
}

This filters for all PARTs who have a ModuleEngines MODULE and have a SolidFuel RESOURCE at the same time.

@PART[*]:HAS[ @MODULE[ModuleEngines] :HAS [ @PROPELLANT[XenonGas] , @PROPELLANT[ElectricCharge] ] ]
{
...(stuff)
}

This goes for all PART thats have ModuleEngines containing XenonGas, and ElectricCharge at the same time. (Space added for clarity)

Even deeper

@PART[*]:HAS[!RESOURCE[ElectricCharge],@RESOURCE[*]]
{
...(stuff)
}

All PARTs without ElectricCharge as a resource but with any other.

Arrays

Take 7th number in an array, separated by ,, and set it to 4

// node_stack_top = 0.0, .9, 0.0, 0.0, 1.0, 0.0, 2
@node_stack_top[6] = 4

Take second numbers in an array, separated by , in all key keys, and multiply by 2

@TemperatureModifier
{
//key = 0 150000 //key = 750 75000 @key,*[1, ] *= 2
}

Some useful examples

@PART[*]:HAS[~TechRequired[]]:Final
{
TechRequired = advScienceTech
}

Adds a tech level to all PARTs who don't have any.

@PART[*]:HAS[@MODULE[ModuleCommand],!MODULE[MechJebCore]]:Final
{ MODULE
{
name = MechJebCore
MechJebLocalSettings {
MechJebModuleCustomWindowEditor {unlockTechs = flightControl}
MechJebModuleSmartASS {unlockTechs = flightControl}
MechJebModuleManeuverPlanner {unlockTechs = advFlightControl}
MechJebModuleNodeEditor {unlockTechs = advFlightControl}
MechJebModuleTranslatron {unlockTechs = advFlightControl}
MechJebModuleWarpHelper {unlockTechs = advFlightControl}
MechJebModuleAttitudeAdjustment {unlockTechs = advFlightControl}
MechJebModuleThrustWindow {unlockTechs = advFlightControl}
MechJebModuleRCSBalancerWindow {unlockTechs = advFlightControl}
MechJebModuleRoverWindow {unlockTechs = fieldScience}
MechJebModuleAscentGuidance {unlockTechs = unmannedTech}
MechJebModuleLandingGuidance {unlockTechs = unmannedTech}
MechJebModuleSpaceplaneGuidance {unlockTechs = unmannedTech}
MechJebModuleDockingGuidance {unlockTechs = advUnmanned}
MechJebModuleRendezvousAutopilotWindow {unlockTechs = advUnmanned}
MechJebModuleRendezvousGuidance {unlockTechs = advUnmanned}
}
}
}

Enables MechJeb on all pods and probes. Respects the Tech-tree.

@EXPERIMENT_DEFINITION[*]:HAS[#id[gravityScan]]
{
@baseValue = 5
@scienceCap = 10
}

Most examples use PARTs, but it works on other nodes too.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Module Manager Handbook · KSP-ModularManagement/ModuleManager Wiki · GitHub
Skip to content

Module Manager Handbook

Lisias T edited this page Mar 17, 2024 · 1 revision

Module Manager Handbook

This section covers the most basic applications of Module Manager, which tend to be the most asked questions in the Module Manager Official Thread. It goes through the main operations in a quick and simple way. For a more detailed description, see Module Manager Syntax.

Keep in mind the following nomenclatures:

  • NODE - Content is written between curly brackets:
    • MODULE { }
    • RESOURCE { }
    • PROP { }
  • Key - Items that can have a value after it:
    • name = mk2LanderCabin
    • maxThrust = 1500
    • description = The mobile processing lab was developed to (...)

Operations

Common Syntax

  • Operators
    • "nothing", for creating a new node
    • @ for edit
    • + or $ for copy
    • - or ! for delete
    • % for edit-or-create.
  • Filters
    • * for any number of alphanumeric chars
    • ? for any single alphanumeric character. This is also applied in case of "space" or special chars.
    • @ for including nodes in filter
    • - or ! for excluding nodes from filter
    • # for including keys in filter
    • ~ for excluding keys from filter
    • :HAS[<node>] for searching only files that have in filter
    • :NEEDS[<modname>] Patch is applied only if given mod is installed.
  • Additional
    • & or , for "AND"
    • | for "OR"
    • :Final forces the patch to be applied lastly (in case multiple files edit the same node)

Note that HAS blocks currently do not support the usage of OR or |. Situations where a patch needs to apply to two seperate requirements will require two seperate patches.

Examples and details

Creating or editing using operators:

// Edit a PART node named "SomePart"
@PART[SomePart]
{
// Change SomePart's mass to 0.625
@mass = 0.625
// Change the description to a new text
@description = SomePart: now uses Xenon!
// Edit SomePart's node MODULE named "ModuleEngines"
@MODULE[ModuleEngines]
{
// Change maxThrust to 225
@maxThrust = 2.25
// Edit SomePart's node PROPELLANT named "LiquidFuel"
@PROPELLANT[LiquidFuel]
{
// Change the PROPELLANT node name from LiquidFuel to XenonGas
@name = XenonGas
// Change the ratio value
@ratio = 1.0
}
// Edit SomePart's node atmosphereCurve. Note that this node doesn't have a name.
@atmosphereCurve
{
// Edit the FIRST "key" Key from the "atmosphereCurve"
@key,0 = 0 390
// Edit the SECOND "key" Key from the "atmosphereCurve" property
@key,1 = 1 320
}
// Remove the node PROPELLANT named "Oxidizer" from the PART
!PROPELLANT[Oxidizer] {}
}
// Create a new node RESOURCE in the PART
RESOURCE
{
// Add a name to the node RESOURCE
name = ElectricCharge
// Add "amount" and its value to this node
amount = 100
// Add "maxAmount" and its value to this node
maxAmount = 100
}
}

If you make a .cfg file with an entry that looks like this:

PART
{
name = myPart
...(stuff)
}

You're defining a new part named "myPart". Then, if another .cfg file somewhere does this:

@PART[myPart]
{
...(stuff)
}

That is saying: "at the PART named 'myPart', edit the following additional stuff...". If you don't put the @ operator before the NODE, instead of editing an existent one, you will create a new one:

PART[myPart]
{
...(stuff)
}

This way, now you have two PARTs named "myPart".

Filtering by numbers

It's also possible to filter Nodes and Keys by numbers. This is useful when there's multiple and nameless (or under the same name) nodes and Keys on a config file.

Keys

If there are two or more Keys with the same name, you can refer to them like this:

@example,0 = <...> finds the first "example" Key or on the list (this is the same as @example = <...>)

@example,1 = <...> finds the second one.

@example,2 = <...> finds the third, and so on.

@example,* = <...> finds all the "example" Keys, and edits all of them.

@example,-1 = <...> finds the last "example" Key.

The same thing works for !example,0, etc.

Nodes

The same is applied to nodes without names, as follows:

!EXAMPLE,0 {}

Looks for the first "EXAMPLE" node in the section and deletes it.

@EXAMPLE,*
{
...(stuff)
}

Looks and edits all the "EXAMPLE" nodes in the section.

@MODULE[Example],1
{
...(stuff)
}

Looks for all the "Example" MODULES. Filters the second one and edits it. Note that this is a named MODULE, but this doesn't prevent you from filtering them by numbers.

Editing Multiple Parts

You can apply changes to multiple parts at the same time, using the * filter.

Specific names

@PART[B9_*]
{
...(stuff)
}

This will edit all the PART nodes that has a name beginning with "B9_", and have anything else after it.

@PART[B9_*]
{
@MODULE[Module*Drill]
{
...(stuff)
}
}

This will edit only ONE module in all beginning with "B9_" parts. If you want to edit all modules in all parts, use:

@PART[B9_*]
{
@MODULE[Module*Drill],*
{
...(stuff)
}
}

Specific nodes

@PART[*]:HAS[@MODULE[ModuleEngines]]
{
...(stuff)
}

This will look for all PART nodes, but will filter for only those who contain ModuleEngines MODULE.

@PART[*]:HAS[!MODULE[ModuleCommand]]
{
...(stuff)
}

Like the previous one, this will look for all PART nodes, but will filter for only those who don't contain ModuleCommand MODULE.

Specific Keys

@PART[*]:HAS[#category[Utility]]
{
...(stuff)
}

This will look for all PART nodes, and filter for those who have a category = Utility Key. Note that this category must not be inside any other node. It must be directly inside the mentioned PART.

@PART[*]:HAS[~TechRequired[]]
{
...(stuff)
}

This will look for all PARTs that DON'T have any TechRequired = Key.

@PART[*]:HAS[#TechRequired]
{
...(stuff)
}

This will look for all PARTs that DO have TechRequired = Key with any value

Specific Configuration

@PART[*]:HAS[@RESOURCE[MonoPropellant]:HAS[#maxAmount[750]]]
{
...(stuff)
}

This will look for all PARTs that have the MonoPropellant RESOURCE. And from these, it will filter again for only those RESOURCE nodes that have a maxAmount = 750 Key.

@PART[*]:HAS[@MODULE[ModuleEngines]:HAS[@PROPELLANT[XenonGas]]]
{
...(stuff)
}

This will look for all PARTs who have a ModuleEngines MODULE using XenonGas as a propellant.

Combined Search

@PART[*]:HAS[@MODULE[ModuleEngines] , @RESOURCE[SolidFuel]] {
...(stuff)
}

This filters for all PARTs who have a ModuleEngines MODULE and have a SolidFuel RESOURCE at the same time.

@PART[*]:HAS[ @MODULE[ModuleEngines] :HAS [ @PROPELLANT[XenonGas] , @PROPELLANT[ElectricCharge] ] ]
{
...(stuff)
}

This goes for all PART thats have ModuleEngines containing XenonGas, and ElectricCharge at the same time. (Space added for clarity)

Even deeper

@PART[*]:HAS[!RESOURCE[ElectricCharge],@RESOURCE[*]]
{
...(stuff)
}

All PARTs without ElectricCharge as a resource but with any other.

Arrays

Take 7th number in an array, separated by ,, and set it to 4

// node_stack_top = 0.0, .9, 0.0, 0.0, 1.0, 0.0, 2
@node_stack_top[6] = 4

Take second numbers in an array, separated by , in all key keys, and multiply by 2

@TemperatureModifier
{
//key = 0 150000 //key = 750 75000 @key,*[1, ] *= 2
}

Some useful examples

@PART[*]:HAS[~TechRequired[]]:Final
{
TechRequired = advScienceTech
}

Adds a tech level to all PARTs who don't have any.

@PART[*]:HAS[@MODULE[ModuleCommand],!MODULE[MechJebCore]]:Final
{ MODULE
{
name = MechJebCore
MechJebLocalSettings {
MechJebModuleCustomWindowEditor {unlockTechs = flightControl}
MechJebModuleSmartASS {unlockTechs = flightControl}
MechJebModuleManeuverPlanner {unlockTechs = advFlightControl}
MechJebModuleNodeEditor {unlockTechs = advFlightControl}
MechJebModuleTranslatron {unlockTechs = advFlightControl}
MechJebModuleWarpHelper {unlockTechs = advFlightControl}
MechJebModuleAttitudeAdjustment {unlockTechs = advFlightControl}
MechJebModuleThrustWindow {unlockTechs = advFlightControl}
MechJebModuleRCSBalancerWindow {unlockTechs = advFlightControl}
MechJebModuleRoverWindow {unlockTechs = fieldScience}
MechJebModuleAscentGuidance {unlockTechs = unmannedTech}
MechJebModuleLandingGuidance {unlockTechs = unmannedTech}
MechJebModuleSpaceplaneGuidance {unlockTechs = unmannedTech}
MechJebModuleDockingGuidance {unlockTechs = advUnmanned}
MechJebModuleRendezvousAutopilotWindow {unlockTechs = advUnmanned}
MechJebModuleRendezvousGuidance {unlockTechs = advUnmanned}
}
}
}

Enables MechJeb on all pods and probes. Respects the Tech-tree.

@EXPERIMENT_DEFINITION[*]:HAS[#id[gravityScan]]
{
@baseValue = 5
@scienceCap = 10
}

Most examples use PARTs, but it works on other nodes too.

Clone this wiki locally