[1.8.x-1.12.x] Module Manager 4.2.3 (July 03th 2023) - Fireworks season (2024)

You can now override specific lines in a ConfigNode (what the game's code calls the format inside a .cfg file), on a line-by-line basis, and you don't have to specify lines that you don't want to change. The new format looks like this:

Single Part and editing format


@PART[SomePart] // change Some PART
{
@mass = 0.625 // change SomePart's mass to 0.625
@description = SomePart: now uses Xenon!

@MODULE[ModuleEngines] // change SomePart's ModuleEngines MODULE
{
@maxThrust = 2.25 // change maxThrust to 225

@PROPELLANT[LiquidFuel] // change its LiquidFuel propellant
{
@name = XenonGas // use XenonGas instead
@ratio = 1.0 // change the ratio
}
!PROPELLANT[Oxidizer] {} // remove the Oxidizer propellant completely.
}

RESOURCE // add a new resource to this part
{
name = ElectricCharge
amount = 100
maxAmount = 100
}
}

Let's break this down.

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


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

you're defining a new part. Then, if another .cfg file somewhere does this:


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

That says "at the PART named myPart, add the following additional stuff..."

There's two ways you can do this:

1. @PART[myPart] {...} is for plugin developers, who need to add new modules and resources to stock parts.

2. @PART[myPart]:Final {...} is for "tweakers", who want to release a set of reconfigurations of other peoples' parts that changes gameplay, or personal patch. The change with :Final are applied after all others are done.

inside the curly brackets, you have several options:

@foo = <new value> changes foo to <new value>.

!foo = DELETE deletes foo completely.

foo = <value> creates a new variable called 'foo'; if there was already a variable called 'foo', now there's two of them.

if there are two or more variables called foo, you can refer to them like this:

@foo,0 = <...> finds the first one (this is the same as @foo = <...>)

@foo,1 = <...> finds the second one, @foo,2 = <...> finds the third, and so on.

The same thing works for !foo,0 etc.

@NODE[foo] {...} modifies the node which has type 'NODE' and name = foo. 'NODE' is a MODULE {} or a RESOURCE {} or a PROP {} or something like that.

!NODE[foo] {} deletes node foo completely.

NODE {

name = foo

...(stuff)

} creates a new node of type NODE. If there was already a node of type 'NODE', now there's two of them.

for nodes, instead of using a numeric index to identify between multiple nodes, you search by its <tag = ...> line. So if you do

@NODE[foo,bar] {...}

that will find and modify the first node that was defined like this:


NODE
{
name = foo
tag = bar
}

Right now 'tag' isn't being used by anything, but in the future if you need to add multiple nodes, adding a 'tag' field isn't a bad idea. It'd look something like this:


PART
{
name = EngineSABRE
module = Part
...
MODULE
{
name = ModuleEngines
tag = Atmosphere
...
}
MODULE
{
name = ModuleEngines
tag = Vacuum
}
}

and then someone could access the second node by going:


@PART[EngineSABRE]
{
@MODULE[ModuleEngines,Vacuum]
{
...
}
}

Multiple Parts

You can also apply a change to multiple part.

Use a wildcard search for all "name" inside brackets :

All PART whose name start with "B9_"


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

Search for specific module

All PART who have a ModuleEngines


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

will search for part that looks like :


PART
{
MODULE
{
name = ModuleEngines
}
}

Or the absence of a module

All PART who have NO ModuleCommand


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

Search for properties

All PART whith "category = Utility"


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

will search for part that looks like :


PART
{
category = Utility
}

Or the absence of a properties

All PART whithout TechRequired


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

Search for module with a specific configuration

All PART who have a ModuleEngines using XenonGas as a propelant (space for clarity)


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

Combine search

All PART who have a ModuleEngines and have a SolidFuel ressource (space added for clarity)


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

It works at lower level too :

All PART who have a ModuleEngines using XenonGas and ElectricCharge as a propelant (space added for clarity)


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

Use wildcard search at lower level

All PART without ElectricCharge as a ressource but with any other.


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

Some usefull exemples

Add a tech level to all PART who don't have any


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

Add the Mechjeb module to all command pods who don't have it


@PART[*]:HAS[@MODULE[ModuleCommand],!MODULE[MechJebCore]]:Final
{
MODULE
{
name = MechJebCore
}
}

All the exemple use PART but it works on other nodes too :


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

You can also search the old threads for use case :

http://forum.kerbalspaceprogram.com/threads/31342-0-20-ModuleManager-1-3-for-all-your-stock-modding-needs

http://forum.kerbalspaceprogram.com/showthread.php/41616-Extension-for-ModuleManager-with-wildcard-and-conditional-v0-2-24-july-2013

Change for v2.x

New features:

MATH!


@PART[*]:FOR[Realism] {
@mass *= 0.25
@maxTemp -= 500
@scale += 2
}

PROPER INDEXING!


@PART[*]:HAS[MODULE[MultiModeEngine]]:FOR[Pony] {
@MODULE[ModuleEngineFX],1 {
@PROPELLANT[Oxidizer]
{
@name = LiquidOxygen
}
}
}

PER-MOD PARSE PASSES!


@PART[fuelTank]:BEFORE[RealFuels]
{
@RESOURCE[LiquidFuel] {
@amount *= 5
@maxAmount *= 5
}
}

@PART[fuelTank]:AFTER[RealFuels]
{
!RESOURCE[LiquidFuel] {}
!RESOURCE[Oxidizer] {}
}

DEPENDENCY CHECKING!


@PART[fuelTank]:AFTER[RealFuels]:NEEDS[RealSolarSystem,!RealKerbalSystem]
{
@scale *= 4;
}

If it detects a loaded DLL, it assumes it's a mod and creates a :BEFORE, :FOR and :AFTER pass for it.

If you use underscores to specify your mod's version in the filename, ModuleManager will regrettably think that these are part of the filename, because I can't tell the difference between "MyMod_1_3_6" and "Mod_1337s_Cool_Stuff". On the other hand, if you use periods to specify your mod's version, then "MyMod.1.3.6" will correctly be identified as "MyMod".

This means that there will always be the following passes:

:FIRST

:BEFORE[Assembly-CSharp]

:FOR[Assembly-CSharp]

:AFTER[Assembly-CSharp]

:BEFORE[ModuleManager]

:FOR[ModuleManager]

:AFTER[ModuleManager]

:FINAL

Specifying ':FIRST' is optional; I just named the 'main' pass so that the log file is clearer.

If your mod includes a DLL put all your MM patch nodes in the :FOR[yourMod] pass.

If your mod does not include a DLL, then pick a name for your mod THAT DOES NOT CONFLICT WITH ANY OTHER MOD'S DLL, and then put all your MM patch nodes in the :FOR[yourMod] pass.

If you do this, other mods can use :BEFORE[yourMod] and :AFTER[yourMod] to politely modify things furthr at the correct sequence.

The following parameters are currently implemented:

:BEFORE[ModName] - execute this patch BEFORE ModName executes its patches.

:FOR[ModName] - I am ModName, and these are my patches.

:AFTER[ModName] - execute this patch AFTER ModName executes its patches.

:NEEDS[ModName1] - execute this patch only if ModName1 is installed.

:NEEDS[!ModName2] - do not execute this patch if ModName2 is installed.

You can combine NEEDS nodes like this:

:NEEDS[ModName1, !ModName2]

You can match subnodes in one of seven ways:

@NODE[name] // will wildcard match name (so you can do ModuleEnginesFX or ModuleEngines*), and apply itself to the first NODE it finds.

@NODE[name],index // will wildcard match name, and apply itself to the indexth NODE it finds.

@NODE[name],* // will wildcard match name, and apply itself to ALL matching NODEs.

@NODE[name]:HAS[criteria] // will wildcard match name and apply itself to all matching NODEs which also meet the :HAS criteria

@NODE:HAS[criteria] // will apply itself to all matching NODEs which also meet the :HAS criteria

@NODE,index // will apply itself to the indexth NODE it finds

@NODE,* // will apply itself to ALL NODEs

These apply to @, ! and % nodes. $ nodes are necessarily single-application, and thus will always apply to the first node they find.

Edited by sarbian

[1.8.x-1.12.x] Module Manager 4.2.3 (July 03th 2023) - Fireworks season (2024)
Top Articles
Latest Posts
Article information

Author: Duncan Muller

Last Updated:

Views: 5642

Rating: 4.9 / 5 (79 voted)

Reviews: 86% of readers found this page helpful

Author information

Name: Duncan Muller

Birthday: 1997-01-13

Address: Apt. 505 914 Phillip Crossroad, O'Konborough, NV 62411

Phone: +8555305800947

Job: Construction Agent

Hobby: Shopping, Table tennis, Snowboarding, Rafting, Motor sports, Homebrewing, Taxidermy

Introduction: My name is Duncan Muller, I am a enchanting, good, gentle, modern, tasty, nice, elegant person who loves writing and wants to share my knowledge and understanding with you.