#Flight Plan

1 messages · Page 3 of 1

grizzled vale
#

the project is merely "prepared" for it by having the correct font fallbacks

wind mica
#

OK then, I'll just focus on making sure normal operations are working.

grizzled vale
#

I think I'll probably wait with adding the localization until I have a chance to update UITK to support previewing localized terms inside Unity

#

so that you can make sure everything looks ok in all languages

wind mica
#

GitHub desktop is a bit confused. I switched my branch from master to Dev and did a Fetch and now it thinks I've got 8258 changed files - looks like all additions. I assume what this means is that in my local folder I've got a fetch of the new Dev on top of and old master and so there are 8258 things that left over from the old master that are presumably not needed now.

#

Is there an easy way to make it get rid of all that so I can just build?

grizzled vale
#

it looks to mostly be the build files from the previous version which are no longer ignored, because the template has a completely different structure for build folders

wind mica
#

Not entirely, there are other things like this too

#

And a ton of UI stuff that must have been moved

grizzled vale
#

well, yeah, those are also files that are not ignored by the template

#

I would advise just backing this folder up somewhere into a zip or something, just so you have it if you need it, and cloning the fresh project from GitHub

wind mica
#

The folder looks like this

wind mica
#

And since your advice is arriving from the future, I must respect it!

grizzled vale
#

that it is 😆

wind mica
#

I may have done the cloning part wrong. When I did it, it cloned the master branch and when I switched to the Dev branch it thinks I need some massive PR - presumably the difference between the two.

wind mica
grizzled vale
#

the app is probably just stupid

#

you should be able to switch from master to Dev after cloning with no issues

wind mica
#

The first time I did the clone I was able to switch, but switching made it think there would be some sort of massive PR

grizzled vale
#

did it look like this?

#

if there were 0 changed files in the left pane, then that's how it's supposed to be

wind mica
grizzled vale
#

the pull request blue box is just suggesting that you can make a PR from dev to master

#

which you only need to do if you want to make a new release

wind mica
#

Oh I see! OK, I'll take a shot and building and testing this.

grizzled vale
#

oh yeah one more thing

#

you probably haven't made any new projects with the later template versions right?

#

you'll probably need to set up the KSP2DIR environment variable

#

the setup script for a new project does it automatically, but since you're not making a new project, you'll need to do it manually

wind mica
#

I did some stuff with CF, but I don't think I set up a KSP2DIR environment variable

grizzled vale
#

you can quickly check

#

just type something like "variable" into the Windows search box

#

the correct setting should pop up

grizzled vale
#

yep, so, create a new one like this

#

in the user variables

#

with the path to your KSP2 debug folder

#

I think you had a separate one, right?

wind mica
#

Done, I think

grizzled vale
#

alright, that should be all

#

now you should be able to just open the solution in Visual Studio, switch configuration to DeployAndRun, rebuild the solution, and it should automatically start the game with the new mod version loaded

wind mica
#

Looks like it built

#

Does building with this template automatically put it in my game at teh KSP2DIR folder?

#

Or do I need to install it after building?

grizzled vale
#

only in the Deploy and DeployAndRun configurations

#

Debug just compiles a debug build and places it into the dist folder, Release compiles a release build and packs it up into a zip in the dist folder, Deploy compiles a debug build into the dist folder, deletes the old version from your game and copies the new version into its place, and DeployAndRun does the same thing as Deploy, plus it runs the game

wind mica
#

Oh nice! So DeployAndRun to make life easy testing a debug version, and Release to prepare something for upload to GH and SpaceDock then

grizzled vale
#

yep

#

and speaking of Release, all of that is now automated

#

so you don't need to build a release and upload it anywhere

#

it all happens in the cloud using GitHub actions

#

for both GitHub releases and SpaceDock

#

you'll just need to do a tiny bit of setup first to add support for SpaceDock

wind mica
#

Something is amiss. It's running the game, but it's runing a completely unmodded version of the game

grizzled vale
#

that is definitely weird

wind mica
#

I'm fairly sure I pointed that environment variable at my highly modded debug version of the game

grizzled vale
#

oh wait, did you already have VS open when you added the variable?

wind mica
#

Do I need to reboot or something because of the environment variable?

grizzled vale
#

it can only use it after you restart VS

wind mica
#

Huh, so it somehow found my steam install!

grizzled vale
#

this is set as the default

#

so if your Steam install is there and it can't find the environment variable, that's where it gets copied

wind mica
#

Yeah, that's probably where my steam install is...

#

Shit. It's still fucked up.

#

I closed VS all the way down and then relaunched it and the GD thing still ran my steam game

grizzled vale
#

then I would try rebooting the computer, just in case

#

but it shouldn't be causing issues

wind mica
#

Screw it. brb

grizzled vale
#

one more potential cause I can think of is if you accidentally closed the environment variables window without saving it (aka clicking OK)

grizzled vale
#

if you have any other issues or questions, feel free to ask, I'll respond in the morning

wind mica
#

Success with building and launching!

#

I'll play around with it now.

#

Here's an issue. On the Resonant Orbit Maneuvers tab, if you click the + or - buttons, it should just add or subtract 1 from the number of payloads or the number of deploy orbits. Instead I'm getting this odd text.

#

The Payloads increment buttons work OK, it's just the Deploy Orbits buttons that are misbehaving.

#

Also on that same tab, the Atm and Vac are pre-filling with "filler text". Should be defaulting to 0.75 and 0.9 respectively.

#

You can manually enter those numbers, but they should be there by default.

#

I have no idea what's going on with New Pe, or even if it might be related to anything in the Dev branch, but this is certainly wrong.

#

OK, I've got a theory what was happening there, but I suspect FP may have had this problem separately from your updates. The first time I tried setting the Pe to 100 I think I had a bad Burn Option set and got a 0 dV maneuver. I changed that, but kept getting the 0 dV manuever. Once I changed the New Pe value to something else (400 as it happens), then it worked fine. My theory is that something is gettign FP or Node Manager or something into a state where you've got stale data from a bad node and if you keep asking for the same thing, you just keep getting the stale data.

#

Asking for 400, and then going back to 100 gives a reasonable result for the 100 Pe solution

#

So there's some issue here, but I honestly don't think this one has anything to do with your efforts.

#

I love love love the new orbit colors!

#

I do not see what's wrong here:

    private void IncrementPayloads(int increment)
    {
        if (NumSats + increment > 1) NumSats += increment;
        NumPayloads.text = NumSats.ToString();

        updateResonance();
        FlightPlanPlugin.Logger.LogInfo($"IncrementPayloads: {NumSats}");
    }

    private void IncrementOrbits(int increment)
    {
        if (NumOrb + increment > 0) NumOrb += increment;
        NumOrbits.text = NumOrbits.ToString();

        updateResonance();
        FlightPlanPlugin.Logger.LogInfo($"IncrementOrbits: {NumOrb}");
    }
#

It seems clear that clicking on the +/- buttons will call this here:

        IncreaseOrbitsButton.clicked += () => IncrementOrbits(+1);
        DecreaseOrbitsButton.clicked += () => IncrementOrbits(-1);
#

Why on earth would that put anything other than an integer in the display?

grizzled vale
wind mica
#

Oh, duh!

#

Of course

grizzled vale
#

to avoid confusing similar variables like this in the future, I would definitely recommend more clear naming, like "NumOrbitsLabel" instead of "NumOrbits"

wind mica
#

Yep, that would have been more clear.

grizzled vale
#

as for "filler text", you've had that in a couple of places in your UXML

#

all that should be needed to do is get rid of the "text" property and instead set "value" to the desired number

#

which reminds me of another thing that I added to the template - when you're in Unity and you click Build AssetBundles in the Assets menu, they now get automatically copied to your plugin_template folder, so you don't have to go around manually copying anything

#

you can just click Build AssetBundles in Unity, and then immediately rebuild the solution in VS and everything will be deployed to the game correctly

wind mica
wind mica
#

I can give this a shot and see if anything breaks

grizzled vale
#

In the worst case scenario, you can use both, if just value alone doesn't work

wind mica
#

True. that should be safe

#

The code fix on the button is working fine. Now I just need to rebuild the bundle so the filler text can be sorted.

wind mica
#

Nope, that didn't work...

#

Pointing Unity Hub at either of those folders does not give the result I was hoping for

grizzled vale
#

There's a good reason for it! The nested folder is the one that contains the Unity project itself, and the outer folder with the same name contains a C# project file that gets compiled along with the main solution, which compiles code from inside the Unity project

grizzled vale
#

It does for me

grizzled vale
wind mica
#

I get this:

grizzled vale
#

Putting the .csproj file inside the inner folder wouldn't work, because Unity generates its own project files

grizzled vale
#

No errors

#

And that one warning is expected

#

Just switch to the Project tab

wind mica
#

Oh, I was expecting it to open with a view of my UI. That's how I always saw it. Must be n opening the first time kind of thing

grizzled vale
#

Yeah I think it just doesn't know which scene it should open by default

#

There should be a TestScene in assets that you can double click to open

#

And then that should become the default on subsequent launches of Unity

wind mica
#

Still not seeing what I hope to see. I must be forgetting what I need to do to get to the view I want

#

There's some step where you need to open something inside the project to get this view...

#

OK I found it, but dang is it goofed up by default

#

I think what I need to do is spend some time getting the various things arranged and docked the way I want them, then I can probably save the project and it will come back the way I expect it to.

grizzled vale
#

If you want to be able to easily reuse layout for different projects, then you should definitely save it

wind mica
#

Can I save the layout I want from MNC and then import that into this one?

grizzled vale
#

In the top right of Unity, there's an option to either switch layouts, or to save a custom one

wind mica
#

Because that one should be exactly as I want it

grizzled vale
#

Then you can use it anywhere

wind mica
#

Well rebuilding the assets worked perfectly (as advertised!)

#

Here I kept both text and value just to be on the safe side

#

Oh this is wild! I apparently had save the layout I wanted! I found this already there

#

Problem solved!

grizzled vale
#

nice

wind mica
#

Well, nearly solved. The Viewpoint was smushed in the vertical, so I guess the layout I saved didn't specify that setting or specified it wrong, but it seems to have salved pretty much all the other issues I had with the layout

#

I'm sure I can sort that one out. This is awesome!

#

Thank you Soooo much for all your work dragging FP into the new template!

#

I'm certain this will be making my life easier in lots of ways

grizzled vale
#

I definitely hope so, that's my main goal with all these template updates!

wind mica
#

Fit Canvas solved my smushed viewpoint!

#

A one-click solution! That's my style!

#

Well, sort of... I may have a little more work here - but nothing big.

grizzled vale
#

well then, after I'm done with my last exam on Saturday, I could do this same process for MNC if you want

wind mica
grizzled vale
# wind mica

you should be able to just drag the bottom right corner to make the canvas larger (it only affects the preview, nothing else)

wind mica
#

I feel like there's something possibly set wrong here, but when I built assets and then rebuilt in VS (amazing!) it worked fine in the game. I'd just like the Unity project to really show me what I should expect in the game.

wind mica
grizzled vale
#

yeah, when you click on the header, you should be able to manually edit the size in the inspector on the right

wind mica
#

Yeah, that's it!

#

I wonder why Fit Canvas doesn't work? Maybe that's just a Unity thing. You'd think it would be able to work out what the minimum height is based on the height of all the stuff that's visible

#

Using that it always goes to 924 px height

#

It seems I need something more like 1000 or 1100

grizzled vale
#

I think that it might be some sort of an issue with the FP styles

#

for example, when you look at the buttons here, it seems to think that the largest button is the one on the left with the text, and positions everything around it accordingly

#

oh and it also seems like you don't have KerbalUI set as the preview stylesheet?

wind mica
#

Yeah! That button should have a fixed height. There are some other similar issues, but this is a good example

#

I bet I've got a little style cleanup I should do here

grizzled vale
wind mica
#

That does seem to help. Poking around with the height it seems that any value north of 975 gives me essentially the same result for the visible parts. Any value above this gives me more canvas, but not taller stuff

#

Of course, the FP UI has a variable height depending on the tab, so this is just what Interplanetary Transfer needs.

#

I need to get going for work. Good luck on your exams! I doubt that you'll need luck though. I hope you ace them!

grizzled vale
#

Thanks 😆 I hope so too, though the odds are not great

grizzled vale
#

@wind mica can I suggest updating the Flight Plan readme? it's quite outdated by now

#

oh by the way, did you use the automated GitHub actions for the GitHub and SpaceDock uploads?

#

those are new in the new template

wind mica
# grizzled vale

Yeah, both this and the SpaceDock page need some attention. I'll work on that.

wind mica
grizzled vale
#

basically, when you go to Releases on GitHub and create a new release, don't upload any zip file

#

just write the text and publish it

#

the action will automatically build the mod in the cloud and attach the zip to the release

wind mica
#

Dang, I had no idea that was even possible

grizzled vale
#

so like this:

wind mica
#

We should do this for MNC and NM for sure!

grizzled vale
#

it will use the code from the specified Target at the top

#

so you just have to make sure that the main/master branch contains the code you want to release

wind mica
#

Nice!

#

I'll give this a try with the next release

grizzled vale
wind mica
#

Hmm... GitHub preview isn't showing the banner image

grizzled vale
#

oh yes, it's because I put the image files into the "media" folder in the new project

#

instead of "Images"

#

I can make a quick PR to Dev to fix it if you want

wind mica
#

OK, I'll fix the readme - not a big deal and I'd like to conform to the mod template

#

For installation I added this

#

Perhaps a link to CKAN could be added?

grizzled vale
#

Yeah, that's a good idea

#

I did that in the MNC Readme that I'm editing now

wind mica
#

Excellent! Thanks!

wind mica
# grizzled vale I did that in the MNC Readme that I'm editing now

OK, I've updated the readme - although I'll bet the guidance at the end for hardcoding and softcoding dependencies is probably a bit out of date. All the images link, and for the most part it's OK now. I'll work on what on SpaceDock, and I think I need to update some graphics in the media folder - but as the images link to the right places that will be a simple thing.

#

I commited my changes direct to the master since it's the readme and it needs to work there.

grizzled vale
#

yeah, it's fine when it's just the README

#

I do it too

wind mica
#

vs this

grizzled vale
#

yeah, that was an intentional change, since many people complained about this being a bug in UITK

wind mica
#

lol

#

Well, there's a use case where it would be helpful to only hide the stock UI and not mods. I can always control what mods are in view.

grizzled vale
#

but yes, it is possible to specifically leave out your window when hiding everything else

#

though beware that you'll probably get users complaining about the "bug"

#

😆

wind mica
#

