#Learning to use Patch Manager
1 messages · Page 1 of 1 (latest)
I'm also interested in learning Patch Manager as well!
basically, the game contains definitions for most things like celestial bodies, parts, experiments, tech tree nodes, etc. in JSON files stored in addressable bundles
assets can each have labels, and those are used by the game to retrieve them, and more than 1 asset can have the same label
so for example, all part definition JSON files have the label "parts_data", and the game loads all assets with that label when it's trying to create its internal database of parts
what Patch Manager does is that it allows you to target a specific label, go through all assets in it, and basically arbitrarily modify the values in the JSON
Oooooooh
and also create or delete JSON files in labels
I know there's a bunch of tools in #🔴tools-and-resources that I've never used for inspecting the game's contents, if I want to look through those JSON files do I use one of those tools or are they just part of my installation?
Text Asset Dumper, made specifically for this purpose
you can use CKAN to download TextAssetDumper (or, alternatively, download it from https://github.com/KSP2Community/TextAssetDumper)
Oh! Perfecttttt
so if you want to see for example all part definitions, you just dump the assets and go to BepInEx/plugins/TextAssetDumper/dump/text_assets/parts_data
and they will all be there
There are around 400 parts in the game after all
Interesting that the game is put together that way. Seems like that is very conducive for modding?
and to make the patching easier (because the structure of some of these JSON files is quite complex leading to rather cumbersome patches), Patch Manager also has some custom "rulesets" like :parts or :resources, which basically transforms the JSON files of specific type into a much easier hierarchy to work with within the patch file
I don't know a ton about game development, but I imagine in general formats like JSON are used a bunch because you can have a tool for the artists and game designers to use that doesn't require them to know how to code, and then take the data from that and load it into the game
I think a large part of it is also because it's just really easy to export objects from Unity editor into it
I've written a parser for .JSON files before so Im actually decently familiar with them
in python you can literally just read in json and it autoconverts to a dictionary ahahahahahahaha
Okay, thanks a ton!
there's quite a lot of information in the docs already: https://pm.kerbal.wiki/overview.html
but there's also still a lot missing, so definitely ask anytime you want
Okay!
and the forum thread also contains some (I think) useful examples of patches https://forum.kerbalspaceprogram.com/topic/221179-080-patch-manager
Patch Manager A mod for all your generic patching needs! Spacedock: https://spacedock.info/mod/3482/Patch Manager Github: https://github.com/KSP2Community/PatchManager Author: KSP2 Community Description Patch Manager is a mod for KSP2 that functions as a sort of spiritual successor to Module Mana...
So, say I want to change a value within a map within a list
My idea for how the syntax for this might work is something like
but this isn't valid syntax apparently
oh yeah, I was just complaining to Cheese today that it's too bad this isn't possible lol
ahh
could you show the part before that?
Why did I not make a list.set function aaaaa
but thats not necessary there
@use "builtin:dictionary";
@patch kerbin_science_regions;
:json #kerbin_science_regions {
Regions[0]: $value:set(landedScalar, 1000.0);
}
dammit Cheese
faster

but wait
I didn't even know you can assign to a list index
in that case we definitely could add dictionary key assignment
Learning to use Patch Manager for you too Munix
it's the same thing basically
We do have dictionary key assignment
excusemewhat
its just every time I've used the set function its been a dictionary in a list
I suppose I could see about making nested indexers though
at least in values like that
but 
If I wanted to set the same value for every dictionary in the list, how would I do that? Do I have to make a function to create a loop or is there a shorter form?
so in that one patch, the map function could have been "simplified" to this?
$inclineMinmus: @function($body) {
@if $body['GUID'] == 'Minmus' {
$body['OrbitProperties']: $body['OrbitProperties']:set('inclination', 45.0);
}
@return $body;
};
I don't have indexers for variables, only fields

