Jump to content

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


sarbian

Recommended Posts

Hello. I'm trying to create a script that adds a partmodule (AtmosphericIntake) based on the fields of an existing stock partmodule (ModuleResourceIntake)

 

@PART[*]:HAS[@MODULE[ModuleResourceIntake]:HAS[#resourceName[IntakeAir]]]:FOR[WarpPlugin]
{
	%ResourceIntakeArea = #$MODULE[ModuleResourceIntake]/area$
	%ResourceIntakeTransformName = #$MODULE[ModuleResourceIntake]/intakeTransformName$
	%ResourceIntakeUnitScalar = #$MODULE[ModuleResourceIntake]/unitScalar$

	MODULE
	{
		name = AtmosphericIntake
		area = #$../ResourceIntakeArea$
		intakeTransformName = #$../ResourceIntakeTransformName$
		unitScalar = #$../ResourceIntakeUnitScalar$
	}

	RESOURCE
	{
		name = IntakeAtm
		amount = 0
		maxAmount = 1.0 // stub, will be updated by AtmosphericIntake
	}
}

 What I'm trying to do is readout the area field in the ModuleResourceIntake module.

How can I fix it?

Edit: it appears the only mistake is that the field unitScalar is usually not present. Is there a way to make it optional or give it a default value when not found?

Edited by FreeThinker
Link to comment
Share on other sites

  On 5/26/2019 at 8:22 AM, blowfish said:

@Lisias I'm still interested to hear exactly this mod is/was doing with ModuleManager (not just what methods it was calling, but what was it trying to accomplish)

Expand  

Oh, that communication line got crossed. Sorry.

There're two things, one that is being done now and another that I would like to do instead:

1) Currently, it's using MMPatchLoader's StartLoad to reload the world so the new welded parts became active without restarting KSP. The way the class is searched is specially interesting, as it overcomes the buggy Mono's runtime support for Reflection (long story made short: if anything goes wrong everywhere while loading a DLL, the runtime's Reflection fails miserably for the whole system until restart - damn, I'm becoming repetitive about it).

Whatever you do to the public classes of MM that could be reused, allowing it to be found with UnityEngine.Object.FindObjectOfType apparently will save a lot of grief (as it appears to be imune to the problem described).

2) What I wanna do instead is, somehow (and this is just a bit more than a brainstorming now), plain inject the new welded part into the GameDatabase without reloading the World. Mangling parts on the prefab is not exactly hard, what's hard is to avoid breaking people on the process, and this is where MM could be a huge differential: a common ground mechanism, with concurrency being correctly dealt, to allow safe GameDatabase mangling.

That item 2 thingy would help too to prevent stunts like this one I made on TweakScale - a lot of Add'ons (including the current SquadExpansion and probably the future new one) uses the Main Menu Scene to carry on some unfinished business on GameDatabase, and with everybody running concurrently, a awful amount of feet stomping would be avoided.

— — — POST - EDIT — — --

3) There're a third suggestion that could be lost in the stream, I will avoid repeating it by linking it here.

Edited by Lisias
post edit
Link to comment
Share on other sites

@blowfish @sarbian again I stumbled upon something:

value = #$/MODULE[ModuleEngineConfigs]/CONFIG[*]/maxThrust$

I try to get the value of maxThrust of for example:

	MODULE
	{
		name = ModuleEngineConfigs
		type = ModuleEngines
		configuration = Rutherford
		origMass = 0.05
		modded = false
		CONFIG
		{
			name = Rutherford
			massMult = 1
			minThrust = 15.575
			maxThrust = 22.25

I tried so many variants
value = #$/MODULE[ModuleEngineConfigs]/CONFIG/maxThrust$
value = #$/MODULE[ModuleEngineConfigs]/CONFIG,0/maxThrust$
value = #$/MODULE[ModuleEngineConfigs]/CONFIG[*]/maxThrust$
even nested search weirdness value = #$/MODULE[ModuleEngineConfigs]/CONFIG[#$/MODULE[ModuleEngineConfigs]/configuration$]/maxThrust$

I lost it. What?

Edited by Gordon Dry
Link to comment
Share on other sites

  On 5/28/2019 at 2:48 AM, Gordon Dry said:

value = #$/MODULE[ModuleEngineConfigs]/CONFIG/maxThrust$
value = #$/MODULE[ModuleEngineConfigs]/CONFIG,0/maxThrust$
value = #$/MODULE[ModuleEngineConfigs]/CONFIG[*]/maxThrust$

Expand  

Those all look like they would work to me.  Do you get any errors?  Is there any other reason why this value might not be available (e.g. patch order/wrong pass)?

  On 5/26/2019 at 4:13 PM, Lisias said:

Oh, that communication line got crossed. Sorry.

There're two things, one that is being done now and another that I would like to do instead:

1) Currently, it's using MMPatchLoader's StartLoad to reload the world so the new welded parts became active without restarting KSP. The way the class is searched is specially interesting, as it overcomes the buggy Mono's runtime support for Reflection (long story made short: if anything goes wrong everywhere while loading a DLL, the runtime's Reflection fails miserably for the whole system until restart - damn, I'm becoming repetitive about it).

Whatever you do to the public classes of MM that could be reused, allowing it to be found with UnityEngine.Object.FindObjectOfType apparently will save a lot of grief (as it appears to be imune to the problem described).

2) What I wanna do instead is, somehow (and this is just a bit more than a brainstorming now), plain inject the new welded part into the GameDatabase without reloading the World. Mangling parts on the prefab is not exactly hard, what's hard is to avoid breaking people on the process, and this is where MM could be a huge differential: a common ground mechanism, with concurrency being correctly dealt, to allow safe GameDatabase mangling.