Could there be both options? I can see use cases for both. So: Normal (it's all visible), Mods Only, and Clean?

#

Then there's no bug, just pick the one you want

grizzled vale
#

I personally can't see the use case for it for normal users

#

so I don't know how I feel about adding something like that

#

you could make it a setting for your mods though

wind mica
#

I can? That would be interesting. I might do that for debug builds so that users don't generally encounter it.

safe nimbus
#

I used it once or twice to hide everything except my window when taking screenshots

wind mica
#

Damn! Of course!

#

Doh!

safe nimbus
#

That and, well, Photoshop 😉

wind mica
#

I'll give IWTMUIC a shot

safe nimbus
#

Black sky is easy to photoshop

wind mica
#

True, but using your mod is probably cleaner andeasier.

wind mica
wind mica
#

Updated the graphics and readme on GitHub

#

Updated the banner on SpaceDock, but those graphics are a PITA to update

wind mica
#

Update graphics and text on SpaceDock

#

Updated graphics on Forum! Whew... That will keep this up to date for a while I hope. Of course, once @grizzled vale does the localization I'll may have to do some of this again...

gaunt fjord
#

Just in time for the KSP2 update coming this Tuesday

wind mica
#

I've got a new theory for what may be causing the misbehavior in my interplanetary transfer. There are not a lot of differences between my code what's in MechJeb, but there is a difference in how OrbitFromStateVectors is done, and that method gets called from DeltaVAndTimeForInterplanetaryTransferEjection.

#

The OrbitFromStateVectors lives in Node Manager, and going back over the code I see the translation from KSP1 to KSP2 was bumpy for this one. It's suspicious for that reason and because it's ued in Flight Plan to compute a sampleEjectionOrbit, which ultimately gives a turningAngle that leads to the ejectionTrueAnomalyRad. That value determines the burnUT - and one thing that I've noticed is that the burn times seem to be off the further in the future the node is.

#

The old MJ code for this function is this

        public static Orbit OrbitFromStateVectors(Vector3d pos, Vector3d vel, CelestialBody body, double UT)
        {
            var ret = new Orbit();
            ret.UpdateFromStateVectors((pos - body.position).xzy, vel.xzy, body, UT);
            if (double.IsNaN(ret.argumentOfPeriapsis))
            {
                Vector3d vectorToAN = Quaternion.AngleAxis(-(float)ret.LAN, Planetarium.up) * Planetarium.right;
                Vector3d vectorToPe = ret.eccVec.xzy;
                double cosArgumentOfPeriapsis = Vector3d.Dot(vectorToAN, vectorToPe) / (vectorToAN.magnitude * vectorToPe.magnitude);
                //Squad's UpdateFromStateVectors is missing these checks, which are needed due to finite precision arithmetic:
                if (cosArgumentOfPeriapsis > 1)
                {
                    ret.argumentOfPeriapsis = 0;
                }
                else if (cosArgumentOfPeriapsis < -1)
                {
                    ret.argumentOfPeriapsis = 180;
                }
                else
                {
                    ret.argumentOfPeriapsis = Math.Acos(cosArgumentOfPeriapsis);
                }
            }

            return ret;
        }```
#

And the code I derrived from that is this hot mess

public static PatchedConicsOrbit OrbitFromStateVectors(Vector3d pos, Vector3d vel, ICoordinateSystem coordinateSystem, CelestialBodyComponent body, double UT)
{
    PatchedConicsOrbit ret = new PatchedConicsOrbit(Game.UniverseModel);
    // Create the type Position and Velocty inputs needed for KSP2's UpdateFromStateVectors
    Position position = new(body.SimulationObject.transform.celestialFrame, (pos - body.Position.localPosition).SwapYAndZ); // OrbitExtensions.SwapYZ(pos - body.Position.localPosition)
    Velocity velocity = new(body.SimulationObject.transform.celestialFrame.motionFrame, vel.SwapYAndZ); // OrbitExtensions.SwapYZ(vel)

    ret.UpdateFromStateVectors(position, velocity, body, UT);
    if (double.IsNaN(ret.argumentOfPeriapsis))
    {
        Vector3d vectorToAN = Quaternion.AngleAxis(-(float)ret.longitudeOfAscendingNode, body.Orbit.ReferenceFrame.up.vector) * body.Orbit.ReferenceFrame.right.vector;
        Vector3d vectorToPe = ret.eccVec.SwapYAndZ; //  OrbitExtensions.SwapYZ(ret.eccVec);
        double cosArgumentOfPeriapsis = Vector3d.Dot(vectorToAN, vectorToPe) / (vectorToAN.magnitude * vectorToPe.magnitude);
        //Squad's UpdateFromStateVectors is missing these checks, which are needed due to finite precision arithmetic:
        if (cosArgumentOfPeriapsis > 1)
        {
            ret.argumentOfPeriapsis = 0;
        }
        else if (cosArgumentOfPeriapsis < -1)
        {
            ret.argumentOfPeriapsis = 180;
        }
        else
        {
            ret.argumentOfPeriapsis = Math.Acos(cosArgumentOfPeriapsis);
        }
    }

    return ret;
}
#

I left some breadcrumbs for myself with these notes

        // was: body.Position ->  body.Position.localPosition
        // was: ret.LAN -> longitudeOfAscendingNode
        // was: Planetarium.up ->  body.orbit.ReferenceFrame.up.vector
        // was: Planetarium.right -> body.orbit.ReferenceFrame.right.vector
        // OrbitFromStateVectors calls the KSP2 method UpdateFromStateVectors. The KSP1 version took pos and vel as Vector3d, but the
        // KSP2 version requires these to be type Position and Velocity.
        // pos = o.SwappedAbsolutePositionAtUT(UT);
        // vel = o.SwappedOrbitalVelocityAtUT(UT) + dV;
        // The MJ version of OrbitFromStateVectors peroforms a SwapYZ on (pos - body Position), and a SwapYZ on vel before passing them into
        // the KSP1 version of UpdateFromStateVectors.
        // ret.UpdateFromStateVectors(OrbitExtensions.SwapYZ(pos - body.Position), OrbitExtensions.SwapYZ(vel), body, UT);
#

The comments show my guesses/assumption/deductions - and they could be wrong

#

I see that I also had some test code in there that'd I'd commented out

            // Position Position = new(body.SimulationObject.transform.celestialFrame, pos);
            // Velocity velocity = new(body.SimulationObject.transform.celestialFrame.motionFrame, vel);

            // ret.UpdateFromStateVectors(OrbitExtensions.SwapYZ(pos - body.Position), OrbitExtensions.SwapYZ(vel), body, UT);
            // orbit.UpdateFromStateVectors(new Position(o.ReferenceBody.SimulationObject.transform.celestialFrame, Position), new Velocity(o.ReferenceBody.SimulationObject.transform.celestialFrame.motionFrame, velocity), o.ReferenceBody, UT);
west slate
#

Just following the code seems everything aligned, the only place some issue could arise (in my ignorance) is the celestialFrame

wind mica
#

@grizzled vale I've noticed that changing mod settings (such as toggling experimental features on and off) has no effect post launch of game. Even an F5/F9 will not apply the effect. I thought I had that setup so that changes would take immediate effect. Has something changed in how these things are loaded? The problem is most likely on my end, but it's weird that even and F5/F9 won't apply the changed settings. It's like the settings are somehow cached and changes are only possible if you fully quit and then relaunch the game.

grizzled vale
#

Nothing has changed, so there's most likely something wrong in how you're handling it

#

(to be blunt, sorry 😅)

wind mica
#

Not terribly surprising.

#

One more thing to try to fix then in 0.10.1!

#

Right now, In my effort to try to solve moon return and interplanetary transfer I've managed to really hose calculation of the transfer window phase angle. I know that was working before... Now I get this for Duna.

#

Which is absolute shite. Should be 44-ish

#

This is interesting...

#

As is this

#

Picking different targets gives me different phase angles to the target (good...), but in each case the transfer window reported is the same (not so good... really very very bad)

#

The transfer time looks OK, so the hypothetical hohmann transfer orbit is presumably OK. The synodic period is also the same in all cases though.

#
    private double TransferCalc(PatchedConicsOrbit targetOrbit, double UT, out double synodicPeriod, out double timeToClosestApproach,
        out double closestApproach, out double relVelocityNow, out double relVelocityCA, out double relativeInc, out double phase,
        out double transfer, out double _transferTime)
    {
        double nextWindow;
        synodicPeriod = Orbit.SynodicPeriod(targetOrbit);
        timeToClosestApproach = Orbit.NextClosestApproachTime(targetOrbit, UT + 1);
        closestApproach = Orbit.RelativeDistance(targetOrbit, timeToClosestApproach);
        // relVelocityNow = Orbit.RelativeSpeed(targetOrbit, UT);
        relVelocityCA = Orbit.RelativeSpeed(targetOrbit, timeToClosestApproach);
        relVelocityNow = Vector3d.Dot(Orbit.WorldOrbitalVelocityAtUT(UT) - targetOrbit.WorldOrbitalVelocityAtUT(UT), Orbit.WorldBCIPositionAtUT(UT) - targetOrbit.WorldBCIPositionAtUT(UT)) / (Orbit.WorldBCIPositionAtUT(UT) - targetOrbit.WorldBCIPositionAtUT(UT)).magnitude;
        relativeInc = Orbit.RelativeInclination(targetOrbit);
        phase = Orbit.PhaseAngle(targetOrbit, UT);
        transfer = Orbit.Transfer(targetOrbit, out _transferTime);
        if (transfer < phase)
            nextWindow = synodicPeriod * MuUtils.ClampDegrees360(phase - transfer) / 360;
        else
            nextWindow = synodicPeriod * MuUtils.ClampDegrees360(transfer - phase) / 360;
        return nextWindow;
    }```
#

This looks OK...

#

If targetOrbit were goofed up (I don't think it is), then that would certainly screw up synodicPeriod, but it should also prevent _transferTime from being OK since that depends on targetOrbit

#

SynodicPeriod is just this, which hasn't changed.

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static double SynodicPeriod(this PatchedConicsOrbit a, PatchedConicsOrbit b)
        {
            int num = ((Vector3d.Dot(a.OrbitNormal(), b.OrbitNormal()) > 0.0) ? 1 : (-1));
            return Math.Abs(1.0 / (1.0 / a.period - (double)num * 1.0 / b.period));
        }```
#

Although I was playing around with the calculations for OrbitNormal, but I've backed out all those changes here:

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector3d OrbitNormal(this PatchedConicsOrbit o) // KS2: OrbitNormal // was: SwappedOrbitNormal
        {
            // return -o.GetOrbitNormal().xzy.normalized;
            Vector3d thisVec = -o.GetRelativeOrbitNormal().SwapYAndZ.normalized;
            Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, -o.GetRelativeOrbitNormal().SwapYAndZ).normalized; // From KS2
            if (thisVec != thisVec2)
            {
                Debug.Log($"OrbitNormal(1): thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                Debug.Log($"OrbitNormal(1): thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
            }
            // return thisVec2;
            return o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, -o.GetRelativeOrbitNormal().SwapYAndZ).normalized; // From KS2
        }```
#

Previously, this was just

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector3d OrbitNormal(this PatchedConicsOrbit o) // KS2: OrbitNormal // was: SwappedOrbitNormal
        {
            // return -o.GetOrbitNormal().xzy.normalized;
            return o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, -o.GetRelativeOrbitNormal().SwapYAndZ).normalized; // From KS2
        }```
#

And when testing these two approaches for computing the orbit normal in every case I tested they gave the same result either way.

#

Also, the PhaseAngle to the target looks OK, and is at least does change from target to target, and it too uses OrbitNormal

        public static double PhaseAngle(this PatchedConicsOrbit a, PatchedConicsOrbit b, double UT)
        {
            Vector3d vector3d = a.OrbitNormal();
            Vector3d vector3d2 = a.WorldBCIPositionAtUT(UT);
            Vector3d vector3d3 = Vector3d.Exclude(vector3d, b.WorldBCIPositionAtUT(UT));
            double num = Vector3d.Angle(vector3d2, vector3d3);
            if (Vector3d.Dot(Vector3d.Cross(vector3d, vector3d2), vector3d3) < 0.0)
            {
                num = 360.0 - num;
            }

            return num;
        }```
#

I've similarly played around with WorldBCIPositionAtUT, but also backed those changes out

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector3d WorldBCIPositionAtUT(this PatchedConicsOrbit o, double UT) // KS2: RelativePosition // was: SwappedRelativePositionAtUT
        {
            // return o.getRelativePositionAtUT(UT).xzy;
            Vector3d thisVec = o.GetRelativePositionAtUT(UT);
            Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetRelativePositionAtUTZup(UT).SwapYAndZ); // From KS2
            if (thisVec != thisVec2)
            {
                Debug.Log($"WorldBCIPositionAtUT: at {UT} thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                Debug.Log($"WorldBCIPositionAtUT: at {UT} thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
            }
            // return thisVec2;
            return o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetRelativePositionAtUTZup(UT).SwapYAndZ); // From KS2
        }```
#

And also that one gives the same results regardless of which approach I take (though you may notice I needed to remove the .SwapYAndZ from the calculation for thisVec where the old MJ code had a .xzy. That shouldn't matter since I'm using the KS2 approach and have been for many months.

remote laurel
#

Hi,

Added fonts to the asset bundle in preparation for localization work - this makes the size of the download much bigger, but does not affect performance in the game otherwise and will enable localized versions of FP in the future.
I was wondering why you weren't packaging all those already into an external library-like-plugin which could be shared with others ?

grizzled vale
#

it has custom fonts, and those need to have the fallback fonts set up separately

#

and Unity doesn't allow you to specify that you want to reference an existing asset from a different project (like the fallback fonts from the UITK for KSP2 package) without also copying them inside the current project's bundles

#

essentially we're hitting the limitations of Unity where from its point of view, it's like we're trying to create multiple different games, where they all reference assets from one central game

#

and that is just not possible without having the assets copied into each individual "game"

#

for the default fonts I provide in UITK for KSP2, there's a workaround - the fonts are assigned to USS variables, and through that abstraction, they are "hidden" from the bundling process

#

so when a mod uses any of the font variables, the font assets don't get copied

#

but, Flight Plan and Maneuver Node Controller use custom fonts, and since the fallback fonts have to be set directly as references in the font assets (as opposed to actually using fonts, which is done in USS and can be done with variables), it's impossible to do the same thing here

#

unless I were to include schlosrat's custom fonts in the main UITK for KSP2 library

#

but it doesn't really make sense that a general library that everyone uses would include assets for specific mods

#

another alternative would be to only set the fallback fonts at runtime, but it would mean that previewing for example how a Chinese UI would look in Unity's UI Builder would be impossible

remote laurel
#

...or through an sort-of UI emulator in charge of simple displaying. Anyway the binding should be limited to few fonts definition, no?

grizzled vale
#

Currently there are three fallback fonts, one for Chinese, one for Japanese, one for Korean

#

Together they are around 45 MB

#

So that's the size increase for these mods with custom fonts if they want to make these languages usable

#

Not sure what to imagine under "UI emulator"

#

That's basically what the UI Builder (in its Preview mode) is

remote laurel
#

I'm in fact not very familiar with Unity dev, but I was used to UI library in old days.

#

But, would it be the same if KSP2 was referencing itself these extra font (in a latter more eloborated/localized release)?

grizzled vale
#

We're using UI Toolkit, it's Unity's newest UI framework

#

While KSP2 itself uses the old framework, Unity UI

#

And the two are mostly completely separate and incompatible

#

If we could use KSP2's existing fonts, we absolutely would, it would make things much easier for us

#

However, the Unity UI system uses TextMeshPro font assets, and UI Toolkit uses TextCore font assets

#

And these are also incompatible

remote laurel
#

I see

grizzled vale
#

So even though we can retrieve the game's fonts at runtime, we can't do anything with them

remote laurel
#

I was having a look at the latest related UitkForKsp2 commits and saw how the ui:label in the TestDocument.uxml was refering -unity-font-definition. Couldn't these url be more dynamic or refering a shared asset?

grizzled vale
#

sadly, no, the issue is that the UXML and USS files get compiled when being bundled, including the paths, which are transformed to (most likely) reference the file IDs in the bundle

#

there's no way to explicitly reference paths from outside the current project

remote laurel
#

Ok. And we (mostly you in fact) don't want to rebuild a full font server. That's fair

grizzled vale
#

yeah, that would be a lot of effort both inside Unity and in the game, and would be probably quite hard to maintain

#

I would basically have to reimplement many of the core functionalities of the whole UI framework to achieve that

#

however, what can be done relatively easily would be schlosrat making a separate mod that would act as a UI library for his other mods, which would be the only place where the font assets are defined, and then he could create USS variables for them and use them in his projects

#

though I'm not sure if it's worth doing all that to serve fonts for 2 mods

#

basically, at most it would save the user 45 MB if they use both Flight Plan and Maneuver Node Controller

remote laurel
#

That would be definitely a must. As soon as you have tested one of them, you're quickly in the need of both

#

The 3rd one being K2-D2

west slate
#

I'm curious, is there any strong opinion on the font used? Cause I think it would be nice to use all the same font

#

Aka: is there a reason why in Flight Plan you wanted a different font? There could be a perfectly reasonable reason, I'm just wondering

grizzled vale
#

my guess would be to make the UI more compact

#

the monospaced font we use by default takes up quite a bit more space

west slate
#

I'd be curious to see if through some clever styling it could be possible to achieve same compactness but with the UITK look & feel

grizzled vale
#

for example this is MNC with the default UITK for KSP2 font

#

compared to the custom font

#

this is with 1px smaller font and with some negative letter spacing

west slate
#

I love the last one

#

with the default background color could be a bit easier on eyes too

grizzled vale
#

yeah I do agree that the background and foreground could have a bit less contrast

#

it makes me squint to read the text

west slate
#

Plus m/s could be written with ㎧

#

(not sure if the font supports it however)

#

but not super important

grizzled vale
safe nimbus
#

So, I want to change my inclination to 90°. There's no good option currently in Flight Plan to do that. Best option in this case would be "at the Apoapsis". Maybe adding that option would be good?

grizzled vale
#

what would the new option be?

#

I can already see all the options I can think of in that menu

#

oh right I can't read lol

#

apoapsis and periapsis

#

makes sense

#

disregard 😆

wind mica
#

So, if I understand, your point is that when changing from 0 to 90 it may be desired to do this at Ap?

#

For anything else it will always be cheaper at AN or DN, though I suppose you may not care about cheaper in some situations

#

Ultimately, the answer is that I can very easily add other burn time options to any particular maneuver case. I believe I patterned the available options for each case off of what MJ offers.

#

I quite frequently use the "at a fixed time" option for changing inclination - particularly when I first arrive at a body. This can be adapted to Ap or Pe by merely warping to just before that point and then picking "at a fixed time" which defaults to 30s from now.

#

It's common that I may arrive at a body, and immediately set the inclination to something very high (85-is) either before or after setting the Pe, then set circularize at Pe. This is how I typically get into a polar orbit when arriving. No reason you can't do that for 90° inc too.

wind mica
wind mica
#

I definitely did not like how things looked with the default font. Granted, munix has shown some ways that even the default font could be salvaged - but I honestly still prefer the font I've got.

grizzled vale
#

in the end, it comes down to whether you're going for consistency with the game's UI or not

wind mica
# west slate with the default background color could be a bit easier on eyes too

I'm a bit more open to this suggestion. On the one hand, I happen to really like the high contrast look it has now. I also very much like how K2D2, MNC, and FP have managed to keep a mostly similar and consistent look. On the other hand, the actual game's UI is converging on it's own in terms of style and there's something to be said about aligning with that. Personally, I still like what I've got now better, but I do get that argument.

wind mica
#

But still, I really like this font...

grizzled vale
#

basically, the default UITK styles attempt to make mods look like they are part of the stock game, and not stand out

#

but I do have to admit that MNC and FP have their own charm, too

wind mica
#

I suppose I just wish I liked the standard the game is using more...

west slate
#

I recognize personal taste as an important factor especially when developing in your own spare time, so I understand it 😄

#

On the other side, what about two fonts options? So you don’t have to bundle the CJK font at least

#

since it’s USS it should be doable, but I’d suggest this only if easy enough

grizzled vale
west slate
#

Yup

grizzled vale
#

it's definitely doable

west slate
#

technically it would be the same font

grizzled vale
#

pretty easily, too

#

could just make a class for the root element that when used, will switch the fonts to the UITK ones

#

and then toggle the class at runtime

west slate
#

this is what i was thinking

#

plus I think there are common classes like unity-button which could make the code smaller too

#

what do you think @wind mica ?

wind mica
#

So, I think what you're suggesting is that there might be a user configurable option to switch between the cool font and the default one?

grizzled vale
#

since they're two different fonts

#

so that can easily be done in FP too

wind mica
#

And that with the cool font we do what, remove the CJK?

west slate
#

a Cool / Coherent font setting

grizzled vale
west slate
grizzled vale
#

and anyone playing in Chinese, Korean or Japanese would have to switch to the default UITK font

#

since yours doesn't support them

#

that could even be done automatically based on the game's language

west slate
#

this could be easily auto-set too checking the current language

wind mica
wind mica
grizzled vale
#

that would just be set in the same class where the font is set

#

it's all just USS

safe nimbus
# wind mica Do you mean "I want to change my inclination *from 0°* to 90°"? Because if you w...

If you're changing inclinations to a lower value, you have to do it at AN or DN. Well you don't have to do it at AN/DN, but if you want 0° inclination, then you do. If you're changing to a higher value you can change it anywhere, and it that case it's always better to do it at the highest altitude possible since your speed is lowest then, so you need the least velocity to cancel out. So burning at AP is most deltav efficient.

wind mica
west slate
#

it’s a variable too, like:
unity-font-definition: var(…)
letter-spacing: 0.8;

wind mica
safe nimbus
#

Nope 😆

wind mica
#

I think I got confused

#

About the inclination problem

safe nimbus
#

Hold on, I'll test a bit

wind mica
# grizzled vale that would just be set in the same class where the font is set

It's irrational, but I hesitate to do this. It's like giving up a bit of creative control over an aspect you really like in a particular way, but OTOH I get that it's probably more important that it works well for the player and is configurable to their liking. My hesitation is definitely irrational - but I'm OK with that as it's not the first or only irrational thing about me

grizzled vale
#

then don't, it's your choice

safe nimbus
#

I'm in a highly eccentric orbit around Jool. If I burn at AP, I only need around 600 m/s to change from near 0° to 90°.

grizzled vale
safe nimbus
#

If I try to change it at AN/DN, I don't nearly have enough fuel to do that. That's because my speed is really high at AN/DN, so canceling that requires a lot of energy

#

Sorry for initiating another topic while you're discussing this.

wind mica
#

Of course you're never in a perfectly 0° inc orbit though you might be very close to that - but that doesn't matter because even in that case your orbit might be highly eccentric as in your example here.

wind mica
#

I do prefer a smaller mod.

grizzled vale
#

but there are other ways to accomplish that, too

#

and you do not need to actually let the user pick

wind mica
#

And any intelligent person using a non-CJK language would clearly pick the cool font...

grizzled vale
#

you can use this method we described, but only make the change when the game's language changes

#

and disallow manual configuration of it

safe nimbus
#

You can always increase your inclination at any point in the orbit. AN/DN is for matching planes with another orbiting vessel, or if you want to change your inclination to 0°, because Ascending Node and Descending Nodes are points in the orbit where you're crossing the equator.

west slate
#

Yup, plus I think it's more about the gray vs black background color than the font

#

It would be coherent even if you don't want to make the font configurable

safe nimbus
#

I'll pause this topic till you get to a conclusion,

grizzled vale
candid inlet
grizzled vale
#

basically what I see is something like this (though that's exaggerated)

#

that's why I dislike dark mode in most places

#

astigmatism sucks lmao

west slate
wind mica
wind mica
grizzled vale
#

honestly the best thing that could happen would be for K2-D2 to be converted into UITK, and then you two could literally just share a single .uss file

tulip quarry
#

I'm a kind of afraid of the work involved in this convertion.

wind mica
tulip quarry
#

I've worked so much on the K2D2 UI that it will take time until to get the same level of details

grizzled vale
#

plus, you can already use his stylesheet as a starting point

#

since your UIs are similar

wind mica
west slate
#

plus, hidpi support!

tulip quarry
#

some controllers like the compas or the curve renderer for the lift will be a bit difficult

grizzled vale
#

it might be easier than it was to make the originals

wind mica
#

That would be interesting to see...

tulip quarry
#

yes probably because ImgUI is awfull

grizzled vale
#

since UITK has libraries for vector drawing

candid inlet
#

you can embed imgui in uitk if you really have to, but I'd argue against doing as such

grizzled vale
#

it could definitely be used at least for the first versions if reimplementing these advanced controls would seem too complicated

tulip quarry
#

yes and it's quite easy to debug in UnityEditor

#

I was more on doing a better land and stage pilot for the moment. But I know I'll have to do this adaptation one day. The moment is perhaps now.....

#

🤔

grizzled vale
#

I would definitely try to help you out however I could

tulip quarry
#

I know you can be of great help @grizzled vale

wind mica
#

Honestly, I think you'd find it's way worth it and would not look back once you've done it.

tulip quarry
#

and I've got good examples in MNC Flightplan and all others. and the size adaptation is a huge argument too....

west slate
#

Count on me too if anything is needed! I'd be glad to help

grizzled vale
#

yep, UITK for KSP2 has built-in support for scaling, localization, reusable styles, etc.

west slate
#

it's really easy to build with it, doing it visually furthermore speeds up the development a lot

tulip quarry
#

Thanks a lot

west slate
#

now would be a good moment for a good ol' promotional video for UITK -

wind mica
#

@safe nimbus For you in the next FP release:

            case ManeuverType.newInc:
                Options.Add(TimeRef.EQ_HIGHEST_AD); // "at Cheapest eq AN/DN"
                Options.Add(TimeRef.EQ_NEAREST_AD); // "at Nearest eq AN/DN"
                Options.Add(TimeRef.EQ_ASCENDING);  // "at Equatorial AN"
                Options.Add(TimeRef.EQ_DESCENDING); // "at Equatorial DN"
                Options.Add(TimeRef.X_FROM_NOW);    // "after Fixed Time"
                Options.Add(TimeRef.APOAPSIS);      // "at Next Apoapsis"```