@use "builtin:dictionary";
@use "builtin:list";
@patch kerbin_science_regions;
:json #kerbin_science_regions {
Regions: $value:map(@function($item) { @return $item:set(landedScalar, 1000.0);});
}
hmm that doesn't seem to actually change anything in game
check the logs and the PM cache
BepInEx/plugins/PatchManager/cache/kerbin_science_regions.zip
inside it you can find the modified JSONs, so you can check if the change was applied or not
I don't see a zip with that name, only missions.zip
then there's an issue with the patch
the logs will probably tell you what
oh wait
I can't even find any label with the name kerbin_science_regions in the dump
ohhh I get it
it's the name of the asset
but you need to patch the label
aka the folder that the asset is in
that would be "science_region" in your case
Ahhhhhhhhhhhhhhhhhhhh
@use "builtin:dictionary";
@use "builtin:list";
@patch science_region;
:json science_region {
@if $$BodyName == Kerbin {
Regions: $value:map(@function($item) { @return $item:set(landedScalar, 1000.0);});
}
}
I think this is what you want
ah right
Okay I am now beyond confused. This is the resulting "Regions" list in my cache. My Test.patch definitely has LandedScalar spelt correctly though, with the L capitalized and everything
is the file outside any mod?
well actually, shouldn't even matter
you need to enable Patch Manager cache purging
in Settings -> Mods -> Patch Manager
Ohhhhhhhhhhh
it won't know to rebuild the cache unless a mod is installed, updated or removed
but you can configure it to always happen on game start
for development
If I want to patch the values for Laythe, which are in the folder Laythe.json, then I need to write @patch Laythe.json or just @patch Laythe?
Even if i just want to add to LocalSimObjectsData?
Or well for laythe I guess i'd be creating that list
@ripe lance Okay I tried not using shoemaker, patch manager seems to have tried to load the patch without error but nothing actually happened (like it didn't even generate anything in the cache) so I'm assuming that shoemaker is necessary to do anything at all with planets?
its not necessary, but hmm it sounds like you are doing something wrong
shoemaker just makes it a lot nicer
ahh
I think the part of patch manager that I just do not understand is the stuff on the very first page of syntax stuff, the selection rules
so
that's probably where my issue is
This is how I'm attempting to add a list to the map called data under Laythe.json
yeah that won't work as is
aaaa
Why is it celestial_bodies? I thought it was supposed to be the name of the folder?
because that is the name of the folder, you'll find the same asset under that folder
So the same asset can appear multiple times?
yes
ahhhhhhhhhhhhh
Okay
And then, I'm trying to add an entry to a dictionary, so how would I do that?
you can just use myDict: myDict.set(key, value)
@use "builtin:dictionary";
$value:set
as the full signature of set is dictionary.set and it gets the type from the $value's type
plus you need the first argument
which is given by using $value
Sorry if this is dumb, but how do I select the J404 Panther engine? I tried using TextAssetDumper and go "engine_1v_turbofan_methane_panther" but whenever I use it, it doesn't work.
idk
what do the logs say? is the part just not being patched at all?
//Module_Engine
:parts {
#engine_1v_turbofan_methane_panther > Data_Engine > engine_mode {
maxThrust: 1000.0;
}
}
here, sorry im dumb just started learning to program
Me and someone else who I wont say the name of are working on a mod that edits the engines to be their real-life counterparts
Didnt realise A Terrible Modder is doing something that is pretty similar
is he?
idk from the looks of it hes adding more engines as well
as far as I know, he's making a propeller engine part, not editing existing parts
one issue I can see is that you're missing Module_Engine in there
this is an example from the forum thread
oh ok
So Ive mostly gotten what I wanted working but I do have one issue still
let me get the code rq
Ive tried a lot of different ways and looked through the wiki and asset dumps, but I just cant seem to find how to select only the afterburning mode (I am using the expanded version on purpose so later I can edit other parts and modules of parts
:parts {
#engine_1v_turbofan_methane_panther
{
* > Module_Engine {
* > Data_Engine {
* > #EngineModeID.["Wet"] {
maxThrust: 107.0;
}
}
}
}
}
This is the best I can get to so far
still doesnt do anything though
just engineMode[1] didn't work?
(assuming 0 is the normal and 1 is the afterburner)
gives me an error
yeah thats what I tried
this is where I got #EngineModID from btw
sorry, engineMode__s__[1]
ill see if that works next
(from the screenshot above)
(in VS Code, not the game)
This works! Thank you for being patient since i've been asking pretty much the same stuff for the last couple days....
I am new to patching and I believe I have a gross conceptural error about selecting. In the below image, the top patch works just fine while the bottom one is probably the N+1th iteration and I'm getting no where. I've also included the full context of the "rate" element I'm trying to patch from the cache zip. Am I not selecting through the Module arrays correctly or something?
that would be how you'd go about the patch if you were using the generic :json ruleset
but the specialized rulesets like :parts have some syntactic sugar and pre-processing done
so they don't exactly match the JSON structure
it's mostly to simplify some complex structures and long selectors
And otherwise impossible selectors
I believe your second patch would look more like this:
:parts #generator_0v_thermoelectric_radioisotope {
* > Module_Generator
* > Data_Generator {
* > ResourceSetting {
Rate: 1234;
}
}
}
}
or, simplified:
:parts #generator_0v_thermoelectric_radioisotope > Module_Generator > Data_Generator > ResourceSetting {
Rate: 1234;
}
Interesting. I want to say that learning had occurred, but tinkering is certinaly in progress.
we should probably put some specific examples on the wiki (https://pm.kerbal.wiki/part-patching-tutorials.html)
there's just always too many things to do and too little time to write more documentation 😆
True enough. However, if you do put an example, you'll be my favorite person for the subsequent hour and forty five minutes or so. Depends on when the pizza arrives.
After some reading about Data_ModuleGenerator, this worked as expected. ```:parts #generator_0v_thermoelectric_radioisotope {
-
Module_Generator
-
Data_ModuleGenerator {
ResourceSetting[Rate] : 1234;
}
}```
-
oh yeah, sorry, I didn't notice it's actually called Data___Module__Generator
weird
as far as I can tell, that's the only one that doesn't follow the convention
(PartComponentModule_XYZ -> Data_XYZ)
However, that omission was indirectly helpful since it sucked me further into the documentation.
Transmitter too is weird
Yeah, it is
I'm trying to build a dictionary of <string, List<string>> but I just can't figure out how dictionaries work.
I've tried various things, but this is what I have currently:
$bodies-and-regions: {};
:discoverables {
$body: $$BodyName;
$log: debug-log("Starting body: " + $body);
/* do I create a new dictionary kvp with this? */
$bodies-and-regions: $value:set($body, []);
@each $discoverable in $$Discoverables {
$region-name: $discoverable["ScienceRegionId"];
@if is-ignored($region-name) {
$log: debug-log($region-name + " is ignored!");
} @else {
$log: debug-log($region-name + " is NOT ignored!");
}
/* append a new region (string) to the existing list for the current body ??? */
$bodies-and-regions: $value:set($body, $value[$body]:append($discoverable[ScienceRegionId]));
}
/* Let's see what we have so far */
@each $k, $v in $bodies-and-regions {
$log: debug-log("Spice must flow");
$log: debug-log("Key: " + $k);
@each $reg in $v {
$log: debug-log("Reg: " + $reg);
}
}
}
At the end of each file I'm doing logging to see what I have so far.
$bodies-and-regions is a top level variable so its data should persist through each discoverable file, right?
What I'm getting in the log is just the current body and its regions, so I guess I'm not creating new dictionary entries for each file but overriding the only entry in it? Or the data in $bodies-and-regions isn't persisting? Or something else?
Umm this is where the abstraction of PM being completely parallel gets in the way
I see the use in what you are trying to do, but it's going to take me a bit to think of a way to actually do it
Yeah, first noticed that when I wanted to do the logging in the end was when I did the logging outside of the :discoverables block, right after it, at top-level, so I'd log it only once. Then saw in the log that that part was executed very early on. So the order of commands in a patch file isn't executed linearly. That's ok, I figured I could solve that with staging.
But I didn't expect to see these logs writing only values for the current body.
What's happening exactly? The $bodies-and-regions variable is destroyed after each :discoverables pass I guess?
You are shadowing the global variable with $bodies-and-regions
There is no way yet to do this, but I may allow it.
Oh I see, ok
@ripe lance, I assume I can't do:
:discoverables {
@new($mission-id)
:missions {
...
}
}
Because I can't create a :mission object inside of a :discoverables scope, right? If so, I'll need to be able to create that top-level dictionary. Or I'll just type the list manually for now.
You have to do it manually for now...
This is a lot of complex usage I wasnt planning for
The issue with stages here tho
Is the order of running
It goes first by label
Then by stag3
Not first by stage then label
I see. Alright, thanks for the input.
I have a problem that I think boils down to a problem with my patch file. After creating a module and attempting to load it, I get a sassypatch exception reading "Unknown part module Part_behavior_Class". Does anyone have any advice on where my problem may be?
:parts {
@if $$crewCapacity > 0 {
+Part_behavior_Class {
+Data_Class {
}
}
}
}
that sounds like your class isn't loaded in the game at the time of patching
are there any exceptions coming from your DLL plugin?
Would those exceptions be recorded in the Player.log file? If so, there does not appear to be any other exceptions relating to the mod.
yeah, they would
I am using the spacewarp template and using build and deploy. How would I go about seeing if the class has been loaded or ensuring that it gets loaded?
do you see your mod in the modlist?
yes

