#Patch Manager
1 messages · Page 8 of 1
sure
/// <summary>
/// This is the current universe that patch manager is using (used for interop reasons)
/// </summary>
[PublicAPI]
public Universe CurrentUniverse => PatchingManager.Universe;
Make sure to base it off of main, I have stuff on dev
yeah dw
Except it should be static
Which we are hotfixing
Another success on the release action
We really just need a spacedock uploader
all done, Nuget is uploaded as well, so you can just update the reference version to 0.7.2 @desert stirrup
(and install the newest version in the game)
yeah, then it will be basically 0 effort to make a release
well, other than the forums

we need to bully nicely ask Dakota to open up the API
Then we can autopost our unformatted markdown :3
lmao
I mean
then we could use a Markdown to HTML parser
and post it directly in HTML which the forum editor uses
ikr
Doing all this work just to automate all the tedium
shouldn't something like this work?
:parts #decoupler_??_radial {...}
That just gets turned into /decoupler_.._radial/ as a regex
Well ? is the same as . and * is the same as .*
You can do like
:parts #decoupler_??_radial {
$log: debug-log("Found " + $$partName);
}
Its how I debugged the engine mode stuff
Like 1 min till the game im at starts so really gotta dip
yeah the selector worked, I was just being stupid
@desert stirrup String interpolation is shaping up to be fun
For reference though, in the next updat this will look like
$visual-parts: ["#antenna_0v_dish_ra-2", "#antenna_1v_parabolic_dts-m1", "antenna_1v_dish_hg55", "antenna_1v_dish_88-88"];
$biome-parts: ["antenna_0v_dish_ra-15", "antenna_1v_dish_ra-100"];
@each $visual-part in $visual-parts {
:parts #"#{$visual-part}" {
// do stuff
}
}
As long as you're having fun, that's all that matters 🙂
Just wait until I allow interpolation in functions and variable names (/j)
That looks a bit weird, but I can understand why it's like that. Could you maybe add some shorthand for that if we're dealing with lists? I mean I'll work with this, I can understand it, but would be nice to have something a bit easier for non programmers.
This part
#"#{$visual-part}"
"#{...}" -> eval(...).ToString()
But yeah its SCSS string interpolatioj
I'm not sure how I'd shorten that tbh?
#$visual-part maybe but would I allow $$property there as well?
couldn't we just allow use of variables in selectors as they are?
@each $visual-part in $visual-parts {
:parts $visual-part {
// do stuff
}
}
That doesnt work because semantically id have to interpret that as a type not a name
So itd have to be #$...
Pinging sinon to update the syntax yet again will be fun
Custom modules, if I define a property like this:
public ModuleProperty<float> MaximumAltitude = new (0, true, val => $"{((float)val/1000):N0} km");
it still won't be read-only, it'll spawn with a slider in Flight scene (the true is for the isReadOnly parameter).
If I place a [KSPState] attribute, it WILL be read-only, but then the value is saved in state/save file, so if I change this value in a future update, it won't be updated in existing saves for existing vessels.
If I place [JsonIgnore] (like IG does in some of their modules) it will also be read-only, but now the property is completely ignored by Patch Manager and it defaults to 0.
If I place [KSPDefinition] it again is NOT read-only.
So the only solution I see is to place [JsonIgnore] and set the value through code. I can grab the config value defined in patch's constants, but the rest of the patch will look "barren". It will just have +Data_OrbitalSurvey {} and that's it. I was hoping to set the values directly with PM.
That's annoying
What you can do is have a backing value, that when you initialize your module you copy into the property
Hmm, that's true. I did that yesterday before I found a way to directly set the value for the property. I'll try it that way.
so like
[KSPDefinition]
public float MaximumAltitude;
[JsonIgnore]
public ModuleProperty<float> MaximumAltitudeProperty = new (0, true, val => $"{((float)val/1000):N0} km");
Then copy maximumaltitude into the property
Yeah it works like this. It's ugly, but it works.
Spacedock Mod Website is set to: https://spacedock.info/mod/3482/pm.kerbal.wiki
I'm now confused on how if statements ever worked in selection blocks
Give me a second
ahh nevermind
I need to implement the ISelectionAction with each/for/while
If I patch a part, will it affect parts already added to a vehicle?
It should*
It wont change fuel amounts or whatever I dont think but anything labelled KSPDefinition in the decompiled code it will update
k, thanks!
also what is the best source of looking at existing part definitions? I'm using Text Asset Dumper, but not sure if there is anything in game I could be using.
Text asset dumper is your best bet
great, thanks so much!
@north mist i'm going to make a PR for the interpolation stuff, but maybe I should bang out a spacedock uploader first
Honestly, it might be a good idea to integrate the language server stuff into the project somehow
yeah, agree with both
That'll be a later thing
I need to actually figure out how to do REST stuff with spacedock
@north mist does this action store cookies?
https://github.com/marketplace/actions/http-request-action
I need to make http requests that have cookies
I wouldn't bet on it if it doesn't mention them anywhere on the page
you can just use curl tbh
Is curl installed by default?
SpaceDock doesn't have API tokens
I would assume so, considering the ubuntu runner even has Mono, .NET and PowerShell
curl is one of the more basic tools
Why the fuck does curl return the entire HTML of the site and then the response
curl curl
ohhh
lmao
@north mist you think this will work?
https://github.com/KSP2Community/PatchManager/blob/dev/.github/workflows/on-release.yml
wait
changelog is wrong
other than that though?
Fixed that part
it looks good to me
One way to find out if it works then
Sorry about the huge update again
a lot of it was all necessary for string interpolation
the other chunk is actually moving the +/-/* operators to just use operator overloads in the DataValue class
bold of you to assume I'll read every line of it

(ngl I actually do, but half the time I barely understand the inner workings of the whole thing so I just quickly scroll through it to see if I can notice any obvious mistakes)
lol
lmao good thing I waited
Fixed
This would've been a fun error
Anyways you are good to submit your review and then we can test the magical spacedock uploader
Need to do some sanitization
And to change the game version
I'm going to delete the release version and try again
Aaaaa wait the nuget repo
hm?
it doesn't look to me like you use the version check flag for the uploads so it shouldn't interfere
Doesn't it terminate early if it fails?
does an action fail if its step has an if that's false?
I have no clue tbh
I was assuming it would just skip the step
Lets try
but maybe not
But the version check has an exit 1
I'm going to remove the exit 1
yeah
sed 's/@/%40/g' having to use sed is fun
lol
attempt no. 2
The changelog definitely needs more sed work
The download is correct though
@north mist should I bring the same action over to Space Warp?
yeah definitely!
Actually jq does the trick bettter
I'll add it to the template, too, if you don't mind
Go ahead
Use the dev branch
and do not forget the add mask action
Otherwise passwords will be leaked in the logs
of course
I'm going to make some changes in the space warp version that I'm going to backport into the PM version
so hang on a second
sure thing, I'll add it later, I'm working on something else rn anyway
going to use the spacedock api to query the latest game version
There that should work now
I see version 0.8.0 on spacedoc, but for some reason CKAN still thinks the current version is 0.7.3, so I can't upgrade using CKAN currently
Also on spacedoc it says: "the first test of our automatic uploader for SpaceDock, so if anything is wrong with the download, notify us." ... I wonder if it could be related or if it will clear in a bit
The spacedock download seemed fine
yeah, shouldn't be related
Don't tell me its that netkan thing
Can you guys see it in CKAN?
LMAO
spec_version: v1.34
identifier: PatchManager
$kref: '#/ckan/github/KSP2Community/PatchManager'
$vref: '#/ckan/space-warp'
x_netkan_version_edit:
find: ^v
replace: ''
strict: false
license: MIT
tags:
- plugin
- library
depends:
- name: SpaceWarp
install:
- find: BepInEx
install_to: GameRoot
include_only:
- patchers
- plugins
x_netkan_override:
- version: '0.7.3'
override:
ksp_version_max: '0.2.0'
---
spec_version: v1.34
identifier: PatchManager
$kref: '#/ckan/spacedock/3482'
$vref: '#/ckan/space-warp'
license: MIT
tags:
- plugin
- library
depends:
- name: SpaceWarp
install:
- find: BepInEx
install_to: GameRoot
include_only:
- patchers
- plugins
don't tell me it's what I said yesterday
lmao
of course it is

that was... not very well thought through on their side?
I think its because we have an unbounded max version of KSP2
Cuz the spacedock API gives a KSP2 version
That's only slightly annoying
@hexed yarrow check now though
just marks them red
yes
I see 0.8.0 now
ok, and the remote supported KSP2 version check makes that easier to deal with
without having to update the mods
Yep
yeah this is not as bad as I thought
Thanks so much!
i remember that someone posted an example of how to make a list and then loop thru it with the new syntax
do u know where that was, i cant find it
o here #1115274490490929172 message
I've noticed the wiki says that functions are created with @func, but it seems to actually be @function:
Why did I say that aaaaa
Ill fix it when I get on my computer and add string interp reference
Moving here, indexers for variables could be possible to implement, but a helluva pain
it would be nice for the sake of consistency
they are easier for fields, as fields don't have the requirement of being immutable
while for variables you'd have to create a deep copy and modify just the one index, I'm assuming
yep
well it only has to be as deep as the index, the immutable requirement allows us to share references like that
I see
but yeah, I think that at some point that + the nested indexers would be very nice QoL improvements (especially for non-programmers just trying to patch some stuff) over the nested set and map calls
Question for oyu
/* Nothing before this */
$val[x]: 5;
Should this automatically create a dictionary like the following
$val: {
x: 5
};
@north mist
It'd allow you to for example define vectors like the following
$normalized[x]: $vec[x]/$mag;
$normalized[y]: $vec[y]/$mag;
$normalized[z]: $vec[z]/$mag;
yeah that'd be cool
Aight, I'll do this in the update after this next one I'm releasing
Speaking of which @north mist can you review my PR (it has zero warnings, and no antlr changes, so its short)
lmao sure
And I'll likely ping you again when I make the Shoemaker PR after I clean that up
Now time to test my updated spacedock uploader
That didn't go as expected