#

Cause it's just that freaking easy.

grizzled vale
#

honestly I would also add Periapsis

candid inlet
#

if you have apoapsis, you should have periapsis

grizzled vale
#

just for completeness

wind mica
#

Periapsis is a gauranteed bad choice

safe nimbus
#

Yeah, some love for Periapsis as well

grizzled vale
safe nimbus
#

but for changing inclination it's a bad choice, yes 🙂

candid inlet
wind mica
#

In what use case is it wise to choose that?

wind mica
#

Actually, it should be this:

            case ManeuverType.newInc:
                Options.Add(TimeRef.EQ_HIGHEST_AD); // "at Cheapest eq AN/DN"
                Options.Add(TimeRef.EQ_NEAREST_AD); // "at Nearest eq AN/DN"
                Options.Add(TimeRef.EQ_ASCENDING);  // "at Equatorial AN"
                Options.Add(TimeRef.EQ_DESCENDING); // "at Equatorial DN"
                Options.Add(TimeRef.X_FROM_NOW);    // "after Fixed Time"
                if (ActiveVessel.Orbit.eccentricity < 1)
                    Options.Add(TimeRef.APOAPSIS);  // "at Next Apoapsis"```
#

We can't have it allowing Ap when the ecc is >= 1

#

That would be really bad

candid inlet
#

Oh yeah, ecc >= 1 is an escape trajectory

#

I was about to say that makes no sense

#

hmm, is it possible to make it show a grayed out apoapsis button?

grizzled vale
wind mica
#

No this gets called when you pick a maneuver type on a tab

grizzled vale
#

but the eccentricity can change without you changing the maneuver type

#

so you'll also need to check for that

wind mica
#

That's a fair point. Currently I call SetOptionList in 16 places, just where I'm handling the maneuver type button toggles like in this example

    private void Circularize()
    {
        // Set the BurnTimeOptions
        selectedManeuver = ManeuverType.circularize;
        ManeuverTypeDesc = SetOptionsList(selectedManeuver);
        // Unset all button toggles
        UnsetToggles();
        // Set this one
        ToggleButtonTextColor(CircularizeButtonOSM, true);
        ToggleButtonTextColor(CircularizeButtonTRMS, true);
        FlightPlanPlugin.Logger.LogInfo($"Circularize: selectedManeuver = {selectedManeuver} {_burnTimeOption}");
    }
#

So, if you click a Circularize button this code runs just once and the options are set.

#

However, you're right - this could lead to a case when eccentricity changes leaving you with a nonsense option for Ap.

#

I could move this to be called on update so that it's only called from one place and just considers whatever the currently selected ManeuverType is - which can be none, so that case would need to be handled.

#

The plus side would be that the option list might be more robust, and the minus would be a little more code to run each update.

grizzled vale
#

it would probably make sense

#

you could just check whether the eccentricity is over 1, or whether the selected maneuver type changed

#

if not, just don't do anything

wind mica
grizzled vale
#

the native dropdown sucks

candid inlet
#

Really need a custom one

grizzled vale
#

yeah

#

I swear that one day I'll get to actually starting work on UITK 3

#

lol

wind mica
#

If we had a custom one I could just set this list once when a maneuver type is selected and the only thing I'd need to do on update grayout the Ap option if it's there

wind mica
#

But for now I think I'd like to keep it simpler. It should be more robust than it is though.

wind mica
#

@grizzled vale , what does the AD mean in CKAN?

#

This is in a brand new copy of 0.2.1 where I'm freshly installing mods

grizzled vale
#

it means "Automatically detected"

#

aka you had the mod installed but not through CKAN

wind mica
#

Oh, I bet I know what happened!

#

When I was first using the new template I didn't have my environment variable set and VS must have put a copy of FP into my steam game!

#

I'll need to fix that.

grizzled vale
#

ah yeah that's definitely possible

wind mica
#

Well this is not good...

#

That should be a clean install of FP 0.10.0 from CKAN and an clean install of NM 0.7.2 also from CKAN

#

So the problem I'm getting goes back a bit further than my recent work.

#

And what's released for all to use is clealy f-ed up.

#

Yuk, and I need to leave tomorrow for a trip where I won't be able to work on this until some time on Friday.

#

@grizzled vale Would you mind testing what your fork is doing? from any Kerbin orbit please use FP to target any other planet and just see what it says for the transfer window phase angle and the synodic period on the PTM: Planet tab

#

I'm getting this from a circular 300 km orbit I teleported to, but I would expect the same result (if this bug is present) at any orbit.

wind mica
#

That's such good news! Now I can pull your source code and diff to see what I've stepped on

wind mica
# grizzled vale looks fine for me

Hey I'm so stupid. How can I do a compare between either of my branches (master or Dev) and your fork? I've googled this but still don't understand.

wind mica
#

Thanks! This is a big help

#

OK, it's pretty much got to be the work I did in FpUiController.cs. Of all the diffs, that's all there really is that I think it could be - and there aren't all that much for diffs.

wind mica
#

Fundamentally, I had three nearly identical blocks of code in the same method that I tried to breack out into one common method that I'd call from those three places. I somehow botched that and made the mess I did.

#

Now I'm back to having the three nearly identical blocks, but at least it works

grizzled vale
#

I'm in bed now, but I can take a look at it tomorrow to see what the reason was

wind mica
#

I'm sure it's something really stupid. I seem to be really good at that 😉

wind mica
#

Oh, BTW, @west slate I've implemented your lovely clickthrough blocking technique in Flight Plan now, too. I'll put this out soon since having a clickthrough blocking technique is so especially useful for any mod - especially one with a lot of buttons like FP.

west slate
#

Happy to hear this! *especially since I use Flight Plan continously 😄 *

tulip quarry
#

Côooooooool

wind mica
#

@grizzled vale do you know why CKAN would be reporting something silly like this for FP?

#

Here I've got the debug version of my game selected, which definitely has 0.10.1 installed, and yet CKAN is saying I've got 0.10.0 installed. Moreover, it's saying 0.10.0.1 is the latest even though I released 0.10.1 last night

#

I've done a refresh

#

I don't see anything wrong in the NetKAN for FP. It points to my GitHub repo and the right SpaceDock, both of which have 0.10.1

wind mica
#

Similar question for MNC. Although CKAN does see that one as updated, it doesn't recognize that I've got that version installed. Shouldn't it show both of those as AD?

grizzled vale
#

if you at some point installed/updated them with CKAN, and then replaced them with your dev versions again, CKAN has no way of knowing that

#

it just thinks you're using the CKAN versions you last installed

wind mica
#

That's the thing, I did install them with CKAN in my non-debug game instance, but I don't believe I've ever installed them with CKAN in by debug game.

#

Maybe I'm wrong about that, but I don't think so.

grizzled vale
#

then I have no clue, you can try to ask HebaruSan in the CKAN discord

wind mica
#

I'll try uninstalling them in CKAN for this game instance and then reinstalling them via VS.

wind mica
#