That item 2 thingy would help too to prevent stunts like this one I made on TweakScale - a lot of Add'ons (including the current SquadExpansion and probably the future new one) uses the Main Menu Scene to carry on some unfinished business on GameDatabase, and with everybody running concurrently, a awful amount of feet stomping would be avoided.

Expand  

Maybe back up a couple more steps.  At a high level, how does this mod do part welding?  It sounds like you're creating new configs for the "welded" parts and then compiling them into actual parts?

Link to comment
Share on other sites

  On 5/28/2019 at 2:55 AM, blowfish said:

Those all look like they would work to me.  Do you get any errors?  Is there any other reason why this value might not be available (e.g. patch order/wrong pass)?

Expand  

This is what I get

[WRN 2019-05-28 04:43:05.545] Cannot find key CONFIG in MODULE
[ERR 2019-05-28 04:43:05.545] Error - Cannot parse variable search when inserting new key volume = #$/MODULE[ModuleEngineConfigs]/CONFIG[*]/maxThrust$

for the third variant with CONFIG[*] and the log errors look similar for the other variants.

I checked the original config and the RealPlume patches / RO patches and there definetely IS a ModuleEngineConfigs with a subnode CONFIG with a value maxThrust.

This is an example of the full patch:
(RO compatibility for Rocket Sound Enhancement)

@PART[*]:HAS[@EFFECTS:HAS[@Ammonialox],@MODULE[ModuleEngineConfigs]]:FOR[zzRocketSoundEnhancement]:NEEDS[RealPlume,RealismOverhaul]
{
    @EFFECTS
    {
        @Ammonialox
        {
            !AUDIO{}
            RSE_AUDIO
            {
				name = running
                channel = Ship
                clip = RocketSoundEnhancement/Sounds/sound_lqd_light
				rolloffMode = Linear
				maxDistance = 10000
				
				lowpass = 0 1 -130.8109 -130.8109
				lowpass = 0.016 0.256 -5.289068 -5.289068
				lowpass = 0.064 0.128 -1.238469 -1.238469
				lowpass = 0.256 0.064 -0.15625 0
				lowpass = 1 0.064
				
				volume = 0.0 0.0
				volume = #$/MODULE[ModuleEngineConfigs]/CONFIG/maxThrust$
				
				@volume,1 /= 1000
				@volume,1 += 1
				@volume,1 /= 2
				@volume,1 ^= :^:0.1 :

				pitch = 0.0 0.2
				pitch = 1.0 0.5

                loop = true
            }
        }
        @engage
        {
            !AUDIO{}
            AUDIO
            {
                channel = Ship
                clip = sound_vent_medium
				volume = #$/MODULE[ModuleEngineConfigs]/CONFIG/maxThrust$
				
				@volume /= 1000
				@volume += 1
				@volume /= 2
				
                pitch = 2.0
                loop = false
            }
        }
        @disengage
        {
            !AUDIO{}
            AUDIO
            {
                channel = Ship
                clip = sound_vent_soft
				volume = #$/MODULE[ModuleEngineConfigs]/CONFIG/maxThrust$
				
				@volume /= 1000
				@volume += 1
				@volume /= 2
				
                pitch = 2.0
                loop = false
            }
        }
        @flameout
        {
            !AUDIO{}
            AUDIO
            {
                channel = Ship
                clip = sound_explosion_low
				
				volume = #$/MODULE[ModuleEngineConfigs]/CONFIG/maxThrust$
				@volume /= 1000
				@volume += 1
				@volume /= 2
				
                pitch = 2.0
                loop = false
            }
        }
    }
}

 