I'm about to just write the stuff to a file, then read it when using curl
We need 200 peoplre using this
is-it possible with patchmanager to make condition (IF...) on mod installed ?
with 2.5x Kerbolar System, i'd like to reduce my engines thrust like real ones
Yes
Just do a
@require KerbolarUpscale before your patch block
But uhh, reducing thrust really only makes sense if you have accurate weights for everything
you right Cheese.
Hy. I will modify some part parameters. When players will update my mod, is patchmanager cache automaticly refresh ?
yes, it refreshes when any mod version changes
To really achieve feature parity with KSP1 we need loading time parity 
I mean, we really have no clue how much PM will affect the loading
we'd need to get to substantially higher part and patch counts to do proper benchmarks
Does PM compute the patches in a multi-threaded way? (like 1 thread per label or something like that)
not afaik
Idk if unity would like that
it would be more complicated than just dividing them by labels
Ah it would have to take into account the dependency graph for patches too, might make it a bit complicated (but parallel scheduling of dependent task is an active research field with some nice results)
since patches can depend on each other's stages
yeah
Actually dividing by label would make more sense
As there is no mechanism to transfer information from one label to another
what about things like configs?
those can theoretically be used in multiple labels, right?
Yes theoretically
I havent implemented them yet for that yet
The current system runs each label one after another
Couldn't configs handled by some kind of "pre-processor" before the actrual computing?
Not at the same time
Thats basically how they are handled atm
But unless I do 2 read stages, one for configs and one for the actual patches, there isnt really a way to transfer data between labels
@north mist I need to do a bugfix release of patchmanager as well as test the github action, should I just force merge
https://github.com/KSP2Community/PatchManager/pull/30
merged
woo
wget -qO- https://api.github.com/repos/$GITHUB_REPOSITORY/releases | jq -r '.[0].body' > ./changelog.md
You have to write the changelog into a file like this
- name: Update spacedock
uses: KSP2Community/[email protected]
with:
username: ${{ secrets.SPACEDOCK_USER }}
password: ${{ secrets.SPACEDOCK_PASSWORD }}
game_id: 22407
mod_id: 3482
version: ${{ env.version }}
zipball: ${{ env.zip }}
changelog: ./changelog.md
Then pass it like this
awesome
note that the update spacedock action ... requires jq to already be installed
(The -r here is very important, otherwise spacedock will 500 error)
Do you need to do anything special when using a name selector with a dash? For example, what about the following selector:
:parts #adapter_4v_3v-4v {
This doesn't seem to work, and I suspect the dash between 3v and the second 4v.
you can't have a dash followed by a number
wrap it in quotes
awesome
Time to test it with shoemaker
[PremonitionAssembly("Assembly-CSharp")]
[PremonitionType("KSP.Assets.AssetProvider")]
internal static class AssetProviderPatch
{
[PremonitionMethod("LoadByLabel")]
[PremonitionTrampoline]
[UsedImplicitly]
public static void LoadByLabel<T>(
string label,
Action<T> assetLoadCallback,
Action<IList<T>> resultCallback = null
) where T : UnityObject
{
if (AssetProvider.IsComponent(typeof(T)))
{
Debug.LogError("AssetProvider cannot load components/monobehaviours in batch.");
return;
}
LoadPatchedAssetsAsync(label, assetLoadCallback).Completed += results =>
{
if (results.Status == AsyncOperationStatus.Succeeded)
{
resultCallback?.Invoke(results.Result);
return;
}
Debug.LogError("AssetProvider unable to find assets with label '" + label + "'.");
resultCallback?.Invoke(null);
Addressables.Release((AsyncOperationHandle)results);
};
}
private static AsyncOperationHandle<IList<T>> LoadPatchedAssetsAsync<T>(
string key,
Action<T> assetLoadCallback
) => Locators.LocateAll(key, out var patchedLocations)
? Addressables.LoadAssetsAsync(patchedLocations, assetLoadCallback)
: GameManager.Instance.Assets.LoadAssetsAsync(key, assetLoadCallback);
}
By the way this is the entirety of our preload patching code now
I thought I had [MeansImplicitUse] labels on the attributes
I'll fix that by actual release time
oh wow I love that
what exactly does trampoline mean btw?
is that just for a complete replacement?
Yes
I call it a trampoline because it just replaces the method body with a call to your method
It only involved a descent into madness on my part
I really need to clean it up yet more
But go ... take a look
Premonition.Core is where the magic happens
@north mist https://github.com/KSP2Community/PatchManager/pull/34
A hotfix for a bug that safarte reported
👍
My plans for the next release are nested indexers with implicit dictionary/list creation, and custom "types" that can also have their own operator overloads
The latter is actually such that someone can say ... convert a Vector3 into PM and have it add/subtract correctly with a library
adding member functions to such, may be more of a pain but yeah
because I think I'd want to implicitly add them to the global namespace with the fully qualified type name thingamajiggy
but I suppose I could also just add them to the data structures
@north mist can you confirm CKAN is not showing PM 0.9.3?
we might want to add a loc term for "VAB/Messages/PartNotAvailable" here
it's not in the stock game yet, but it shows up when a missing part cannot be loaded in VAB (which is made possible by Patch Manager)
Good idea
Is it possible to add through PatchManager a new KSPDefinition on an existing partModule?
My need is to add a property IsRelay to Data_Transmitter, so that I can distinguish between antennas & relays.
Technically I can do it anyway adding a new Module, but I'm not sure it's better
not just by using patches
you'd need to Harmony patch the methods where the JSON gets deserialized, and then read that newly added property into some data storage of your own
since the Data_Transmitter class just doesn't have the property, it won't be deserialized automatically
I honestly think that a PM patch that removes all antenna modules from all parts and then adds a custom module would be more suitable for your use
it's the same even if it's a definition? it's not something that should be saved (like the state)
I'll probably just add a new one so
like I said, the class doesn't contain the property
so there's no way for Newtonsoft.Json to somehow save it into an object of the class
Well, here we are, trying to add a new Part Module! Reading through PM wiki & docs has been pretty much exhaustive, plus I have OrbitalSurvey example which is an awesome boost
I was just wondering if this fix commented here is still something needed:
https://github.com/Falki-git/OrbitalSurvey/blob/master/src/OrbitalSurvey/Modules/Data_OrbitalSurvey.cs#L111
It mentions that readonly [KSPDefinition] doesn't work by default with PM, and I think I'll need to set this with PM?
As far as I know, yes, it's still needed, but I haven't checked with the latest patch. You can test is by placing a [KSPDefinition] attribute to a property, set its readonly to true and see how it's created in PAM - if it's a slider or a static value.
My use case was that I wanted certain values that are defined by a part to be displayed as static values (like field of view, min altitude, etc.) but the game kept creating them as sliders that players can change. They were really readonly only one I placed a [KSPState] attribute, but that woule mean that the value is written to the save game file and I didn't want to do that in case I wanted to change those values in another version. [JsonIgnore] was also an option, but that of course can't work with PM that parses jsons.
So technically if you don't want to show the value it's not an issue, right? I'll probably will, just to be sure
If you don't want to show the value then it doesn't need to be a ModuleProperty, so yeah, not an issue then
Thank you @desert stirrup !
I suppose the KSP Patch Manager extension for VSCode is not updated right?
Not entirely...
It needs to be
But since the person who maintains it is barely active, its a lot of effort
Gotcha
would it be possible to make a fork on GitHub like on KSP2Community? Would make it a bit easier to contribute
it definitely would
but Sinon insisted on keeping it on his private Git server for some reason
plus he's the author on the VS Code marketplace
so I don't think we can publish updates without him anyway
this is for sure right
would it be possible in the meantime to keep the syntax highlight while disabling the language server?
Ok, I didn't find a way so I forked the Grammar only, I hope this isn't a problem. I released everything in GPLv3 with clear attribution: https://marketplace.visualstudio.com/items?itemName=Kerbalight.patch-language-grammar
Gotcha
You coulda done MIT for just the grammar, but GPL works here ig
Wait im being dumb am i
I took the original from PatcherLS
Grammar as in the textmate grammar
oh yes
Not the antlr grammar that is pulled from PM
So, I'm trying to add some custom modules, howver I'd like to do this using stages
I'm currently doing it like this:
@use 'relay_mixins';
@use 'constants';
@stage 'CommNext:setup-relays';
:parts #antenna_0v_dish_ra-2 {
@include override-range($commnext-RANGE-RA2);
+Module_NextRelay {
+Data_NextRelay {
}
}
@include add-next-relay-visuals();
}
With the stage defined as
@define-stage "CommNext:setup-relays":
{
@before "falki.orbital_survey";
};
However PM logs say:
line 4:30 extraneous input ';' expecting {'@require', '@stage', '@new', '(', '+', '*', '~', STRING, NAME, STRING_NAME, CLASS, STRING_CLASS, RULESET, ENSURE, STRING_ENSURE, ELEMENT}
[Error :Patch Manager] error parsing CommNext:relay_module.patch - 4:30: extraneous input ';' expecting {'@require', '@stage', '@new', '(', '+', '*', '~', STRING, NAME, STRING_NAME, CLASS, STRING_CLASS, RULESET, ENSURE, STRING_ENSURE, ELEMENT}
line 7:48 mismatched input ';' expecting '}'
[Error :Patch Manager] error parsing CommNext:relay_module.patch - 7:48: mismatched input ';' expecting '}'
line 14:4 extraneous input '@include' expecting {<EOF>, '@use', '@function', '@if', '@mixin', '@while', '@for', '@each', '@require', '@stage', '@define-stage', '@patch', '@new', '@create-config', '@update-config', '(', '+', '*', '~', STRING, NAME, STRING_NAME, CLASS, STRING_CLASS, VARIABLE, RULESET, ENSURE, STRING_ENSURE, ELEMENT}
[Error :Patch Manager] error parsing CommNext:relay_module.patch - 14:4: extraneous input '@include' expecting {<EOF>, '@use', '@function', '@if', '@mixin', '@while', '@for', '@each', '@require', '@stage', '@define-stage', '@patch', '@new', '@create-config', '@update-config', '(', '+', '*', '~', STRING, NAME, STRING_NAME, CLASS, STRING_CLASS, VARIABLE, RULESET, ENSURE, STRING_ENSURE, ELEMENT}
line 14:36 mismatched input ')' expecting {'(', '+', '*', '~', STRING, NAME, STRING_NAME, CLASS, STRING_CLASS, RULESET, ELEMENT}
Could somebody help me understanding the errors?
I tried different combinations but I'm losing my head, plus I didn't find mods with staging in use
(these are the mixins by the way)
don't have a semicolon after the @stage ...
it applies to the selection block, and the semicolon there can be conceptually thought of as separating the two
oh ok
so I need the stage for each selection?
if I need to patch 3 different parts for example
thanks, going to try
oh!
well other than me
I love composability 😄
i forgot I used a few
plus DRY
@mixin scale-curve-time($factor:$atmo-rescale-factor) {
* > fCurve {
m_Curve: $value:map(mult-time-by($factor));
}
}
A mixin I wrote for scaling float curves
Where
@function mult-time-by($factor:$atmo-rescale-factor) {
@return @function($curve-step) {
@return $curve-step:set(time,$curve-step[time] * $factor);
};
}
we should write a kernel in Patch Manager
I mean PM is inspired by functional programming
I love it
oh well, I'd love it more if I could get my patches working correctly, but you know
[Message:Patch Manager] Loading patch CommNext:relay_module.patch
line 6:48 mismatched input ';' expecting '}'
[Error :Patch Manager] error parsing CommNext:relay_module.patch - 6:48: mismatched input ';' expecting '}'
line 13:4 extraneous input '@include' expecting {<EOF>, '@use', '@function', '@if', '@mixin', '@while', '@for', '@each', '@require', '@stage', '@define-stage', '@patch', '@new', '@create-config', '@update-config', '(', '+', '*', '~', STRING, NAME, STRING_NAME, CLASS, STRING_CLASS, VARIABLE, RULESET, ENSURE, STRING_ENSURE, ELEMENT}
[Error :Patch Manager] error parsing CommNext:relay_module.patch - 13:4: extraneous input '@include' expecting {<EOF>, '@use', '@function', '@if', '@mixin', '@while', '@for', '@each', '@require', '@stage', '@define-stage', '@patch', '@new', '@create-config', '@update-config', '(', '+', '*', '~', STRING, NAME, STRING_NAME, CLASS, STRING_CLASS, VARIABLE, RULESET, ENSURE, STRING_ENSURE, ELEMENT}
line 13:36 mismatched input ')' expecting {'(', '+', '*', '~', STRING, NAME, STRING_NAME, CLASS, STRING_CLASS, RULESET, ELEMENT}
I'm definitely doing something wrong here
@use 'relay_mixins';
@use 'constants';
@stage "CommNext:setup-relays"
:parts #antenna_0v_dish_ra-2 {
@include override-range($commnext-RANGE-RA2);
+Module_NextRelay {
+Data_NextRelay {
}
}
@include add-next-relay-visuals();
}
oh uhhh
I forgot to put semicolons after mixins for the grammar for some reason
I'll likely change that
* > atmospherePressureCurve {
@include scale-curve-time()
}
* > BodyAltitudeTemperatureCurve {
@include scale-curve-time()
}
* > BodyAltitudeSurfaceFluxCurve {
@include scale-curve-time()
}
* > BodyAltitudeRelativeHumidityCurve {
@include scale-curve-time()
}
like this I mean
ahn, gotcha
[Error :Patch Manager] Could not run patch: CommNext:stages.patch due to: Object reference not set to an instance of an object
Ok, progress!
that's uhhh huh?
@define-stage "CommNext:setup-relays":
{
@before "falki.orbital_survey";
};
maybe the name?
shouldn't be?
Is there any more of the error?
Run with this version?
that shouldn't matter
oh ok
Here it is the message
Plus now that I'm seeing the docs.. the stage would be executed only if there is OrbitalSurvey installed; I just wanted to order it before, so maybe I'm taking the wrong path
You are misreading the docs I'm pretty sure
the stage will execute before orbital survey if it is installed
but it will always execute
Ha! Ok I misread the "it is ignored" here:
or @before "stage-name"; which forces this stage to run before the defined stage, if said stage is defined, otherwise it is ignored.
So the last sentence is referring to the "@before" condition, not to the stage, correct?
yes
ok, so well that would be exactly what I'd like to have 😄
I really don't get the error here
ah, damned bugs
I forgot to actually uhh parse the @after/@before stuff
@brazen oyster new version should be released asap
give it like a minute or 2
I'll test is asap! Thanks
Ok, version installed! Just a question:
:parts .Module_DataTransmitter.Module_CommandPod
is this correct to choose parts which have both classes?
Add a space
PM differs from (S)CSS where a . splits stuff in those, but PM treats it as part of the full name
so :parts .Module_DataTransmitter .Module_CommandPod
ok!
so instead if I want "any of the two"
that would be :parts .Module_DataTransmitter , .Module_CommandPod
?
:parts (.Module_DataTransmitter, .Module_CommandPod)
gotcha
and when I see something like that (KLSS):
:parts ~#eva_kerbal ~#lab_2v_science_orbital ~#lab_2v_science_marine ~.Module_ResourceCapacities
It's everything that doesn't match any?
Yep
amazing, thanks
let see if 0.9.4 did it!
Worked perfectly! As you can see "Relay" is on the left since it has been loaded before Orbital Survey
I think this is.. the first ordering in KSP2 modding?
Likely
We'll remember this day when @after "falki.orbital_survey:zzzLoading" will come in year 2043