Uninstalling in CKAN, and then rebuilding in VS did sort out CKAN's recognition of the install being AD, but CKAN does still think FP is current at 0.10.0.1. I'll take that question to HebaruSan on the CKAN discord.

grizzled vale
#

yeah, they'll probably know better what's wrong

wind mica
#

Problem solved. Turns out I was just in idiot QA mode again. I did the build on GH before checking my release.yml, and then found that I needed to do a bit more work there in order to get the auto-push to SpaceDock. I foolishly attempted to solve this by doing a Release build on my PC and then posting that to SpaceDock, but it had a slightly different file size owing to being built on Windows vs. Linux. CKAN did not like the file size mismatch.

#

Problem solved by downloading the zip from GH and replacing the one on SpaceDock with that.

plush coral
#

@wind mica I'm getting an error when trying to update to 0.10.2

CKAN.InvalidModuleFileKraken: FlightPlan 0.10.2: C:\Users\nikit\AppData\Local\CKAN\downloads\downloading\B8934B49-FlightPlan-0.10.2.zip has SHA1 0BBDC9A7D9FB356D139FF7FCE5D0E4009BA91DA7, should be 07737EEE69A10698037C3DF4B1DEAC1B84AC1284
at CKAN.NetModuleCache.Store(CkanModule module, String path, IProgress`1 progress, String description, Boolean move, CancellationToken cancelToken)
at CKAN.NetAsyncModulesDownloader.ModuleDownloadComplete(Uri url, String filename, Exception error, String etag)

wind mica
wind mica
urban river
#

Hi! This is a bit nit-picky, but is there a reason that the maneuver altitude when you choose circularize at an altitude is measured from the center of the body, but the new Pe and new Ap is measured from "sea level"? To me, it would be nice if the maneuver altitude input used the "sea level" altitude that everything else (like the Ap and Pe's displayed in game) uses. I often am targeting circularize at a particular altitude when positioning orbital survey satellites into optimal orbits, and right now I usually start by creating a dummy test maneuver to determine the sea level offset and then calculate the needed value for this field.

This is relatively minor... thanks so much for the mod, I use it CONSTANTLY

wind mica
wind mica
urban river
#

perfect!

wind mica
#

0.10.3 will be coming to a CKAN near you shortly...

wind mica
#

It out there! CKAN may take a bit to catch up, but give it a bit of time and it will. https://spacedock.info/mod/3359/Flight Plan#changelog

urban river
wind mica
#

Do you also use the Resonant Orbit Maneuvers tab to help deploy your sats?

urban river
#

I haven't yet, but maybe I should look at it. I pretty much just use micro engineer to validate the current inclination is close to 90 degrees and then circularize at the optimal altitude.

It would be cool if we had to care about orbit resonance, but KSP's one SOI at a time thing seems to make it mostly roll play, right?

urban river
#

yeah, just realized there's a whole tab I haven't figured out yet in this mod! Some of that stuff looks cool, I might need to learn a bit more orbital science. There's some useful stuff there if I want to say make a geosynchronous orbit. What is Min LOS Alt? What does LOS stand for? Is it where the atmosphere effectively ends and you can timewarp beyond 4x? That would be really useful to have. The occlusion toggle seems to affect it, maybe taking into account how much the atmoshphere occludes? This stuff could be useful if using a mod to make satnet more realistic, maybe I should look at those

wind mica
#

The occlusion toggle affects how atmosphere is accounted for with the min LOS altitude and allows you to have a margin of error in addition to considering the effects of atmosphere on satellite to satellite communication

west slate
urban river
#

ok, so now that I have installed CommNext, I have a reason (I think) to figure out the resonant orbit maneuvers. I'm a novice at this. I think this will help me deploy a constellation of satellites that are spaced evenly in an orbit. I understand the target altitude and I've set it to the synchronous alt. But I don't quite understand what "Fix Ap" / "Fix Pe" does. It seems to use a different altitude than what I put in the target, and I don't understand what it is doing. I suspect it is going to somehow use a different orbit to deploy the satellite(s).

Is there some docs beyond what's on SpaceDock for this tab in FlightPlan? I didn't see much there for that tab, other than to say that it had "Fix Ap" and "Fix Pe" and a screenshot. (It has great docs for the other tabs which I have mastered.)

Or... I probably could figure it out if I had a link to a wikipedia article or something talking about how deployment of constellations work.

west slate
#

ok, so now that I have installed CommNext, I have a reason (I think) to figure out the resonant orbit maneuvers. I'm a novice at this. I think this will help me deploy a constellation of satellites that are spaced evenly in an orbit.

#

This is exactly a good reason to use resonant orbits

#

I didn't try resonant orbit in Flight Plan, however the concept is "simple": one of Pe/Ap is going to be the target, and the other one will be different. The idea is to have an orbit "touching" the desired satellites orbit exactly after a specific period;
e.g. you want it to touch every 20 min (1/3 of the sync orbit period, supposing it is of 60 min), so that you can decouple one satellite each time you pass in Ap/Pe

#

the yellow line here is the "desired" orbit; the dark green line is the resonant orbit, which will allow you to touch the yellow every 1/3 of the yellow orbit

urban river
#

cool. Do you have a link to that website? It might help me in figuring it out, and then I think the FlightPlan stuff will make more sense to me

west slate
#

Oh sure sorry

urban river
#

ah! So one side touching the final orbit and it just lets you space them

west slate
#

It's for KSP1, plus an in-game tool is definitely easier

#

but a good reference to "learn" about it

urban river
#

that's what I was missing, thanks so much for explaining it to me

west slate
#

Glad to be helpful, plus.. doing resonant orbits is hard

#

doing them well I mean

#

😄

urban river
#

I think flightplan will make it much easier. I'll try it out.

wind mica
# urban river I think flightplan will make it much easier. I'll try it out.

OK, I think @west slate probably already helped you with this, but I'll be happy to take a shot at explaining what's going on in the ROM tab. It's all about helping you get your deployment vehicle into a resonant orbit - which is what the Payloads and Deploy Orbits part is about at the top. If you'd like to deploy 3 satellites total, and do each deployment needing just one swing through your resonant orbit then you'd have a 4/3 resonance for a non-diving orbit and you would be releasing each satellite at the Pe of your resonant orbit.

#

In the example above it's starting from a circular orbit with a 600 km altitude, so to get into a 4/3 resonant orbit you need to raise your Ap to 1107 km

#

You can see at the bottom of the tab where it's telling you the orbit you need, and right under that offering you a button to give you the node you need to get into it

#

In a non-diving resonant orbit you always release at the Pe and your resonant orbit flys higher than the orbit you want your satellites to be in (hense it's non-diving)

urban river
#

yes, thank you! I'm in the middle of deploying my first set now. I've had to reset back to VAB a couple times but not because of your tool, little design flaws unrelated to flightplan. I just didn't understand how the deploy orbits worked and once leonardfactory explained them your tool made perfect sense

wind mica
#

If you wanted a do a diving orbit then the resonance would be 2/3 and you'd need to drop the Pe so that your Ap is at 600 and your resonant orbit "dives" below your target orbit

urban river
#

I'm currently using a 4/3 resonant orbit

wind mica
#

Oh, OK. Sounds like you've got it!

urban river
#

yes, thanks so much!

wind mica
#

You can always take a look at diving vs. non-diving to see which will take less delta v

west slate
#

Nice to have the Flight Plan explanation! Now putting relays should be easier 😄

wind mica
#

I'll work on updating the documentation - I see now that that's a bit lacking for this tab!

urban river
#

Hi @wind mica I think when you fixed the target altitudes to use altitude from "sea level" instead of from the center of the body, you may have forgotten about the calculations for synchronous alt. It still shows 3463, which might be correct from the center of Kerbin but it should be around 2863 when measured from sea level I think.

#

My constellation is a bit slower than the rotation of Kerbin, but it will still work I think once it is fully deployed

urban river
#

I got my constellation fully deployed. It works great now that I understand how to do it!

west slate
#

Awesome!!

wind mica
wind mica
urban river
#

Thanks so much! I'll look when I play later today! Out and about now...

#

@wind mica said: Fixed Diving prohibition to account for atmosphere depth. You are now (correctly) prevented from setting up a diving resonant orbit around a body with an atmosphere where the Pe would be inside the atmosphere - which, I think we can all agree, would be bad.

This made me chuckle 😆

wind mica
#

Previously the FixPe and FixAp buttons allowed all the same burn time options as a NewPe or New Ap, but I don't think all those options really make sense for this speciallized application. For now (and I can change this pretty easily) you get a default of "at next periapsis" when doing a FixAp, and a default of "at next apoapsis" for FixPe, but either one will let you pick "at a fixed time from now" which would let you do it right now or whatever. My thinking is that other options than "at next apoapsis" or "at next periapsis" could make sense with the first maneuver (if you need to do more than one), but if you have fixed one of these and then want to fix the other, then you really don't want any other options.

urban river
#

that sounds good to me

wind mica
wind mica
# urban river that sounds good to me

Thanks for helping surface bugs in FP! Your feedback is definitely helping to make this a better tool for everyone. I still need to go do a better write up so this tab is a little less mysterious to those not already familiar with the concepts. It's always my hope that FP gives the right amount of aid that it helps people learn more about orbital mechanics without robbing them of the fun of mission planning.

urban river
#

I confirm the issue with the sync orbit is resolved. Thanks so much!!!

grizzled vale
#

that doesn't seem quite right

#

this is after warping to the transfer window

west slate
#

(I saw that line and I was like, hey it does remember me something!)

wind mica
# grizzled vale that doesn't seem quite right

That definitely doesn't look right. What it reminds me of, though are the results I've seen trying to get a Moon Return at Minmus where it places the node ~180 degrees from where it should be in the starting orbit and it has me headed off to a Kerbol orbit very similar to Kerbin's. If you can, could you go back and take a look to see which side of the orbit around Duna the node is on? It ought to be on the side facing Kerbol so that you depart loosing a lot of speed to give you a Pe somewhere near Kerbin.

grizzled vale
#

yeah no, it was on the other side

wind mica
#

Hmmm... well, scratch that theory.

grizzled vale
#

not 180 degrees, I'd say like 120

#

but moving it around with MNC did give me a transfer

wind mica
grizzled vale
#

yeah

wind mica
#

If that's the case, then it makes me think these things could be related

#

That's a lot like what I've seen with MoonReturn at Minmus, and fundamentally they do the saem thing. Ejection velocity going into Hohmann transfer

#

So... Why would it be out of phase some times and not others? Very curious

grizzled vale
#

yeah, that it is

wind mica
#

Try that if you would. It's a debug build of NM that has a different approach to some functions that I've been testing.

grizzled vale
#

I'm off to bed already, but I will try tomorrow

wind mica
#

It goes back to something @safe nimbus pointed out a while back where planetary rotation was not being handled correctly.

#

There are several places where the code in OrbitExtensions.cs deviated from MJ. I had been using some stuff from KS2. I think it's all working this way now, but if for any reason the values differ we will get warnings in the log like this generates

        public static Vector3d WorldOrbitalVelocityAtUT(this PatchedConicsOrbit o, double UT) // KS2: OrbitalVelocity // was: SwappedOrbitalVelocityAtUT
        {
            // return o.getOrbitalVelocityAtUT(UT).xzy;
            Vector3d thisVec = o.GetOrbitalVelocityAtUTZup(UT).SwapYAndZ;
            Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetOrbitalVelocityAtUTZup(UT).SwapYAndZ); // from KS2
            if (thisVec != thisVec2)
            {
                NodeManagerPlugin.Logger.LogWarning($"WorldOrbitalVelocityAtUT: at {UT} thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                NodeManagerPlugin.Logger.LogWarning($"WorldOrbitalVelocityAtUT: at {UT} thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
                return thisVec2;
            }
            return thisVec;
            // return o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetOrbitalVelocityAtUTZup(UT).SwapYAndZ); // from KS2
        }
#

I believe this one was the one Falki found

        public static Vector3d WorldBCIPositionAtUT(this PatchedConicsOrbit o, double UT) // KS2: RelativePosition // was: SwappedRelativePositionAtUT
        {
            // return o.getRelativePositionAtUT(UT).xzy;
            Vector3d thisVec = o.GetRelativePositionAtUT(UT);
            Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetRelativePositionAtUTZup(UT).SwapYAndZ); // From KS2
            if (thisVec != thisVec2)
            {
                NodeManagerPlugin.Logger.LogWarning($"WorldBCIPositionAtUT: at {UT} thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                NodeManagerPlugin.Logger.LogWarning($"WorldBCIPositionAtUT: at {UT} thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
                return thisVec2;
            }
            return thisVec;
            // return o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetRelativePositionAtUTZup(UT).SwapYAndZ); // From KS2
        }
#

But there are 8 methods in OrbitExtensions where I previously had the KS2 lines, and now I have code blocks like these.

#

I need to scrub some of the code in FP to see if I need to do things like this there as well.

wind mica
#

So, it seems the Minmus Moon Return problem also afflicts Gilly

#

Heads off in almost exactly the wrong direction...

#

With a bunch of pushing the node time around though, and no changes to the burn vector otherwise, I can get this

wind mica
#

Further testing at other moons has not produced results like this - not even Bop or Pol. So, it's not the size of the moon you're at, though maybe it's how deep that moon is inside its primary's SOI. Perhaps the thing that Minmus and Gilly have in common here is just that they are not that deep in the SOI, and perhaps Bop and Pol are comparatively deeper?

plush coral
wind mica
#

I've done a bit more testing on this in that I've got a dev version of FP that's using updated code from the latest MJ2 dev version. That version of MJ has a completely different way of doing Hohmann transfers and moon return - they did a big overhaul of how a bunch of things are done. I've got a working copy of this MJ dev version compiled with some additional debug logging to spit out a lot of info verifying which functions are called and what they're computing when you perform a moon return or bi-impulsive hohmann transfer. I've got equivalent code in my Dev branch of FP on my local machine, so I can verify the same functions are called and what results they give.

#

Curiously, with this all-new code approach I'm getting essentially the same results as before, qualitatively speaking.

#

The same cases work and the same cases fail.

#

I can verify that in MJ2/KSP1 they work fine and see the new functions being called and see what they're computing in the calls.

#

I see the same functions and general behavior in the Dev version of FP where it will go through some number of optimization iterations in the new functions - and code-wise I believe they've got the same code now in these functions.

#

My operating hunch is that with my previous version and with this new Dev version, the same problem exists - which means it's probably not in ReturnFromMoon.cs, TwoImpulseTransfer.cs, OperationTransfer.cs, OperationMoonReturn.cs, the DeltaVAndTimeForHohmannTransfer method (in OrbitManeuverCalculator.cs) or the DeltaVAndTimeForMoonReturnEjection method (also in OrbitManeuverCalculator.cs).

#

Those are all new files and new/overhauled functions.

#

So, if the problem is not there (and why would it be?), and since both the previous version of MJ and the latest Dev version give excellent moon return results at Minmus and Gilly, and since FP is doing the same things in these functions, then the problem is with something these functions call or the inputs to them.

#

I think there may be something fundamentally wrong in FP in how I compute something needed by these functions. In MJ they're getting the right info and giving good/excellent results. In FP they do all the same things but give crap results in some cases. The inputs must be different.

#

The problem then is how to compare the differences in some meaningful way. How to spot where the problem is. As similar as I can make the test cases, they are never identical. The initial conditions for the orbits are always slightly different, and so there will always be small differences everywhere. How then to spot the difference that is actually meaningful?

#

@grizzled vale how would you suggest debugging this? Any ideas?

grizzled vale
#

I can't say I have any better ideas than just testing out the math yourself outside of either MJ or FP

wind mica
#

It's very complicated math as it's run through optimization functions. It's not at all like simple orbital mechanics equations. The simple maneuvers that are like that are sadly not the ones that are failing.

grizzled vale
#

I mean, very complicated math in C# and in Python shouldn't be that different

wind mica
#

Perhaps a painstaking debug mode single stepping through in both might reveal something

grizzled vale
#

it's still just math

wind mica
#
        public static (Vector3d dv, double dt) DeltaVAndTimeForMoonReturnEjection(PatchedConicsOrbit o, double ut, double targetPrimaryRadius)
        {
            FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForMoonReturnEjection: From {o.referenceBody.Name} to {o.referenceBody.referenceBody.Name}");
            FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForMoonReturnEjection: UT = {FPUtility.SecondsToTimeString(ut)}, targetPrimaryRadius = {targetPrimaryRadius}");
            var solver = new ReturnFromMoon();

            CelestialBodyComponent moon = o.referenceBody;
            CelestialBodyComponent primary = moon.referenceBody;
            (V3 moonR0, V3 moonV0) = moon.Orbit.RightHandedStateVectorsAtUT(ut);
            double moonSOI = moon.sphereOfInfluence;
            (V3 r0, V3 v0) = o.RightHandedStateVectorsAtUT(ut);

            FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForMoonReturnEjection: Calling ReturnFromMoon.NextManeuver");
            (V3 dv, double dt, double newPeR) = solver.NextManeuver(primary.gravParameter, moon.gravParameter, moonR0,
                moonV0, moonSOI, r0, v0, targetPrimaryRadius, 0);

            FlightPlanPlugin.Logger.LogDebug($"Solved PeR from calculator: {newPeR}");

            return (dv.V3ToWorld(), ut + dt);
        }```
#

If RightHandedStateVectorsAtUT is wrong, then of course it will all fall apart.

#

Once you go into solver.NextManeuver things are not so easy

grizzled vale
#

if I had to guess, these inaccuracies are probably caused by the differences in representations of orbits and coordinates in the two games

#

beyond that, I have no clue

#

I would have to do a deep dive into MechJeb's code to understand exactly how it works

#

and also into both of the games' orbital physics systems

outer valve
outer valve
grizzled vale
wind mica
#

The outputs are deltaV and time for burn. If the outputs were not working then I think all of FP would be failing, so I suspect it's the inputs.

#

My current hope is that it's in RightHandedStateVectorsAtUT since I don't think I'm using that one in the stuff that does work.

outer valve
#

my eye was on the right state vector

#

it's definition can be slightly arbitrary (as it just has to be in the plane defined by the up vector)

#

get we get some debug data from MJ running in KSP1?, like values for inputs in a given gamestate

wind mica
#

Yeah, I can get that. I'm aiming to set up as close to the same initial conditions as I can by using the cheat menues to teleport to a starting condition and trying to make sure the UT is very lose to the same.

#

Then I make saves at those points and do a load-and-test approach

outer valve
#

I notice that there are lots of direction vectors changing rapidly when you pass 20km altitude, so, I mean, quite likely that some objects are still bugged in ksp2

wind mica
#

Here's a sample from FP

#

I'll try to get the same one from MJ and post that.

#

This one gives a typically borked return

#

Here's the same thing from MJ

#

Although I'm puzzled by the time... In FP the UT was 5:45:46, in MJ it reports as 1d 00h 15m 20s, although the screen shot clearly shows it's 5:45:24-ish

urban river
#

Could this be a timing issue like CommNext had? It sounds similar... the right computations, but if you get coordinates for different things at different times, things could be way off especially when you are far from Kerbol because of the speed of the SOIs

wind mica
#

I do not think it is as I renamed my Update function to be LateUpdate in FP and that had no effect.

urban river
#

k

grizzled vale
#

huh that's weird

#

5:45 is 15 minutes less than 1 day, not more

wind mica
#
    private void LateUpdate()
    {
        if ((_keybind != null && _keybind.Value.IsDown()) || (_keybind2 != null && _keybind2.Value.IsDown()))
        {
            ToggleButton(!InterfaceEnabled);
            if (_keybind != null && _keybind.Value.IsDown())
                Logger.LogDebug($"Update: UI toggled with _keybind, hotkey {_keybind.Value}");
            if (_keybind2 != null && _keybind2.Value.IsDown())
                Logger.LogDebug($"Update: UI toggled with _keybind2, hotkey {_keybind2.Value}");
        }
        //if (_keybind != null && _keybind.Value.IsDown())
        //{
        //  ToggleButton(!_interfaceEnabled);
        //  Logger.LogInfo($"Update: UI toggled with _keybind, hotkey {_keybind.Value}");
        //}
        //if (_keybind2 != null && _keybind2.Value.IsDown())
        //{
        //  ToggleButton(!_interfaceEnabled);
        //  Logger.LogInfo($"Update: UI toggled with _keybind2, hotkey {_keybind2.Value}");
        //}
        //if (MainUI != null)
        //  MainUI.Update();
    }```
#

That used to be Update

#

But then it may be the wrong thing to test..

urban river
#

You're over my head but it might be worth pinging @west slate to see if he has any ideas based on his experience

wind mica
#

Maybe I need to also change from Update to LateUpdate in FpUiController? The above is in FlightPlanPlugin

west slate
#

You need to check from my experience everywhere you use <simObj>.Position

#

If you access it, you need to be sure that code is run in LateUpdate

#

Are you running everything in the main thread or are you using Coroutines?

wind mica
#

Well, I access that alot. How do I ensure it's only accessed in a LateUpdate?

grizzled vale
#

in this case it doesn't seem like that is relevant

wind mica
#

And not here

grizzled vale
#

since your Update/LateUpdate doesn't seem to be doing anything else than opening/closing the window

#

you're not running any simulation code in it

#

so it's irrelevant

west slate
#

this is the thing I noticed

grizzled vale
#

yeha but what I'm saying is, his Update doesn't do anything

#

other than toggling the UI visibility

west slate
#

I know, but if that code in the UI

#

starts grabbing positions

#

you cannot be sure they are all right

grizzled vale
#

I'm not sure what you mean

west slate
#

Suppose you do this:

grizzled vale
#

it's only changing visibility

west slate
#

Oh ok

#

lol no in that case it's non an issue by itself

#

but the important thing

wind mica
#

Fine, so I changed that back. That makes sense

west slate
#

is to check that all code using simulation positions

#

is run not during an Update phase

wind mica
#

But how can I make sure I only access <simObj>.Position in a LateUpdate?

wind mica
#

I've got zero clue how to make that happen

grizzled vale
#

well, the code runs presumably in the event handlers for UI elements like buttons

#

so it depends on when Unity fires those events

west slate
#

doubt*

wind mica
#

I'll try changing from Update to LateUpdate in FpUiController. Maybe that will have an effect

west slate
#

How do you start the computations?

wind mica
#

Buttons trigger it from the UI

west slate
#

Ok

wind mica
#

Well that didn't make it happy

#

Disregard, I think it had a pre-existing node where it was trying to create one

#

Clearing the node and starting again I get this

#

Which is to say the same horrible junk as always when at Minmus

west slate
#

I'd try, for testing at least, to do something like this

private bool _shouldRunCommand;
// ...
private void Initialize() {
  button.clicked += () => _shouldRunCommand = true;
}
// ...
private LateUpdate() {
  if (_shouldRunCommand) RunYourComputations();
}
wind mica
#

very, very, very wrong node position

grizzled vale
wind mica
#

I can take a shot at that.

outer valve
#

also, looking at the two logfiles, it does seem that the coordinate systems are very different.

#

[Info : Unity Log] [MechJeb2] ReturnFromMoon.NextManeuver: moonR0 = [39,546,587.103, -24,925,876.922, 4,875,254.677] m
[Info : Unity Log] [MechJeb2] ReturnFromMoon.NextManeuver: moonV0 = [146.463, 231.682, -3.537] = 274.118 m/s
[Debug :Flight Plan] DeltaVAndTimeForMoonReturnEjection: moonR0 = [-45,666,090.976, 9,973,610.437, 4,912,761.936] m
[Debug :Flight Plan] DeltaVAndTimeForMoonReturnEjection: moonV0 = [-58.473, -267.808, 0.159] = 274.118 m/s

wind mica
#

It's nice the vector magnitudes are the same.

outer valve
#

[Info : Unity Log] [MechJeb2] Secondary celestial orbit: sma:47,000,000.000 ecc: 0.000 inc: 6.000 lan: 230.647 argp: 0.000 tanom: 97.092
[Info :Flight Plan] Secondary celestial orbit: sma:47,000,000.000 ecc:0.000 inc:6.000 lan:78.000 argp:277.213 tanom:172.469

wind mica
#

I'd hoped that with a fairly similar initial time and orbit I might see most of the error being in a Swap Y and Z kind of thing or maybe a sign diff

outer valve
#

it doesn't mean they are wrong necessarily, but the reference coordinate is definately a different one

grizzled vale
grizzled vale
#

more likely you'll have to do some linear algebra

#

to convert between them

wind mica
wind mica
#

The game may well be doing all the math for me and I just need to fix something like that

grizzled vale
#

well, one of the biggest things is whether you're in the same reference frame

#

the game does have conversion methods between them

west slate
#

It's pretty easy in reality

wind mica
#

It's not always obvious as the game has very similar or same sounding methods which are not always same

west slate
#

body.celestialFrame.ToLocalPosition(otherPosition)

wind mica
#

I'd buy a bottle of nice scotch for the first person who can beat the truth out of the devs for wth they did with that stuff

west slate
#
sourceTransform.celestialFrame.ToLocalPosition(body.transform.Position)
wind mica
#

Or vodka if you prefer... I'm not picky

west slate
#

I was asking too, the main thing I suppose is that having different Frames it would be easier to implement N-body dynamics

west slate
outer valve
#

So, I've computed the angle between the MoonR0 from MJ and FP, and this is what I get:
rad 2.736926968124578
deg 156.8143641090747
I was hoping for 90deg or something, but it's not

#

the angle between the velocities is also slightly off:
rad 2.7926104138145993
deg 160.00479053585886

#

and r0
rad 2.6269295365376197
deg 150.511975521863
and v0
rad 2.6269276478404753
deg 150.51186730748785
I have no idea to explain these angles, moreover, if it is only the reference frame that is changed, they should all be the same, and I think they are enough different to exclude computational precision

wind mica
#
    public static (V3 pos, V3 vel) RightHandedStateVectorsAtUT(this PatchedConicsOrbit o, double ut)
    {
        o.GetOrbitalStateVectorsAtUT(ut, out var localPositionZup, out var relativeVelocityZup);
        return (localPositionZup.ToV3(), relativeVelocityZup.ToV3());
    }```
#

That's what Node Manager has in it.

#

And this is what MJ has in the same bit

        public static (V3 pos, V3 vel) RightHandedStateVectorsAtUT(this Orbit o, double ut)
        {
            o.GetOrbitalStateVectorsAtUT(ut, out Vector3d pos, out Vector3d vel);
            return (pos.ToV3(), vel.ToV3());
        }```
#

Where GetOrbitalStateVectorsAtUT is a KSP1/KSP2 function

outer valve
#

are these righthandedvectors in the log too? didn't spot them

#

and, the orbits are defined differently too between KSP1 and KSP2, notice the argp here: #1091863665134796880 message

#

the difference in lan is 152 deg, sus...

outer valve
#

do you have any idea why these two dv vectors are not equal:
[Info :Flight Plan] CreateManeuverNode: Solution Found: _deltaV1 [70.256, 0.416, 142.483] m/s = 158.863 m/s 1:12:28.86 from now
[Info :Flight Plan] CreateManeuverNode: newDeltaV [71.369, 0.420, 141.926] m/s = 158.861 m/s

I mean, they are close, but I don't see why they are not identical

outer valve
#

So, i've encountered another, perhaps similar issue. I've put two craft in a circular orbit around kerbin. Then I ask FP for a hohmann transfer, and it gives me the one in the first screen (ending 2957_1.jpg), it has a closest approach of 1225km, which is less then optimal. Now, by just moving the time of the burn I can get the correct transfer with 290m of distance. Notice how the two are about 180deg apart. I've included the save, it's a bare sandbox with just the two vessels, perhaps this can be a nice testcase.

wind mica
# outer valve are these righthandedvectors in the log too? didn't spot them

Yes, both FP and MJ call RightHandedStateVectorAtUT to get a number of the values that are shown in #1091863665134796880 message and #1091863665134796880 message. Here's the code tha produces part of that log in FP, there is nearly identical code in MJ except that it calls a different logging function.

public static (Vector3d dv, double dt) DeltaVAndTimeForMoonReturnEjection(PatchedConicsOrbit o, double ut, double targetPrimaryRadius)
{
    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForMoonReturnEjection: From {o.referenceBody.Name} to {o.referenceBody.referenceBody.Name}");
    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForMoonReturnEjection: UT = {FPUtility.SecondsToTimeString(ut)}, targetPrimaryRadius = {targetPrimaryRadius}");
    var solver = new ReturnFromMoon();

    CelestialBodyComponent moon = o.referenceBody;
    CelestialBodyComponent primary = moon.referenceBody;
    (V3 moonR0, V3 moonV0) = moon.Orbit.RightHandedStateVectorsAtUT(ut);
    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForMoonReturnEjection: moonR0 = [{moonR0.x:N3}, {moonR0.y:N3}, {moonR0.z:N3}] m");
    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForMoonReturnEjection: moonV0 = [{moonV0.x:N3}, {moonV0.y:N3}, {moonV0.z:N3}] = {moonV0.magnitude:N3} m/s");
    double moonSOI = moon.sphereOfInfluence;
    (V3 r0, V3 v0) = o.RightHandedStateVectorsAtUT(ut);
    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForMoonReturnEjection: r0 = [{r0.x:N3}, {r0.y:N3}, {r0.z:N3}] m");
    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForMoonReturnEjection: v0 = [{v0.x:N3}, {v0.y:N3}, {v0.z:N3}] = {v0.magnitude:N3} m/s");
    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForMoonReturnEjection: Calling ReturnFromMoon.NextManeuver");
Discord

Discord is the easiest way to communicate over voice, video, and text. Chat, hang out, and stay close with your friends and communities.

#

The equivalent code in MJ is like this

        public static (Vector3d dv, double dt) DeltaVAndTimeForMoonReturnEjection(Orbit o, double ut, double targetPrimaryRadius)
        {
            Debug.Log($"DeltaVAndTimeForMoonReturnEjection: From {o.referenceBody.name} to {o.referenceBody.referenceBody.name}");
            Debug.Log($"DeltaVAndTimeForMoonReturnEjection: UT = {GuiUtils.TimeToDHMS(ut)}, targetPrimaryRadius = {targetPrimaryRadius}");
            var solver = new ReturnFromMoon();

            CelestialBody moon = o.referenceBody;
            CelestialBody primary = moon.referenceBody;
            (V3 moonR0, V3 moonV0) = moon.orbit.RightHandedStateVectorsAtUT(ut);
            double moonSOI = moon.sphereOfInfluence;
            (V3 r0, V3 v0) = o.RightHandedStateVectorsAtUT(ut);

            Debug.Log($"DeltaVAndTimeForMoonReturnEjection: Calling ReturnFromMoon.NextManeuver");
            (V3 dv, double dt, double newPeR) = solver.NextManeuver(primary.gravParameter, moon.gravParameter, moonR0,
                moonV0, moonSOI, r0, v0, targetPrimaryRadius, 0);

            Debug.Log($"Solved PeR from calculator: {newPeR}");

            return (dv.V3ToWorld(), ut + dt);
        }```
#

So, FP calls ReturnFromMoon.NextManeuver, and that also logs the same values

        public (V3 dv, double dt, double newPeR) NextManeuver(double centralMu, double moonMu, V3 moonR0, V3 moonV0, double moonSOI, V3 r0, V3 v0,
            double peR, double inc, bool optguard = false)
        {
            FlightPlanPlugin.Logger.LogInfo(
                $"ReturnFromMoon.NextManeuver: centralMu = {centralMu:N3}, moonMu = {moonMu:N3}, moonSOI = {moonSOI:N3}, peR = {peR:N3}, inc = {inc:N3}, optguard = {optguard}");
            FlightPlanPlugin.Logger.LogInfo(
                $"ReturnFromMoon.NextManeuver: moonR0 = {moonR0:N3} m");
            FlightPlanPlugin.Logger.LogInfo(
                $"ReturnFromMoon.NextManeuver: moonV0 = {moonV0:N3} = {moonV0.magnitude:N3} m/s");
            FlightPlanPlugin.Logger.LogInfo(
                $"ReturnFromMoon.NextManeuver: r0 = {r0:N3} m");
            FlightPlanPlugin.Logger.LogInfo(
                $"ReturnFromMoon.NextManeuver: v0 = {v0:N3} = {v0.magnitude:N3} m/s");```
#

So, you can see that moonR0, moonV0, r0, and v0, all are obtained from calls to RightHandedStateVectorsAtUT(ut)

#

And the code for those functions are basically the same for FP and MJ

wind mica
# outer valve do you have any idea why these two dv vectors are not equal: [Info :Flight Pla...

Those vecotrs are similar but slightly different because FP backs off the node time by 1/2 the burn duration to make is so the center of the burn is at the point it's asked for. KSP1 doesn't need this, but KSP2 does. We need this because the orbital mechanics equations and methods applied by both MJ and FP assume an instantaneous impulse, so the burn vector computed has no understanding of the burn duration. It's not enough to simple move the node time back by 1/2 the duration though. Since burn vectors are in Prograde, Normal, and Radial directions, then shifting the time of the node cause a rotation of the vector in inertial space. This is why FP looks at the direction of the burn vector in an inertial frame at the requested time of the burn, then backs off the node time and rotates the burn so that it's new Prograde, Normal. and Radial components align with the original inertial vector.

#

What I can't explain off the top of my head is why there would be a 0.02 m/s difference between their magnitudes. I've not observed that before. The magnitudes should be the same.

wind mica
outer valve
outer valve
#

Did you move minimus before using MJ in your log above?

wind mica
#

I’m going to catalog all the places where I use simobj position and look at how that transform is done. Maybe we’ll get lucky and find a simple fix in there. I’ve previously done tests to ensure the base functionality is returning the same values for other things, but not the right handed versions

#

This is involving code in Node Manager BTW as that mod also needs the functionality so I put it there

outer valve
#

I was thinking, does the KontrolSystem (https://forum.kerbalspaceprogram.com/topic/214543-release-kontrolsystem2-042/) mod use the same codebase to make transfers? If not, maybe it can serve as a reference to test some code

wind mica
# outer valve I was thinking, does the KontrolSystem (https://forum.kerbalspaceprogram.com/top...

It does not use the same code base, and I have used it as a reference. In fact, when I was initially struggling to get the MJ code in FP to work, I turned to KS2 for examples and have duplicate bits of code in OrbitExtensions.cs in Node Manager such as this.

        public static Vector3d WorldOrbitalVelocityAtUT(this PatchedConicsOrbit o, double UT) // KS2: OrbitalVelocity // was: SwappedOrbitalVelocityAtUT
        {
            // return o.getOrbitalVelocityAtUT(UT).xzy;
            Vector3d thisVec = o.GetOrbitalVelocityAtUTZup(UT).SwapYAndZ; // MechJebWay
            Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetOrbitalVelocityAtUTZup(UT).SwapYAndZ); // from KS2
            if (thisVec != thisVec2)
            {
                NodeManagerPlugin.Logger.LogWarning($"WorldOrbitalVelocityAtUT: at {UT} thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                NodeManagerPlugin.Logger.LogWarning($"WorldOrbitalVelocityAtUT: at {UT} thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
                // return thisVec2;
            }
            return mechJebWay ? thisVec : thisVec2;
        }```
#

In all, there were 7 places I did this, and I've experimented with these confirming that the code I've got now gives the same results, and will give a warning level log in any case where it doesn't. Note that in MJ/KSP1 there is a .xzy method for Vector3d. The equivalent in KSP2 is .SwapYAndZ.

#

In my Dev version of Node Manager I define mechJebWay as true within the OrbitExtensions class like this

    public static class OrbitExtensions
    {
        private static bool mechJebWay = true;```
#

However, regardless of how that's defined, I compute both ways and compare them so I would get a warning if they're different.

#

There is one exception where I deviate from the pure MechJeb approach, and that's in WorldBCIPositionAtUT.

        public static Vector3d WorldBCIPositionAtUT(this PatchedConicsOrbit o, double UT) // KS2: RelativePosition // was: SwappedRelativePositionAtUT
        {
            // return o.getRelativePositionAtUT(UT).xzy;
            Vector3d thisVec = o.GetRelativePositionAtUT(UT); // MechJebWay (sort of - without the SwapYAndZ)
            Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetRelativePositionAtUTZup(UT).SwapYAndZ); // From KS2
            if (thisVec != thisVec2)
            {
                NodeManagerPlugin.Logger.LogWarning($"WorldBCIPositionAtUT: at {UT} thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                NodeManagerPlugin.Logger.LogWarning($"WorldBCIPositionAtUT: at {UT} thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
                // return thisVec2;
            }
            return mechJebWay ? thisVec : thisVec2;
        }```
#

Here, you can see that in MJ, they apply the .xzy operation, but in my code we do not. This is necessary to get agreement with the KS2 result and to also get good results. If I were to apply the .SwapYAndZ operation here then all hell breaks loose and everything that depends on WorldBCIPositionAtUT would fail to produce any kind of good result.

wind mica
#

I just pulled a fresh copy of KS2 and it looks like that mod may have changed how it computes some things since I snatched code from it. I believe the place to look is in KS2's OrbitWrapper.cs, but there are no comments at all (shame on you untoldwind!) and the names have either changed or I've lost track of what the mapping was. Probably the latter. If I look at older versions of my OrbitExtensions.cs I may find comments I used to have that noted what the corresponding KS2 method names are. With the code changed now in KS2 it will be hard to sort out just based on that.

#

I think a good exercise now would be to re-map the MJ OrbitExtensions methods to the corresponding KS2 methods and then update my calculations for thisVec2 so we can see if there are differences in any of these. If there are differences, then it may be a good experiment to set mechJebWay to false and see what we get.

west slate
#

Sounds a good plan

#

hard, but a good plan

wind mica
#

Not too hard in some cases...

        public static Vector3d WorldOrbitalVelocityAtUT(this PatchedConicsOrbit o, double UT) // KS2: OrbitalVelocity // was: SwappedOrbitalVelocityAtUT
        {
            // return o.getOrbitalVelocityAtUT(UT).xzy;
            Vector3d thisVec = o.GetOrbitalVelocityAtUTZup(UT).SwapYAndZ; // MechJebWay
            // Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetOrbitalVelocityAtUTZup(UT).SwapYAndZ); // from KS2
            Vector3d thisVec2 = o.GetOrbitalVelocityAtUTZup(UT).SwapYAndZ; // from KS2 2024.02.21
            if (thisVec != thisVec2)
            {
                NodeManagerPlugin.Logger.LogWarning($"WorldOrbitalVelocityAtUT: at {UT} thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                NodeManagerPlugin.Logger.LogWarning($"WorldOrbitalVelocityAtUT: at {UT} thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
                // return thisVec2;
            }
            return mechJebWay ? thisVec : thisVec2;
        }```
#

So, KS2 uses o.OrbitalVelocity as MJ and FP use o.WorldOrbitalVelocityAtUT for example, and apparently KS2 is now using the exact same thing MJ and FP use for this. I'll keep sorting through these looking for where things get different.

#
        public static Vector3d WorldBCIPositionAtUT(this PatchedConicsOrbit o, double UT) // KS2: RelativePosition // was: SwappedRelativePositionAtUT
        {
            // return o.getRelativePositionAtUT(UT).xzy;
            Vector3d thisVec = o.GetRelativePositionAtUT(UT); // MechJebWay (sort of - without the SwapYAndZ)
            // Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetRelativePositionAtUTZup(UT).SwapYAndZ); // From KS2
            Vector3d thisVec2 = o.GetRelativePositionAtUTZup(UT).SwapYAndZ; // From KS2 2024.02.21
            if (thisVec != thisVec2)
            {
                NodeManagerPlugin.Logger.LogWarning($"WorldBCIPositionAtUT: at {UT} thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                NodeManagerPlugin.Logger.LogWarning($"WorldBCIPositionAtUT: at {UT} thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
            }
            return mechJebWay ? thisVec : thisVec2;
        }```
#

Interesting difference here perhaps.

#
        public static Vector3d OrbitNormal(this PatchedConicsOrbit o) // KS2: OrbitNormal // was: SwappedOrbitNormal
        {
            // return -o.GetOrbitNormal().xzy.normalized;
            Vector3d thisVec = -o.GetRelativeOrbitNormal().SwapYAndZ.normalized; // MechJebWay
            // Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, -o.GetRelativeOrbitNormal().SwapYAndZ).normalized; // From KS2
            Vector3d thisVec2 = -o.GetRelativeOrbitNormal().SwapYAndZ; // From KS2 2024.0220
            if (thisVec != thisVec2)
            {
                NodeManagerPlugin.Logger.LogWarning($"OrbitNormal(1): thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                NodeManagerPlugin.Logger.LogWarning($"OrbitNormal(1): thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
            }
            return mechJebWay ? thisVec : thisVec2;
        }```
#

Another one with no difference in KS2 these days.

#

Also this one is no longer a difference

        public static Vector3d NormalPlus(this PatchedConicsOrbit o, double UT)
        {
            // return o.OrbitNormal();
            Vector3d thisVec = o.GetRelativeOrbitNormal().SwapYAndZ.normalized; // MechJebWay
            // Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetRelativeOrbitNormal().SwapYAndZ.normalized); // From KS2
            Vector3d thisVec2 = o.GetRelativeOrbitNormal().SwapYAndZ.normalized; // From KS2 2024.02.21
            if (thisVec != thisVec2)
            {
                NodeManagerPlugin.Logger.LogWarning($"NormalPlus: thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                NodeManagerPlugin.Logger.LogWarning($"NormalPlus: thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
            }
            return mechJebWay ? thisVec : thisVec2;
        }```
#

These look OK

        //normalized vector along the orbital velocity
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector3d Prograde(this PatchedConicsOrbit o, double UT) // Agrees with KS2
        {
            // KS2: OrbitalVelocity(ut).normalized; // From KS2 2024.02.21
            return o.WorldOrbitalVelocityAtUT(UT).normalized;
        }

        //normalized vector pointing radially outward from the planet
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector3d Up(this PatchedConicsOrbit o, double UT) // Agrees with KS2
        {
            //KS2: RelativePosition(ut).normalized; // From KS2 2024.02.21
            return o.WorldBCIPositionAtUT(UT).normalized;
        }

        //normalized vector pointing radially outward and perpendicular to prograde
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector3d RadialPlus(this PatchedConicsOrbit o, double UT) // Agrees with KS2
        {
            // KS2: Vector3d.Exclude(Prograde(ut), Up(ut)).normalized; // From KS2 2024.02.21
            return Vector3d.Exclude(o.Prograde(UT), o.Up(UT)).normalized;
        }```
wind mica
#

I've been able to match up nearly all of the functions from KS2's OrbitWrapper.cs to the MJ/FP OrbitExtensions.cs. There are still a few spots where I'm uncertain though, and I suspect these include the spot(s) that matter. For example, WorldBCIPositionAtUT (#1091863665134796880 message). However, I've also found several sources that talk about swapping between right-handed and left-handed coordinates, such as here https://stackoverflow.com/questions/1263072/changing-a-matrix-from-right-handed-to-left-handed-coordinate-system

Discord

Discord is the easiest way to communicate over voice, video, and text. Chat, hang out, and stay close with your friends and communities.

#

It seems that all that's needed is to do a .SwapYAndZ to get from one to the other. Also, KSP2 chose to give us slightly different function names that may actually be decalring whether they're returning right-handed or left-handed coordinates. In WorldBCIPositionAtUT, the MJ approach is simply this

return o.getRelativePositionAtUT(UT).xzy;```
And the KS2 version of the same function (called RelativePosition) is this
```cs
return o.GetRelativePositionAtUTZup(UT).SwapYAndZ;```
#

Since Z is up in a right-handed coordinate system, then presumably GetRelativePositionAtUTZup gives us the relative position in right-handed coordinates and KS2 is transforming it to left-handed. I've seen comments in MJ that talk about KSP1 functions returning things in such a way that they need a .xzy operation, so this makes sense. KSP2 is just being honest in the method name.

#

So, in this case, KSP1 apparently has getRelativePositionAtUT (which returns right-handed, and so needs a .xzy), and KSP2 has both GetRelativePositionAtUT (returning left-handed) and GetRelativePositionAtUTZup (returning right-handed, and so needing a .SwapYAndZ).

#

This makes me wonder if there's more to the difference between these two than just the coordinate frame - or why would they have them.

#

Also there is this weird thing in KS2. Weird, in that it seems like it's a recursive call

    public Position GlobalPosition(double ut) {
        return ReferenceBody.Orbit.GlobalPosition(ut) + GlobalRelativePosition(ut);
    }```
#

I believe this function is intended to serve the same purpose as the MJ/FP WorldPositionAtUT function, which I've got as this.

        public static Vector3d WorldPositionAtUT(this PatchedConicsOrbit o, double UT) // was: SwappedAbsolutePositionAtUT
        {
            // return o.referenceBody.position + o.WorldBCIPositionAtUT(UT);
            Vector3d thisVec = o.referenceBody.Position.localPosition + o.WorldBCIPositionAtUT(UT); // MechJebWay
            Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.referenceBody.Position.localPosition + o.GetRelativePositionAtUTZup(UT).SwapYAndZ); // from KS2
            // Vector3d thisVec2 = o.referenceBody.Orbit.GlobalPosition(ut) + GlobalRelativePosition(ut); // KS2: 2024.02.21 - recursive function? This is in a method called `GlobalPosition`
            if (thisVec != thisVec2)
            {
                NodeManagerPlugin.Logger.LogWarning($"WorldPositionAtUT: at {UT} thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                NodeManagerPlugin.Logger.LogWarning($"WorldPositionAtUT: at {UT} thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
                // return thisVec2;
            }
            return mechJebWay ? thisVec : thisVec2;
        }```
#

There is some old KS2 code in there (marked // from KS2), and then there's the new KS2 code commented out for comparison, but what's going on here? OrbitWrapper extends Orbit objects, so it would give you an Orbit.GlobalPosition method. Calling that should then call ReferenceBody.Orbit.GlobalPosition. WTF? A ReferenceBody will have an Orbit, but since Orbit is extended, that orbit will have a GlobalPosition method and we're off to the recursive races.

#

In VS, when I ask it where the GlobalPosition of RefererenceBody is defined it just shows me the same function. I understand recursion, and as we all know - to understand recursion you must first understand recursion... But... WTH?

#

KS2, in it's current form, does not have anything equivalent to the RightHandedOrbitalVelocityAtUT method in MJ/FP, but I believe it used to - at least I've got some code and a comment that claims it did. Nevertheless, given what I beleive I know about these functions, what is in MJ and FP makes sense. MJ calls getOrbitalVelocityAtUT and doesn't do a .xzy, and FP calls GetOrbitalVelocityAtUTZup and similarly does not do a .SwapYAndZ, so that seems like it should be OK. I guess KS2 just doesn't need this function, or at least I was unable to map it to anything.

#

GetOrbitalVelocityAtUTZup is called in only one place in KS2, and that's in the OrbitalVelocity method in OrbitWrapper, but that applies a .SwapYAndZ to it, so it's apparelyt left-handed in it's return.

#

There are no places in KS2 that then turn around and call OrbitalVelocity applying another .SwapYAndZ, so it's just not got an equivalent to RightHandedOrbitalVelocityAtUT as far as I can tell.

#

Another similar difference is in RightHandedBCIPositionAtUT

        public static V3 RightHandedBCIPositionAtUT(this PatchedConicsOrbit o, double UT)
        {
            // return o.getRelativePositionAtUT(UT).ToV3();
            V3 thisVec = o.GetRelativePositionAtUTZup(UT).ToV3(); // MechJebWay
            V3 thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, o.GetRelativePositionAtUTZup(UT)).ToV3(); // from KS2
            if (thisVec != thisVec2)
            {
                NodeManagerPlugin.Logger.LogWarning($"RightHandedBCIPositionAtUT: at {UT} thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                NodeManagerPlugin.Logger.LogWarning($"RightHandedBCIPositionAtUT: at {UT} thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
                // return thisVec2;
            }
            return mechJebWay ? thisVec : thisVec2;
        }```
Where again I seem to have som older KS2 code hanging in there, but I can't find an KS2 equivalent to this what's in the current code base. There's the KS2 RelativePosition method, but that applies .SwapYAndZ to the GetRelativePositionAtUTZup - so that's not right-handed.
#

There's also KS2's GlobalRelativePosition which does this

    public Vector GlobalRelativePosition(double ut) {
        return new Vector(ReferenceFrame, orbit.GetRelativePositionAtUTZup(ut).SwapYAndZ);
    }```
#

But the real kicker, the one I'm more concerned with for the current problem, is the MJ/FP RightHandedStateVectorsAtUT method, which is this.

        public static (V3 pos, V3 vel) RightHandedStateVectorsAtUT(this PatchedConicsOrbit o, double ut)
        {
            o.GetOrbitalStateVectorsAtUT(ut, out Vector3d pos, out Vector3d vel);
            return (pos.ToV3(), vel.ToV3());
        }```
#

This is the one we've seen differences in, and given the KSP2 penchant for naming things that return right-handed with a ZUp, then I'm guessing that maybe this is left-handed. This is why I was expecting that possibly the difference between what MJ gives today and what FP gives would be possibly swapped in those coordinates, but they were not, and instead the observed difference was... stranger. #1091863665134796880 message

#

KSP2 has a GetOrbitalStateVectorsAtUT, a GetOrbitalStateVectorsAtObT, and a GetOrbitalStateVectorsAtTrueAnomaly, but no GetOrbitalStateVectorsAtUTZup or anyhting like that.

#

Time to go spelunking into KSP2 and see if I can learn what that function does...

wind mica
#

LOL, GetOrbitalStateVectorsAtUT just calls GetOrbitalStateVectorsAtObT passing in this.GetObtAtUT(UT) and UT. However it does appear to return localPositionZup and relativeVelocityZup!

#

And guess what. GetOrbitalStateVectorsAtObT just calls GetOrbitalStateVectorsAtTrueAnomaly passing in this.TrueAnomalyAtObT(ObT) and UT!

#

Digging through GetOrbitalStateVectorsAtTrueAnomaly it does appear that GetOrbitalStateVectorsAtUT returns right-handed vectors.

outer valve
#

digesting your posts

outer valve
outer valve
outer valve
#

man, quite the journey, I guess I have to bite the bullet and install the stuff to inspect this code in action, c# seems quite easy to read with a c++ background. However, I have a weekend trip planned this WE, so it will have to wait.

wind mica
# outer valve are you ever dealing with matrices? I think not right, all relevant objects are ...

Lots and lots of vectors, but not a lot of matrices. Mostly it's Vector3d, V3. As I inherit code from MJ there are some things in Primitives which include M3.cs and V3.cs. M3 is a "3x3 Matrix with right-handed APIs that integrates with V3 and Q3" according to the comments in it. In Node Manager, where I've got that, it's used only within M3.cs and Statics.cs, where in Statics.cs it's used in the NearlyEqual method. NearlyEqual is not even used in Node Manager, but other parts of Statics are, so I included M3.cs there.

#

In FP there is more use of M3, in particular in Sheppard.cs in the Solve2 method, and a little bit in Statics.cs (NearlyEqual method) and in Astro.cs in the ENUToECI and ECIToENU methods.

#

When I look in FP, I don't see anywhere that Solve2 is used, and VS is telling me there are 0 references. I do have 16 references to Solve from Sheppard.cs, but that just uses some V3's. So, I don't think I'm really using matricies in FP and those are not likely to be the issue, but this was a good line to explore so I'm glad you asked since I hadn't gone down that line yet.

wind mica
# outer valve The recursion issue seems valid, can you add a recursion counter in there to see...

The recursion issue, if there is one, would be in KS2 and not in FP. It's quite possible it's not really an issue and there's something subtle going on there that I'm not realizing. Digging into that I see that KS2 has this in KSPOrbitModule.Orbit.cs

        [KSMethod(Description = @"Get the coordinate independent position at a given universal time `ut`. 
                Note: This takes the motion of the parent body into account.")]
        Position GlobalPosition(double ut);```
#

And it tells me that version of GlobalPosition has 8 references across three files in 5 specific lines - one of which is OrbitWrapper.cs line 93 - the place where I thought there may be recursion.

#

It's also used in OrbitWrapper's GlobalVelocity method

    public VelocityAtPosition GlobalVelocity(double ut) {
        return new VelocityAtPosition(
            new Velocity(context.Game.UniverseModel.GalacticOrigin.celestialFrame.motionFrame,
                orbit.GetFrameVelAtUTZup(ut).SwapYAndZ), GlobalPosition(ut));
    }```
#

Which also turns up in KSPOrbitModule.Orbit.cs like this

        [KSMethod(Description = @"Get the coordinate independent velocity at a given universal time `ut`.
                Note: This takes the motion of the parent body into account.")]
        VelocityAtPosition GlobalVelocity(double ut);```
#

Here are all the references to GlobalPosition from KSPOrbitModule.Orbit.cs

#

In MockOrbit.cs there's a GlobalPosition that does this

    public Position GlobalPosition(double ut) {
        var bodyPosition = body.orbit?.GlobalPosition(ut) ?? new Position(ReferenceFrame, Vector3d.zero);

        return bodyPosition + new Vector(ReferenceFrame, RelativePosition(ut));
    }```
#

That seems like it would not be recursive since if there isn't an orbit for a body (e.g. Kerbol) then it stops the recursion and just returns the position.

#

I think I'm getting confused with there being multiple definitions for GlobalPosition in KS2. I wonder if VS is similarly confused. When I ask it to show me all the places MockOrbit's GlobalPosition is used it points to OrbitWrapper.cs line 93 again as one of them.

#

Possible theories: (a) This is a subtle coding technique I'm not (yet) savvy enough to understand where things with the same name are coexisting in some harmonious and useful way. (b) VS is stupid and can't tell distinct things apart and so is reporting references that are not true. (c) I'm really not savvy and just not understanding some blindingly obvious truth.

#

I do find the KS2 descriptions for GlobalVelocity and GlobalPosition intriging in that they both say "Note: This takes the motion of the parent body into account", which makes me wonder if that's where FP is going wrong. This is one place where FP and KS2 are not yet aligned, so perhpas this is the clue we need to follow.

wind mica
# outer valve So, i've encountered another, perhaps similar issue. I've put two craft in a cir...

I did a quick test in my dev version with an existing save and didn't see an issue when planning a Hohmann transfer between to craft orbiting Mun. I tried both the transfer from the craft in the higher orbit to the lower one and from the lower orbit to the higher one. The lower orbit in my test case was fairly circular, but the higher one happened to be more elliptical. The process should work best when both are perfect coplanar circles. I'll download your save and see if I see this at my end.

wind mica
#

Loading your test case save I do get this issue in my dev version. I also am getting massive log spamming from my own debugging logs for this:

#

The log spam happens when I'm on the Target Relative Maneuvers: Vessel tab (the one needed for this operation), so it presumably relates to the calculation of some info on that tab

#

Moving to the Resonant Orbit Maneuvers tab doesn't generate log spam.

#

OrbitNormal does get called in SynodicPeriod, so it's possible that's what's causing the log spam, however the difference is so slight that I don't think that's likely to have anything to do with the observed effect - it's just annoying in that it makes the log harder to use to diagnose this.

wind mica
#

That's what I see in my log using your save to perform the same maneuver and with the annoying spam resolved.

#

Spam resolved this way:

        public static Vector3d OrbitNormal(this PatchedConicsOrbit o) // KS2: OrbitNormal // was: SwappedOrbitNormal
        {
            // return -o.GetOrbitNormal().xzy.normalized;
            Vector3d thisVec = -o.GetRelativeOrbitNormal().SwapYAndZ.normalized; // MechJebWay
            // Vector3d thisVec2 = o.referenceBody.transform.celestialFrame.ToLocalPosition(o.ReferenceFrame, -o.GetRelativeOrbitNormal().SwapYAndZ).normalized; // From KS2
            Vector3d thisVec2 = -o.GetRelativeOrbitNormal().SwapYAndZ; // From KS2 2024.0220
            if ((thisVec - thisVec2).magnitude > 0.000001)
            {
                NodeManagerPlugin.Logger.LogWarning($"OrbitNormal(1): thisVec  = [{thisVec.x}, {thisVec.y}, {thisVec.z}]");
                NodeManagerPlugin.Logger.LogWarning($"OrbitNormal(1): thisVec2 = [{thisVec2.x}, {thisVec2.y}, {thisVec2.z}]");
            }
            return mechJebWay ? thisVec : thisVec2;
        }```
#

So, it still checks to see if there's a difference, but if the difference is in any way trivial it ignors it

outer valve
#

[Debug :Flight Plan] DeltaVAndTimeForHohmannTransfer: dv1 = [34.933, -128.408, 12.084] = 133.623 m/s, dt1 = 1:27:21.53
[Debug :Flight Plan] DeltaVAndTimeForHohmannTransfer: dv2 = [-50.525, 133.957, 14.209] = 143.872 m/s, dt2 = 1:53:28.69
here the 2nd one seems correct, but the first one doesn't

wind mica
#

Those logs and values are coming from here:

public static ( Vector3d dV1, double UT1, Vector3d dV2, double UT2) DeltaVAndTimeForHohmannTransfer(PatchedConicsOrbit o, PatchedConicsOrbit target, double ut,
    double lagTime = double.NaN, bool fixedTime = false,
    bool coplanar = true, bool rendezvous = true, bool capture = true)
{
    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: Making transfer at UT {FPUtility.SecondsToTimeString(ut)}");
    FlightPlanPlugin.Logger.LogDebug($"lagTime = {lagTime}, fixedTime = {fixedTime}, Coplanar = {coplanar}, Rendezvous = {rendezvous}, Capture = {capture}");

    (V3 r1, V3 v1) = o.RightHandedStateVectorsAtUT(ut);
    (V3 r2, V3 v2) = target.RightHandedStateVectorsAtUT(ut);
    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: r1 = [{r1.x:N3}, {r1.y:N3}, {r1.z:N3}], v1 = [{v1.x:N3}, {v1.y:N3}, {v1.z:N3}] = {v1.magnitude:N3} m/s");
    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: r2 = [{r2.x:N3}, {r2.y:N3}, {r2.z:N3}], v2 = [{v2.x:N3}, {v2.y:N3}, {v2.z:N3}] = {v2.magnitude:N3} m/s");

    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: Calling TwoImpulseTransfer.NextManeuver");
    (V3 dv1, double dt1, V3 dv2, double dt2) =
        TwoImpulseTransfer.NextManeuver(o.referenceBody.gravParameter, r1, v1, r2, v2, lagTime: lagTime, coplanar: coplanar,
            rendezvous: rendezvous, capture: capture);

    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: dv1 = [{dv1.x:N3}, {dv1.y:N3}, {dv1.z:N3}] = {dv1.magnitude:N3} m/s, dt1 = {FPUtility.SecondsToTimeString(dt1)}");
    FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: dv2 = [{dv2.x:N3}, {dv2.y:N3}, {dv2.z:N3}] = {dv2.magnitude:N3} m/s, dt2 = {FPUtility.SecondsToTimeString(dt2)}");

    return (dv1.V3ToWorld(), ut + dt1, dv2.V3ToWorld(), ut + dt2);```
#

So, the second dv we're seeing is actually the second impulse in a TwoImpulseTransfer, which is the burn you need at the end of the rendezvous

#

We're throwing that away right now and relying on the user to do a match velocity node when they get to the rendezvous point

#

That said, the input to TwoImpulseTransfer is coming from RightHandedStateVectorsAtUT, and so this may very well be a symptom of the same problem we're already trying to sort out for Moon Return.

#

Here's a minor bug in FP. IF you select a target before launching FP, or if you select the target by any means other than using FP's GUI, then the FP GUI does not display the target. Not related to our main issue, but something I probably ought to fix.

#

Hold on! I just got this!

#

The only change I made was what I thought was a trivial one to the logging, and now when I load your test case and make a node, bang it nails it.

#

Litterally, the only thing I changed was to simplify the logging like this

        public static ( Vector3d dV1, double UT1, Vector3d dV2, double UT2) DeltaVAndTimeForHohmannTransfer(PatchedConicsOrbit o, PatchedConicsOrbit target, double ut,
            double lagTime = double.NaN, bool fixedTime = false,
            bool coplanar = true, bool rendezvous = true, bool capture = true)
        {
            FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: Making transfer at UT {FPUtility.SecondsToTimeString(ut)}");
            FlightPlanPlugin.Logger.LogDebug($"lagTime = {lagTime}, fixedTime = {fixedTime}, Coplanar = {coplanar}, Rendezvous = {rendezvous}, Capture = {capture}");

            (V3 r1, V3 v1) = o.RightHandedStateVectorsAtUT(ut);
            (V3 r2, V3 v2) = target.RightHandedStateVectorsAtUT(ut);
            FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: r1 = {r1:N3}, v1 = {v1:N3} = {v1.magnitude:N3} m/s");
            FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: r2 = {r2:N3}, v2 = {v2:N3} = {v2.magnitude:N3} m/s");

            FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: Calling TwoImpulseTransfer.NextManeuver");
            (V3 dv1, double dt1, V3 dv2, double dt2) =
                TwoImpulseTransfer.NextManeuver(o.referenceBody.gravParameter, r1, v1, r2, v2, lagTime: lagTime, coplanar: coplanar,
                    rendezvous: rendezvous, capture: capture);

            FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: dv1 = {dv1:N3} = {dv1.magnitude:N3} m/s, dt1 = {FPUtility.SecondsToTimeString(dt1)}");
            FlightPlanPlugin.Logger.LogDebug($"DeltaVAndTimeForHohmannTransfer: dv2 = {dv2:N3} = {dv2.magnitude:N3} m/s, dt2 = {FPUtility.SecondsToTimeString(dt2)}");```
#

Here's what's in the log now

#

Other than those minor changes to logging, the only difference was that I selected the target using the game's interface before launching FP.

outer valve
#

I don't remember how I selected the target, I think I used FP

wind mica
#

Nope... There must be some other differene...

#

I just tried it again and got the bad result.

#

OK, I know what I did differently now, but not why it made a difference. I thought I'd loaded your quicksave_2 save, but instead I'd loaded an autosave_2 that KSP2 made for me when I was previously in your quicksave_2.

#

When I load that save, it works fine. When I load quicksave_2 it does not.

#

There's my autosave_2

outer valve
#

Interesting, maybe the bug is not with FP

wind mica
#

That would be both a joy and a sorrow.

#

Though I wonder if the clue we need is buried in the difference between these saves

outer valve
wind mica
#

No worries... I'll keep whittling on it. There are loads of cases where MoonReturn reliably does not work.

outer valve
#

Ill have a look thru the save in my next train

outer valve
#

lol, I guess we are 6h appart:
"unlockedAt": "2024-02-18T11:22:23.6768437-05:00",
"unlockedAt": "2024-02-18T17:22:23.6768437+01:00",

#

The first "surprising" difference:

looking at: "assemblyName": "Test1-1" / "location"

autosave:
"inclination": 0.40300352700320846,
"eccentricity": 0.0001202326096178923,
"semiMajorAxis": 1118449.264075554,
"longitudeOfAscendingNode": 121.97906451938974,
"argumentOfPeriapsis": 115.90364913209123,
"meanAnomalyAtEpoch": 0.402766404669801,
"epoch": 5225.8964749889838
quicksave:
"inclination": 0.40300380668487523,
"eccentricity": 0.00011957392461973344,
"semiMajorAxis": 1118448.4274033685,
"longitudeOfAscendingNode": 121.97901579440963,
"argumentOfPeriapsis": 116.16837580409006,
"meanAnomalyAtEpoch": -0.05083948250430461,
"epoch": 4943.296481305586

The values are close, but they should be identical, right, you did not burn any engines?

Continuing my search

#

same for vessel Test1-3

#

Ok, after a long diff of both savefiles, there are lots of "innocent" differences, simply because you had another vessel active, or because you are on a later UT which changes all local coordinates. All these innocent differences make the diff a bit less efficient to scan through. The only "surprising" difference I found was the fact that the vessels have slightly different orbits in the autosave

#

maybe the difference is just that, the UT

west slate
# wind mica Possible theories: (a) This is a subtle coding technique I'm not (yet) savvy eno...

Hi @wind mica ! I have my two cents here, not sure if this could be helpful but I’ll say it, feel free to ignore me: I think i’m this case the game is calculating the “final” global position by “summing” the body position relative to its parent, but if the parent body is revolving another body it needs to calculate the relative position again and so on; so in the ends it’s Position relative to Kerbol + Position relative to Kerbin + Position relative mun for example

west slate
wind mica
# west slate Hi <@402620630585049088> ! I have my two cents here, not sure if this could be h...

Thanks! I had a similar thought myself, though it was more along the lines that perhaps KS2 approaches it this way and the recursion - if this is what's going on - is just the way it happens to arrive at the answer it needs. That said, why then would some maneuvers be consistently quite good and some so far off? I've yet to find a case where Moon Return from Mun to Kerbin doesn't give excellent results, though I've only done them from fairly low inclination, low eccentricity starting orbits. A Moon Return from Ike is the same, and at every single body orbiting Jool you can get a reasonably good result - at least not something that sends you off in some wacky direction.

#

That said, at Gilly or Minmus we can't get even a tolerable result - the time is way off.

#

So, perhaps it's about chasing the coordinate frame back to Kerbol, but why bad at Gilly and Minmus, but Great to good in other places?

#

If I can sort out what KS2 is doing - if it is recusrsion, then I could at least give that a shot in FP to see if it makes a difference.

outer valve
#

Please let me know how I can help. I've installed unity, but I'm afraid I need some help getting to where I can debug the code. I did manage to find a somewhat pathological case, where asking for a moon return on Gilly takes about 1min and then borks out, maybe this case provides some info.

I've tried moon returns from many different UT's, as I'm suspecting that some of the computations may work in different "quadrants" but Gilly never seems to work.

#

The one thing Minimus and Gilly have in common is that they have inclined orbits, maybe some z vector is upsidedown

#

If you add a "return to kerbol" option to other bodies, I can test Eeloo, the "return from moon" code must work to get from a CB to kerbol, right?

#

Found something else, switching the "target" from Eve to Kerbin changes the retrun from moon orbit, this definately should not happen, right?

#

This line is attracting my attention:
[Warning:Flight Plan] PlanetaryXfer: Recommend starting interplanetary transfers from Gilly from an orbit in the same plane as Gilly's orbit around Eve. Starting orbit around Gilly is inclined 12.0º with respect to Gilly's orbit around Eve (recommend < 10º). Planned transfer may not intercept target properly.

#

perhaps the inclination triggers a different code path, and the bug is in that codepath

wind mica
wind mica
# outer valve This line is attracting my attention: `[Warning:Flight Plan] PlanetaryXfer: Rec...

The inclination doesn't change the control flow - the same code is executed regardless. That warning is copied from the same warning that MJ has historically had for many years now. It's interesting that MJ gives good results at Minmus and Gilly where FP does not - despite their both having the same code for this part - or as "same" as I've been able to make it. Also, in the course of developing FP I've employed now three different versions of MJ code. There was the non-dev branch I started from more than a year ago. There was an update to align with what MJ was doing last fall (October IIRC), and then there was the most recent MJ alignment. In each of these the code for how MJ did Hohmann transfers and moon return changed in slight ways, so we've really had three separate tests of this. For sure this problem has been present since the alignment last fall. I'm unable to test the earlier versions without rolling KSP and SpaceWarp and FP all back to much earlier versions (like KSP 0.1.2 or something).
I think the poor results hinted at by MJ have to do with not necessarily getting the Pe you want at the planet you're transferring to.

wind mica
# outer valve Found something else, switching the "target" from Eve to Kerbin changes the retr...

Oh that's funny! So apparently FP tests to make sure you're at a moon, and that you're targeting a planet, but it's just fine with things for any moon/planet combination and will therefore allow nonsense settings like this. It should be simple enough to place a guard on this so that it doesn't allow the node to be made unless you're targeting the planet that the moon you're orbiting is in orbit about.

wind mica
#

#🔴tools-and-resources message

#

There's a Gist for setting up debug. It was written for KSP1, but if you're using the right version of Unity Editor then it works the same for KSP2. It's really quite awesome!

outer valve
#

Ill have a look at the gist, perhaps I can be of some actual help.

wind mica
#

@grizzled vale what do I need to do to make a nuget package with FP? It doesn't seem to be making them. I found that NodeManager had a nuget folder and nuget.config and Package.nuspec files at the root level in that mod's folder, so I copied those to FP's folder and changed the Package.nuspec to reference the FlightPlan license, but other than that I don't know what to do.

#

It doesn't seem to bea difference in the csproj or scripts

grizzled vale
#

and you're building in Release configuration?

wind mica
#

Yep, just built Release

#

Do I need to make a nuget folder for it, or will it make one if there isn't one?

#

I didn't see any errors in the build results

grizzled vale
#

oh, I see

#

looking at your project, you're not using the library template

#

so nuget building is not defined at all

wind mica
#

Sounds like I'll need to do some more work with FP and MNC then to convert them over to the library template

wind mica
#

Then I halfway did it. I already copied and modified the Package.nuspec from nodemanager. I'll go do that with Directory.Build.targets and see if that doesn't get me on my way. Thx!

#

Interesting though. NodeManager has a Directory.Build.props file, but I don't see a Directory.Build.targets...

grizzled vale
#

it's in the project folder

#

not in the root

wind mica
#

Oh, looking in the wrong place then! Thanks!

#

FP already has one of those, I'll compare it's content to that of NM and see what my FP version may be missing

#

Well, right off the top the NM version had these two lines that FP's did not

        <NuGetExecutable Condition="'$(OS)' == 'Windows_NT'">nuget</NuGetExecutable>
        <NuGetExecutable Condition="'$(OS)' != 'Windows_NT'">mono /usr/local/bin/nuget.exe</NuGetExecutable>
grizzled vale
#

that, plus the tasks about nuget

#

it's all commented so it should be fairly easy

wind mica
#

However FP's version also has a bunch of hard coded stuff where NM's has parameterized stuff like this

#

Makes me wonder if I shouldn't be doing more to align FP's version with NM's

grizzled vale
#

yeah I think I just did FP like that at first, and then later when I was doing NM, I realized it'd be better to create properties for the stuff so it isn't hardcoded

#

that means you'll have to create the appropriate properties in the Directory.Build.props file most likely

wind mica
#

I found this difference you alerted me to for nuget

        <!-- Packing NuGet package -->
        <Message Text="Copying plugin DLLs and XMLs to temporary folder for NuGet packing" Condition="$(ConfigurationName) == Release"/>
        <MakeDir Condition="$(ConfigurationName) == Release"
                 Directories="$(SolutionDir)/temp_nuget"/>
        <ItemGroup Label="Plugin XMLs to be copied">
            <PluginXMLs Include="$(PluginBinPath)/**/*.xml"/>
        </ItemGroup>
        <Copy Condition="$(ConfigurationName) == Release"
              SourceFiles="@(PluginDLLs)"
              DestinationFolder="$(SolutionDir)/temp_nuget"/>
        <Copy Condition="$(ConfigurationName) == Release"
              SourceFiles="@(PluginXMLs)"
              DestinationFolder="$(SolutionDir)/temp_nuget"/>

        <Message Text="Packing NuGet package" Condition="$(ConfigurationName) == Release"/>
        <Exec Condition="$(ConfigurationName) == Release"
              Command="$(NuGetExecutable) pack &quot;$(SolutionDir)/Package.nuspec&quot; -OutputDirectory &quot;$(SolutionDir)/nuget&quot; -Properties &quot;NoWarn=NU5125;id=$(ProjectName);version=$(Version);authors=$(Authors);description=$(Description);repositoryType=$(RepositoryType);repositoryUrl=$(RepositoryUrl)&quot;" />

        <Message Text="Removing temporary folder" Condition="$(ConfigurationName) == Release"/>
        <RemoveDir Condition="$(ConfigurationName) == Release"
                   Directories="$(SolutionDir)/temp_nuget"/>
#

But also this one

        <OnError ExecuteTargets="Cleanup"/>
    </Target>

    <!-- Clean up temporary folder if build fails -->
    <Target Name="Cleanup">
        <Message Text="Removing temporary folder if it exists"/>
        <RemoveDir Directories="$(SolutionDir)/temp_nuget"
                   Condition="Exists('$(SolutionDir)/temp_nuget')"/>
#

Oh wait, that second one is also nuget... duh

grizzled vale
#

yep, both are for nuget building/cleanup

wind mica
#

This is the only difference I see in Directory.Build.props

#

Should I replace what FP (left) has or add this as a new PropertyGroup?

grizzled vale
#

if you remove the stuff on the left, you'll also have to add a nuget.config file with the SpaceWarp nuget server

#

those two basically do the same thing

wind mica
#

Oh, I already did that

grizzled vale
#

then you can just replace it

wind mica
# grizzled vale then you can just replace it

Are things like $(AssemblyName) and $(SolutionName) already defined? Those weren't in the Directory.Build.props, but they are part of the differences in the Directory.Build.targets

grizzled vale
#

yes, those are pre-defined by MSBuild

#

(well, AssemblyName should be defined in your Directory.Build.props)

#

at least it is in the template

wind mica
#

OK, only two errors on trying to build. Apparently it's looking for the LICENSE file and I suspect I may need to pre-make an empty nuget folder

#

Yeah, NM has a LICENSE file where FP has a License.md file

#

Do I just need to change LICENSE to License.md here?

    <files>
        <file src="README.md" target="" />
        <file src="LICENSE" target="LICENSE" />
        <file src="temp_nuget\*.dll" target="lib/netstandard2.1/" />
        <file src="temp_nuget\*.xml" target="lib/netstandard2.1/" />
    </files>
#

Or is it like README.md where the target is ""?

grizzled vale
#

no need to make a nuget folder

#

it will do it

#

but yes, you need to change the src to your license filename

wind mica
#

Voila!

#

I suppose I need to do the same now with MNC

grizzled vale
#

most likely

wind mica
#

Should be easy now!

grizzled vale
wind mica
#

Well, I picked up MNC from earlier work, but the differences between FP and NM are all me.

grizzled vale
wind mica
#

For this block, should I understand target="" to mean that it doesn't place the file there?

    <files>
        <file src="README.md" target="" />
        <file src="LICENSE.md" target="LICENSE.md" />
        <file src="temp_nuget\*.dll" target="lib/netstandard2.1/" />
        <file src="temp_nuget\*.xml" target="lib/netstandard2.1/" />
    </files>```
#

What does target="" do?

grizzled vale
#

it means it won't rename the file and it will simply put it into the root folder

wind mica
#

Should I be renameing this file? Or does it not matter much?

grizzled vale
#

it doesn't

wind mica
#

I found a possible booboo in the FP Package.nuspec where the licenseUrl was broken. I fixed that and regenerated the nuget package just to be on the safe side.

#

Other than an update to the licenseUrl no difference. Not sure if that will matter, but I don't want to cause cahos down the road because of it

tulip quarry
#

@wind mica I've added the K2-D2 API back but I can't see the K2-D2 button in FlightPlan

#

in the log i've got only :

[Info   :FlightPlanPlugin.OtherModsInterface] K2D2_Plugin.ModGuid = com.github.cfloutier.k2d2
[Info   :FlightPlanPlugin.OtherModsInterface] _k2d2Loaded = False
#

as I use now the @grizzled vale template the ModGuid has a little changed

#

i'm trying to change it but i'm a bit lost

#

The assembly name is now defined with the same name as the MOD : K2D2

#

so changing it will lead to changing the target directory

grizzled vale
#

oh right you have the same thing as schlosrat where the project name =/= the assembly name =/= the folder name =/= the mod ID

tulip quarry
#

yes

#

perhaps I can change it by and to got back to com.github.cfloutier.k2d2 in the Directory.Build.props

grizzled vale
#

if you only want to change the mod ID, that's done in swinfo

#

and nothing else needs to be changed

tulip quarry
#

the mod ID is unchanged = K2D2

grizzled vale
#

but it used to be com.github.cfloutier.k2d2

#

so you can go to swinfo.json and change it back to that

#

to have Flight Plan recognize the mod

tulip quarry
#

here is the previous swininfo.json

#
{
    "mod_id": "K2D2",
    "author": "cfloutier",
    "name": "K2-D2",
    "description": "The KSP astromech",
    "source": "https://github.com/schlosrat/k2d2",
    "version": "0.12.3",
    "version_check": "",
    "dependencies": [{
        "id": "SpaceWarp",
        "version": {
            "min": "1.5.2",
            "max": "*"
        }
    }],
    "ksp2_version": {
        "min": "0.2.0",
        "max": "*"
    }
}```
#

the mod id was K2D2

grizzled vale
#

yes, in the very early versions of SpaceWarp, you could have a different SpaceWarp mod_id and BepInEx GUID

#

now you can't

tulip quarry
#

ok

grizzled vale
#

and since Flight Plan is checking the BepInEx GUID, it makes more sense to just continue using com.github.cfloutier.k2d2

tulip quarry
#

the my new mod_id should be com.github.cfloutier.k2d2... ok i change that

#

but isn't it also the way it is identified by... ckan or Spacedock ?

#
{
  "spec": "2.0",
  "mod_id":" com.github.cfloutier.k2d2",
  "author": "Christophe Floutier",
  "name": "K2-D2",
  "description": "",
  "source": "",
  "version": "1.0.0",
  "version_check": "",
  "ksp2_version": {
    "min": "0.2.0",
    "max": "*"
  },
  "dependencies": [
    {
      "id": "com.github.x606.spacewarp",
      "version": {
        "min": "1.8.0",
        "max": "*"
      }
    }
  ]
}

#

I should also add uitk as a dependency

grizzled vale
tulip quarry
#

ok then I've got progress, the butoon is visible in FlightPlan

#

but I've got a null pointer exception from FlightPlan

#

in : "FlightPlan.FpUiController.K2D2"

#

I think that from K2D2 side the Api have not changed. but I could have made a mistake

#

here is a preview version @wind mica If you have time to test what is wrong

grizzled vale
#

FP expects the plugin class to be named K2D2_Plugin but it's now K2D2Plugin

#

I also don't see any "ToggleAppBarButton" method in the new plugin class

tulip quarry
#

thanks

#

but I've got an appbar button

#
        // Register Flight AppBar button
        Appbar.RegisterAppButton(
            ModName,
            ToolbarFlightButtonID,
            AssetManager.GetAsset<Texture2D>($"{ModGuid}/images/icon.png"),
            isOpen => main_window.IsWindowOpen = isOpen
        );

grizzled vale
#

no what I mean is that schlosrat's code calls a method named "ToggleAppBarButton" that you used to have in your plugin class, now it doesn't exist

#

so that will cause another error

#

ahh nevermind, that is there for compatibility with old K2D2 versions

tulip quarry
#

.... hum you're right but I've still have the same error.

#

I don't know what's cause it.

tulip quarry
#

I'm currently debugging it in FlightPlan code

#

i'm a bit lost ...

#

K2D2Type = Type.GetType($"K2D2.K2D2_Plugin, {K2D2ModGuid}");

#

return null

#

but my namespace and plugin name have not changed