This btw is the original patch that is for non-RO - and it works this way:

  Reveal hidden contents

 

Link to comment
Share on other sites

@blowfish

This is the actual variant of the code which does not throw MM errors but also does not do anything:

@PART[*]:HAS[@EFFECTS:HAS[@Kerolox-Upper],@MODULE[@ModuleEngines*]:HAS[#maxThrust[>0]]]:NEEDS[RealPlume]:FOR[ZZROCKETSOUNDENHANCEMENT]
{
    @EFFECTS
    {
        @Kerolox-Upper
        {
			!AUDIO{}
            RSE_AUDIO
            {
				name = running
                channel = Ship
                clip = RocketSoundEnhancement/Sounds/sound_lqd_medium
				rolloffMode = Linear
				maxDistance = 10000
			
				lowpass = 0 1 -130.8109 -130.8109
				lowpass = 0.016 0.256 -5.289068 -5.289068
				lowpass = 0.064 0.128 -1.238469 -1.238469
				lowpass = 0.256 0.064 -0.15625 0
				lowpass = 1 0.064
				
				volume = 0.0 0.0
				volume = #$/MODULE[ModuleEngines*]/maxThrust$
				
				@volume,1 /= 1000
				@volume,1 += 1
				@volume,1 /= 2
				@volume,1 ^= :^:0.1 :

				pitch = 0.0 0.5
				pitch = 1.0 1.0

                loop = true
            }
		}
		
		@engage
		{
            !AUDIO{}
			AUDIO
            {
                channel = Ship
                clip = sound_vent_medium
				volume = #$/MODULE[ModuleEngines*]/maxThrust$
				@volume /= 1000
				@volume += 1
				@volume /= 2
				
                pitch = 1.0
                loop = false
            }
		}
		
		@disengage
		{
            !AUDIO{}
            AUDIO
            {
                channel = Ship
                clip = sound_vent_soft
				volume = #$/MODULE[ModuleEngines*]/maxThrust$
				@volume /= 1000
				@volume += 1
				@volume /= 2
				
                pitch = 1.0
                loop = false
            }
		}
        @flameout
        {
            !AUDIO{}
            AUDIO
            {
                channel = Ship
                clip = sound_explosion_low
				volume = #$/MODULE[ModuleEngines*]/maxThrust$
				@volume /= 1000
				@volume += 1
				@volume /= 2
				
                pitch = 2.0
                loop = false
            }
        }
	}
}

@PART[*]:HAS[@EFFECTS:HAS[@Kerolox-Upper],@MODULE[@ModuleEngines*]:HAS[~maxThrust[>0]],@MODULE[ModuleEngineConfigs]:HAS[~type[ModuleRCS],#origMass[>0],@CONFIG:HAS[#maxThrust[>0]]]]:NEEDS[RealPlume,RealismOverhaul]:LAST[ZZROCKETSOUNDENHANCEMENT]
{
    @EFFECTS
    {
        @Kerolox-Upper
        {
			!AUDIO{}
            RSE_AUDIO
            {
				name = running
                channel = Ship
                clip = RocketSoundEnhancement/Sounds/sound_lqd_medium
				rolloffMode = Linear
				maxDistance = 10000
			
				lowpass = 0 1 -130.8109 -130.8109
				lowpass = 0.016 0.256 -5.289068 -5.289068
				lowpass = 0.064 0.128 -1.238469 -1.238469
				lowpass = 0.256 0.064 -0.15625 0
				lowpass = 1 0.064
				
				volume = 0.0 0.0
				volume = #$/MODULE[ModuleEngineConfigs]/CONFIG/maxThrust$
				
				@volume,1 /= 1000
				@volume,1 += 1
				@volume,1 /= 2
				@volume,1 ^= :^:0.1 :

				pitch = 0.0 0.5
				pitch = 1.0 1.0

                loop = true
            }
		}
		
		@engage
		{
            !AUDIO{}
			AUDIO
            {
                channel = Ship
                clip = sound_vent_medium
				volume = #$/MODULE[ModuleEngineConfigs]/CONFIG/maxThrust$
				@volume /= 1000
				@volume += 1
				@volume /= 2
				
                pitch = 1.0
                loop = false
            }
		}
		
		@disengage
		{
            !AUDIO{}
            AUDIO
            {
                channel = Ship
                clip = sound_vent_soft
				volume = #$/MODULE[ModuleEngineConfigs]/CONFIG/maxThrust$
				@volume /= 1000
				@volume += 1
				@volume /= 2
				
                pitch = 1.0
                loop = false
            }
		}
        @flameout
        {
            !AUDIO{}
            AUDIO
            {
                channel = Ship
                clip = sound_explosion_low
				volume = #$/MODULE[ModuleEngineConfigs]/CONFIG/maxThrust$
				@volume /= 1000
				@volume += 1
				@volume /= 2
				
                pitch = 2.0
                loop = false
            }
        }
	}
}

There is no single instance in the ModuleManager.ConfigCache where AUDIO has been replaced by RSE_AUDIO - that alone shows me that the patch does nothing at all.

All the checks are necessary to avoid failures because of a handful of part packs.

Edited by Gordon Dry
Link to comment
Share on other sites

  On 5/28/2019 at 6:06 PM, Gordon Dry said:

!AUDIO{}

AUDIO{

// ....

}

Expand  

I'm new when comes to MM syntax, but above does not look legit to me.
I suppose that firts "!AUDIO{}" command try to earse whole AUDIO module and after that, to add new one.

Does MM can handle such thing properly ?

 

Link to comment
Share on other sites

  On 5/28/2019 at 6:59 PM, kcs123 said:

I'm new when comes to MM syntax, but above does not look legit to me.
I suppose that firts "!AUDIO{}" command try to earse whole AUDIO module and after that, to add new one.

Does MM can handle such thing properly ?

 

Expand  

Yes, lots of mods do that.  The syntax is correct

Link to comment
Share on other sites

  On 5/28/2019 at 2:55 AM, blowfish said:

Maybe back up a couple more steps.  At a high level, how does this mod do part welding?  It sounds like you're creating new configs for the "welded" parts and then compiling them into actual parts?

Expand  

Yes. Essentially, a 'welded" part is a new synthetic part, living in a new CFG file. How the part is built is somewhat out of scope to this problem, but essentially we "join" the meshes and textures, recalculate mass, CoM, CoL, etc, and create a new part that ideally woud behave as the parts "welded" behaved when they were separated.

Edited by Lisias
A bit less worse grammars
Link to comment
Share on other sites

  On 5/28/2019 at 6:59 PM, kcs123 said:

I suppose that firts "!AUDIO{}" command try to earse whole AUDIO module and after that, to add new one.

Expand  

Yes, that works fine. Also best practice. Ripping out the old module, then inserting your new one often is easier and less error-prone than trying to modify it.

I've got a question of my own: what's the smart approach to applying a patch to each and every part from one particular mod?

Link to comment
Share on other sites

  On 5/30/2019 at 4:33 PM, Laie said:

I've got a question of my own: what's the smart approach to applying a patch to each and every part from one particular mod?

Expand  

Depends on the mod.  Some have a systematic naming scheme which makes it easy - a simple glob and you're done.

Link to comment
Share on other sites

Working on a patch for BreakingGround

I want to add one InventorySlots per seat in each command pod, here is what I have - corrections and improvements are solicited and appreciated:

  Reveal hidden contents

thank you in advance!

gameplay balance: this is what each kerbal already has inherently in their backpack, so is just reflecting this in their seat.

 

and two more I have been working on for kOS - setting diskspace based upon mass for crewed, and based upon SASServiceLevel for unmanned. Again, suggestions and corrections appreciated:

  Reveal hidden contents

 

Edited by zer0Kerbal
Link to comment
Share on other sites

  On 5/31/2019 at 6:24 AM, zer0Kerbal said:

@PART[*]:HAS[#CrewCapacity[>0],!MODULE[ModuleInventoryPart]:NEEDS[BreakingGround]:FINAL

Expand  

How MM recognize name "BreakingGround" as name of DLC/mod/addition ? Is it hadcoded somewhere ?
I found that DLC is installed into "..\Gamedata\SquadExpansion\Serenity\" folder. No any dll plugin with "BreakingGround" in name either.

In another word, is it legit to put "BreakingGround" in MM filter and be certain that something was not messed up ?

Link to comment
Share on other sites

  On 5/31/2019 at 7:52 PM, kcs123 said:

How MM recognize name "BreakingGround" as name of DLC/mod/addition ? Is it hadcoded somewhere ?
I found that DLC is installed into "..\Gamedata\SquadExpansion\Serenity\" folder. No any dll plugin with "BreakingGround" in name either.

In another word, is it legit to put "BreakingGround" in MM filter and be certain that something was not messed up ?

Expand  

good catch - that was a placeholder while I was spitcoding and forgot to change it. thank you for noticing - it should be :NEEDS[Serenity]. will fix in above.

Link to comment
Share on other sites

  On 5/29/2019 at 12:56 PM, Lisias said:

Yes. Essentially, a 'welded" part is a new synthetic part, living in a new CFG file. How the part is built is somewhat out of scope to this problem, but essentially we "join" the meshes and textures, recalculate mass, CoM, CoL, etc, and create a new part that ideally woud behave as the parts "welded" were when separated.

Expand  

Okay, that makes more sense.  Does building the new "welded" part config involve MM patching, or are you putting it in the game database in its final state?

Link to comment
Share on other sites

  On 6/2/2019 at 10:43 PM, blowfish said:

Okay, that makes more sense.  Does building the new "welded" part config involve MM patching, or are you putting it in the game database in its final state?

Expand  

after a part is welded - it is standalone (except for the models/textures it requires). Example of a weldedpart:

  Reveal hidden contents

 

Link to comment
Share on other sites

a little assistance kindly:

want to make sure all crewed pods have MonoPropellent: so the patch adds 5 to any pod without, then adds 5 units per crew capacity to all pods with MP.

so a pod without: 5/5

pod with: MaxAmount+(5*CrewCapacity)

Would appreciate some error checking and suggestions. Thank you.

  Reveal hidden contents

 

Link to comment
Share on other sites

  On 6/3/2019 at 6:19 AM, zer0Kerbal said:

a little assistance kindly:

want to make sure all crewed pods have MonoPropellent: so the patch adds 5 to any pod without, then adds 5 units per crew capacity to all pods with MP.

so a pod without: 5/5

pod with: MaxAmount+(5*CrewCapacity)

Would appreciate some error checking and suggestions. Thank you.

  Reveal hidden contents

 

Expand  

Well you've got the arithmetic part basically right, just the RESOURCE:HAS[!RESOURCE[MonoPropellant]] bits are incorrect.  HAS is used to check the node you're currently patching, so HAS[RESOURCE[MonoPropellant]] would only be valid at the top level.  It also looks like you're trying to edit the resource in the second part but not using an operator to actually edit the node?  Try this

  Reveal hidden contents

I added a few comments to try and explain what's going on there, of course they don't have to be part of the final patch.

Link to comment
Share on other sites

  On 6/3/2019 at 7:56 AM, blowfish said:

Well you've got the arithmetic part basically right, just the RESOURCE:HAS[!RESOURCE[MonoPropellant]] bits are incorrect.  HAS is used to check the node you're currently patching, so HAS[RESOURCE[MonoPropellant]] would only be valid at the top level.  It also looks like you're trying to edit the resource in the second part but not using an operator to actually edit the node?  Try this

  Reveal hidden contents

I added a few comments to try and explain what's going on there, of course they don't have to be part of the final patch.

Expand  

thank you.

I understand now and appreciate the assistance both for its timeliness and usefulness. 

Link to comment
Share on other sites

This is just a heads up. In the breaking ground release Squad has done something I didn't think was valid. I've now seen two places where Squad patches add new nodes for existing parts instead of appending to existing nodes. It apparently doesn't create problems in the stock game, but can cause issues with mod patches.

For example: kerbalEVA is the part definition for the male Kerbal in the default suit. It's originally defined in GameData\Squad\Parts\Prebuilt\kerbalEVA.cfg. There's a different files for each suit and gender combination, but all have the pattern kerbalEVA*. Serenity adds the new pick up rocks science experiment to each Kerbal in  GameData\SquadExpansion\Serentiy\Parts\Prebuilt\kerbalEVA.cfg. The gotcha is that instead of patching the existing kerbalEVA PART node with @PART, the files create a new PART (no '@') with the same name with just the science experiment in it. 

You can see the multiple PART nodes in the ModuleManager.ConfigCache. I guess the partloader merges all the nodes with the same part name together eventually. Mods (like KAS) that add modules to kerbalEVA* need to be careful to catch the correct node definition otherwise it's modules can be duplicated on a part node with unintended consequences. This is one of the things breaking KAS on 1.7.1 launch, it's patches need to be more specific to prevent duplicate KAS modules on each Kerbal.

The second case was less of a problem. The same thing happens with GameData\SquadExpansion\Serenity\Experience\Traits.cfg. A new EXPERIENCE_TRAIT node is created to add skills for Engineers and Scientists related to the deployed ground experiments. This caused patches for mods that expand the list of traits like Extraplanetary Launchpads and MKS to run on multiple nodes duplicating their changes. At least in this case you only get a warning that the trait already exists in the database for each of the duplicates.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...