Ok, now I just need to find out why CommunicationRange is not being modified.. damn
:parts #antenna_0v_dish_ra-2 {
Module_DataTransmitter {
Data_Transmitter {
CommunicationRange: $commnext-RANGE-RA2;
}
}
It was too good to be true 😄
Ok, I think a need some help here.. sorry to bother you ;_;
- selectors should be working correctly, since Relay is being added
- I removed any mixin or constant, in order to do a clean test but "Max Range" remains the same
CommunicationRangeis the property I'd like to override; it's aKSPDefinition, I checked and it's the variable used in the OAB Info panel
You've checked parts_data.zip in PM's cache and the range isn't changed? Do the logs say that the patch is applied?
I can't say for sure because honestly a lot of the grammar is still a mystery to me due to the differences between it and SCSS (which I'm just used to more), but I think if you want to split and nest the selectors like this, it should look like:
:parts #antenna_0v_dish_ra-2 {
* > Module_DataTransmitter {
* > Data_Transmitter {
CommunicationRange: $commnext-RANGE-RA2;
}
}
}
That would be more accurate yes
No didn't check, nice
But I am a bit lost about Modules
since in the JSON there are only the serializedPartModules
Like that
or, you can just one-line it like
:parts #antenna_0v_dish_ra-2 > Module_DataTransmitter > Data_Transmitter {
CommunicationRange: $commnext-RANGE-RA2;
}
(I think)
it doesn't perfectly match the JSON structure
it's simplified for parts
so that you only need Module_XYZ to select a module of a part
and then from there you can select the Data_XYZ object
if you wanted to edit the pure JSON, you'd use the :json ruleset
Makes sense, let me double check the PM cache and this "*" trick
but all the customized rulesets like :parts, :resources, and all the other undocumented ones do apply some transformations to make patching easier
ok, in PM cache there is the next relay but CommunicationRange hasn't been modified
let's see with * selector
it worked!
Just to confirm this: both * > are needed
I'm writing it here since I'll forget that for sure
@brazen oyster you are the one maintaining the syntax highlighting now?
I'm about to be making some additions to the syntax to make nested indexers possible, and with variables too (even creating dictionaries/lists when I need to)
I could try to test it with new changes, sure
@north mist thoughts on me removing how indexers currently work, I don't think I see anyone actually using the very convoluted way that they work
by indexers you mean stuff like this?
#selector {
property[0][1]: "value";
}
yeah
They work in a very convoluted way, that makes nesting them impossible
like you can select by class and stuff
Like on parts
... {
serializedPartModules[.Module_Engine]: ...
}
Is possible
But like
holy crap I think its too convoluted for what it should be
Though what would be kind of cool is a
#selector {
property[*][1]: "Value";
}
And that would be very easy to translate between variables and fields
I mean I feel like the other way (using nested set calls) is way more convoluted for the end users
but if you feel like the indexers are bad, then I guess remove them
Noy
you forget what I mean
or rather misunderstand
I meant the way they currently work
I want to simplify them so they work how one would expect naturally, just indexing into the data object
rather than the stupid abstractions I have over them
b/c it makes stuff like nesting impossible with the current system
And I can implement syntactic sugar for map calls for example with this newer system
i.e. this
yeah that would be nice
Yeah, you get what I mean now?
I think I want to add a syntactic sugar for filtering too, idk
$variable[(expresssion)?] *: 5; // Do a selected map
$variable ?: $value > 3; // Select all that is greater than three
something like those 2
but hmmmmm
seems a bit too complex
I'm gonna just stick with the simple map expression
as
BodyAltitudeRelativeHumidityCurve[*][fCurve][m_Curve] *: $atmo-rescale-factor
Is inherently understandable, I think
But rn
I'm trying to think of the logic such that
$x[1][2][3]: 5
Will automatically define $x as a list of lists of lists
mostly so that you can do the following
{
$x[0]: /* Some long expression */;
$x[1]: /* Some long expression */;
$x[2]: /* Some long expression */;
}
If you really need to
@mixin scale-curve-time($factor:$atmo-rescale-factor) {
* > fCurve {
m_Curve[*][time] *: $factor;
}
}
Gonna test in my kerbolar upscale mod by changing the curve scaling mixin to this
What do y'all think
{
"serializedVersion": "3",
"time": 85567.46949355134,
"value": 0.0,
"inSlope": 0.0,
"outSlope": 0.0,
"tangentMode": 0,
"weightedMode": 0,
"inWeight": 0.0,
"outWeight": 0.0
}
With the patch
{
"serializedVersion": "3",
"time": 70000.0,
"value": 0.0,
"inSlope": 0.0,
"outSlope": 0.0,
"tangentMode": 0,
"weightedMode": 0,
"inWeight": 0.0,
"outWeight": 0.0
}
Without
Hey, so I think my new syntax worked :3
nice
yee
Hmm, I think it's quite an inuitive way to do a map selection, right?
yeah, much better than the nested function calls
Yeah, and using functional programming in general for $value:map(...)
it's nice to have the full power of the language available, but it's also nice to have these shorthands
Yeah, and this case is definitely a more common one that needed a shorthand
anyways, let me do some stuff, and update the documentation on indexers
and I shall make a PR for 0.10.0
Stuff being forum actions and discord webhook
sounds good
Writerside apparently supports pdf export now
oh nice
Alright @north mist PR made
I'm also thinking for the future, making a special type called a LazyConfig, which is instead what is returned from get-config that has a :resolve method, but is also automatically called when not in the global context, and being assigned to anything
Just to make configs easier to work with
was this intentional?
it doesn't seem to be used in the modified code
in PartModifiable.cs
@brazen oyster whatever markdown your converter is using doesn't suppport code blocks nested in lists it doesn't seem?
<h2 id="release-v0100">Release v0.10.0</h2>
<p>This release changes how indexers work, it adds support for the following types of indexers</p>
<ol>
<li>Indexers in variable declarations</li>
</ol>
<pre><code>$x[5]: 3;
</code></pre>
<ol start="2">
<li>Nested indexers</li>
</ol>
<pre><code>$x[1][2]: 3;
</code></pre>
<ol start="3">
<li>Mapping indexers</li>
</ol>
<pre><code>$x[*] *: 5; // multiplies all values in $x by 5
</code></pre>
<ol start="4">
<li>Defining new lists and such using indexers</li>
</ol>
<pre><code>$y[0]: 3; // Creates $y as a list with its first element being 3
</code></pre>
<p><a href="https://spacedock.info/mod/3482/Patch%20Manager">Download on SpaceDock</a></p>
This is what it spat out
Release v0.10.0
This release changes how indexers work, it adds support for the following types of indexers
- Indexers in variable declarations
$x[5]: 3;
- Nested indexers
$x[1][2]: 3;
- Mapping indexers
$x[*] *: 5; // multiplies all values in $x by 5
- Defining new lists and such using indexers
$y[0]: 3; // Creates $y as a list with its first element being 3
Test
Like see how discord supports it
that looks fine to me
like it's not great, but it should work
Ahh
yeah
the forum puts classes on codeblocks
Your converter spits them out as unclassed pre blocks
that kinda makes me wonder what all could be put into the HTML there 👀
I really wanna try <marquee>

Dewit
ok I have to say, I didn't even think modern browsers still support it
wow
this brings me back like 15 years
Now I want to see you make a post with it
ngl I would if I weren't too lazy to set it up
just tested, PM breaks both KLSS and CommNext @upbeat hare
Attempting to add a value of type: None and a value of type: List which is not allowed
for both
What
Ah, shit, I think I know where that might be
This is on the part
@north mist
Im gonna tell you the fix
Give me a second
Alright
So the issue is in this function
https://github.com/KSP2Community/PatchManager/blob/20f1224288b1f11fdcac1679d5a480f43c8cd4b0/src/PatchManager.Parts/Modifiables/PartModifiable.cs#L21
Before it says return null
There needs to be a check to see if the field is in the jobject
Something like
if (jObject.ContainsKey(fieldName)) return DataValue.FromJToken(jObject[fieldName]);
Can you add that rq
And force out a release
I assume this should do the job
yeah that's better
Alright, ideas for a 0.11.0 update
Mixin blocks for sure
and a god damn error counter ffs
I hate having to look in the logs to find if an error occured
lmao yes that would be helpful
@north mist PR for you to review
Removed
I think at this point we need to start thinking about what is necessary for a 1.0.0 release
Cuz I think we are getting close to that
Does anyone who uses pm have any gripes or suggestions for stuff that you would want in before a 1.0 release?
I do wish we could somewhat simplify/unify some of the syntax
there are some specific things I was thinking about earlier
I'll need to find it
Gotcha
Oh before 1.0.0 I want to fix the ensure element selector
because rn it acts as
:parts {
@if ($$serializedPartModules:contains("...") {
// Do nothing
} @else {
+... {
// Do stuff
}
}
}
When it should work as
:parts {
@if ($$serializedPartModules:contains("...") {
* > ... {
// Do stuff
}
} @else {
+... {
// Do stuff
}
}
}
Other ideas
I still want a kind of lazy get config that resolves after patches start or something, idk, because the only example of config usage is incorrect, as it reads the configs in the pre-patching period, instead of during the patch
And I suppose maybe some form of "resolve" operator there
one thing that I kinda wish we could get rid of are the compulsory asterisks
I wish that too, but I had parsing issues when trying to not have them
Like I'd love an implicit asterisk before a > when at the start of a selector, but that was aaaaaaaaaaaa
these should ideally be identical
:parts #generator_0v_thermoelectric_radioisotope > Module_Generator > Data_ModuleGenerator {
ResourceSetting[Rate] : 1234;
}
:parts #generator_0v_thermoelectric_radioisotope
> Module_Generator
> Data_ModuleGenerator {
ResourceSetting[Rate] : 1234;
}
}
}
yeah, that's basically how it works in SCSS
I could try to look into it again
well actually, that's not exactly right
SCSS works basically by concatenating selectors
I can't really do that here for many reasons
div {
.my-class {}
}
is equivalent to
div {
& .my-class {}
}
which is just
div .my-class {}
so maybe we could at least use the ampersand to be more consistent
similarly in SCSS you can use
div {
&.my-class {}
}
to say
div.my-class {}
idk, it depends on how far we want get away from CSS
also the second example with no space, wouldn't work as well as that would be parsed as "div.my-class"
not "div"".my-class"
because * only really makes sense as a wildcard, like * div selects all divs that are not the root
Then we do have a semantic difference here
Yeah, no, theres no point of having * act like that
yeah, sure
what I mean is that if we're trying to capitalize on the familiarity of the language, it shouldn't use the same syntax for very different concepts
I mean hmmm, but I was capitalizing on the simplicity rather than the full familiarity.
* makes more sense in the contexts where it is used, and someone who has minimal code knowledge will understand it to mean everything like that
I mean, sure, but in this specific instance, replacing * with & doesn't add any complexity, and adds to the familiarity
idk, I'm not too sure about that
I mean sure, but also consider that * can also just be thought of as the wildcard part of an identifier by itself
recall we have #xyz* and xyz* as both valid IIRC
* has the same meaning as #* basically
but the latter doesn't parse
I'm saying there are other places where * is used
I mean
:parts #generator_0v_thermoelectric_radioisotope {
#* > Module_Generator
#* > Data_ModuleGenerator {
ResourceSetting[Rate] : 1234;
}
}
}
this wouldn't make any sense even if it could parse
Yes it would
:parts #generator_0v_thermoelectric_radioisotope
#"*" > Module_Generator
#"*" > Data_ModuleGenerator {
ResourceSetting[Rate] : 1234;
}
}
}
Try this right now, I assure you it would work
why
how
I think I have a fundamental misunderstanding of how selectors work at all tbh
because in names, * is a wildcard
it's too different things ending in the same result
I'm just trying to show another path to conceptualize what * means here
like seeing that, it basically reads to me like: using the parts ruleset, select the object with the ID/name of "generator_0v_thermoelectric_radioisotope", then select all its children with any name/id, select their direct children of the element/object type "Module_Generator", select all its children with any name/id, and select all their direct children of the element/object type "Data_ModuleGenerator"
it means:
Using the parts ruleset, select all objects that match the name of "generator_0v_thermoelectric_radioisotope" and match any name, then select their direct children that match the element "Module_Generator" and any name, then select their direct children that match the element "Data_Module_Generator"
A space/a new block is an implicit and
lol I think I'm just forever going to struggle with PM
simply for the reason that I've been used to CSS/SCSS for like the past 15 years and now the same syntax and symbols mean completely different things

I understand that it's not always possible to make them match 100% but still
it's quite difficult for me to grasp/get used to
Yeah, that's fair, It's like hearing a language that's very similar to your own but still hard to understand parts of if I had to guess?
well, more like hearing someone speak using words you know, but in (partially) nonsensical sentences
lmao
But anyways, I will try to remove the * needed at the start of stuff
it annoys me too
I'm just worried that the further away we get from the "blueprint" of SCSS, the more confusing it will be to anyone who has any web development (or even USS) knowledge
the hard part is that I have to parse
> x > y > z
as
(* > x) > y > z
And not
* > (x > y > z)
Or something like that
because the latter makes ... no sense
shouldn't the > operator be associative?
Yes, the issue is the associativity when parsing that, thats what caused me to not do it at first
oh btw
:parts {
@if $$crewCapacity > 0 {
* > resourceContainers > .ElectricCharge { @delete; }
}
}
this thing was really weird
that's what I couldn't remember earlier
the dot before the EC selector
Because I made the containers classes contain the container type, which was a poor choice I made early on
It annoys me too
Dw
if I understand the intent of the class selector in PM, usually it should basically just mean ".x = filter the preceeding selector based on whether the element contains x", rather than actually selecting x, right?
Yes basically
I guess the best way to put this though is each selector works on a list of selectables > ... for example takes all the selectables from its righthand side, gets all their children and filters it through ...
So when itd doing * > .ElectricCharge it takes everything in its input list, gets their children and filters all that contain electric charge to the result
But id normally use an element type in this case
I can see where this would be confusing
I should make a writeup about how all the internals actually work
oh by the way, I know we've definitely discussed this before, but what was the reason for changing the "and" syntax from <selector1><selector2> to <selector1> <selector2>?
Cuz i wanted to be able to have names with "." in them
And its easier to read that way
ah yeah, that's what I thought
When I look at a.b.c i see it as one unit, when I see a .b .c i see it as separate
I mean
it kinda is that though
a.b.c is a single element matching all three selectors, a .b .c is a sequence of 3 elements
I suppose
But a lot of the functions like :set are defined as list.set, string.set, dictionary.set
I know you definitely won't like it, but if we wanted to, we could just force names that contain special characters like ~, . and # to be quoted, since that's now a thing in selectors
and we could use the usual syntax
Well ~ and # already require being quoted
then that would make even more sense for .
It would force the need to allow function names to be strings
but the grammars for the selectors themselves, and for the selector bodies should be nearly completely separate, no?
you can't call a function inside a selector, can you?
No, but the tokenization process happens before parsing
is there no way to get around that with modes?
No not easily
The grammar is in 2 files, there is nothing other than tokenization in the lexer grammar, there is no way for it to know if its a selector or a function name
I mean, looking at SCSS, they also use functions with dots:
I mean I can definitely understand not wanting to make major changes to the base syntax at this point
but also I feel like this is the time to do it, if we ever were to
before we put out a stable release
I'm just trying to figure out a justification for it other than its like scss
Because parsing wise stuff will be a bit of a pain
As I said, I shall think on it
my other grievance with PM is the ambiguous @ syntax
sometimes it's used as a decorator/attribute/annotation, and other times it's a statement terminated with ;
I mean that by itself is not the worst thing, SCSS does something similar
it's meant to just reserve keywords without breaking things
but it always at least applies to an explicit scope, like a function definition
I feel like something like this would be a bit clearer/more consistent maybe?
@new ResourceName {
:resources {
// ...
}
}
That doesn't work if it has more than one argument
@new("label","name")
:json {
// ...
}
For example
I kinda feel like that inconsistency makes it even worse
the fact that the "call" is sometimes @new(label, name) and sometimes @new(name)
based on what's inside the "body"
Well in this case :json will always be the first thing
I mean, the call can be anything depending on the ruleset
which I feel like is the issue, considering the ruleset is only specified after the parameters
I would probably prefer something more like @new json(label, name) and @new resources(name)
It's not that bad of a change, but I'm trying to think of how I would implement it
I'm just trying to identify the biggest inconsistencies/pain points from my perspective
but others might not consider those an issue at all
for all I know
we should hold like a "public forum" on the PM syntax
lmao
to get some more opinions
Yeah
especially from people who actually use it
and from some non-experienced users
like on the KSP forums
I have a question
I'm a bit confused about the missions ruleset
looking at this patch
it seems like it expects you can only have one condition of a type as part of a set
how would I select the n-th condition in a set?
You are supposed to use conditonals to figure out the one you want
That selects all property conditions
@north mist my investigation has led me to another few hints for you, i'll write them up later
One thing is how the model is set here
which that model gets passed to viewPrefabAssetKey
which if you go through that route, by postfix patching that method
the colors patch will automatically be applied
but this is only for the space simulation
I need to look at the same but for the OAB
and then if you like trampoline patch or something this method
And this method
to change the target.Name
these methods are the ones you want to replace or patch for switching out the prefab
If you target these places, the colors patch will automatically be applied
Uhh no
Because commas will have to be replaced with semicolons on the first level down, and then a semicolon at the end
If you use a @set-value tho
It should work
ah yeah that's what I forgot
`@new(missions, ${missionData.ID})\n:json {\n@set-value ${data};}`
like so?
Should, let me check
Did you read the messages I sent earlier btw? About the possible target points for prefabs
tbh I just skimmed through it quickly
because I was just trying to focus on getting the editor done today
@set
gotcha
Fair, well I can pin it if you want
Thats the start message
could this also be done with @new(abc) :missions { @set ...; }?
or is the :json ruleset necessary here
Lemme look rq
alrighty
Can you ... indent the output ... please
Lmao yeah
@north mist I have a very stupid idea, what if
string / string was the same as string + "/" + string
Because localization keys/addressables keys tend to follow that format
You've been doing too much JavaScript
Disagree
I haven't touched js in forever
Eh I feel like that's making it a little bit too much of a magic blackbox
Fair enough
@upbeat hare someone sent me these logs on the KLSS forum thread because the loading of their game was stuck and it seems to come from a Patch Manager error, any idea what could cause that?
That error is coming from the place where we edit saved vessels to delete those that have missing parts
Idk what is causing the issue specifically
I don't see what could be causing it aaaaaa
I'd need them to be running a dev version of pm that shows what line of the error
Hmmm, could a patch file validator for github be useful?
@upbeat hare, I'm trying to use a mixin inside a top level each loop, but I'm getting an extraneous input error from patch manager:
line 492:8 extraneous input '@include' expecting {'@use', '@function', '@if', '@mixin', '@while', '@for', '@each', '@require', '@stage', '@define-stage', '@patch', '@new', '@create-config', '@update-config', '}', '(', '+', '*', '~', STRING, NAME, STRING_NAME, CLASS, STRING_CLASS, VARIABLE, RULESET, ENSURE, STRING_ENSURE, ELEMENT}
I can't figure out what's wrong. Looking at other examples of mixins and the docs, this should be valid syntax for it.
The first each keyword is getting an extraneous input error in VSCode, but that's just the syntax grammar not being up to date I think. If I use something else instead of the mixin, it runs fine.
Just that I havent added mixins at a top level yet, semantically that feels a bit odd to me
Will you add them?
I'll have to think on it
@mixin hmmm() {
x: 5;
}
What does this mean in a top level context though?
I don't know. I'm still grasping how PM works.
For mixins, I understood that they give a way to reuse other parts of codes, or in my case: I have a complex set of commands and all I want is to move them from this part. Same as in c# - I'd separate a part of code to a different method. Even if I want to use that method only once, it gives a bit cleaner way to write it. Would mixins be suited for this?
My full code will be creating a new mission object/asset/however we call it 🙂
Hmmm
At the top level I think I'd rather use functions for this
That's not possible yet though
What's the key difference between mixins and functions?
Mixins work inside the environment they are included in, and act as a list of "selection actions", and take in the context of the selection block they are in
Functions work inside the environment they are defined, and act as a list of "statements", and dont require a selection block context
Ok, for now I'll place my gigiantic block of statements inside that inner each loop. But it'd be nice to have separate it in a new function or mixin for better readability. And if in the future there's a need to repeat the gigantic block that creates objects, it would be even more valuable, so here's my vote to add this.
@upbeat hare I removed the custom domain in the docs repo if that's ok, it's better to have an ugly URL (https://ksp2community.github.io/PatchManagerDocs/) than have the docs completely inaccessible
