Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

It looks to me, on a quick cursory glance, that you're trying to set the position of the line the same way twice, thus making it have the translation offset twice over rather than once over.

See these two lines:

There's two approaches to take:

1 - Give the line object a transformation matrix that describes a local frame of reference in which the origin point is zero'ed at what what the world coordinates would call mapFarPos.

2 - Use the coordinates raw without a local transform, and tell the line to draw from mapFarPos.

It looks like you're trying to do both, which essentially offsets the origin point twice over.

I tried messing with that, but it doesn't seem to have solved the issue. The lines are, if anything, even more offset than previously. Entirely possible that I'm doing it wrong, though.

Link to comment
Share on other sites

Hello! I've got the list of maneuver nodes from patchedConicSolver and I want to determine which one is currently selected for editing on the map view. How can I do this?

Edited by orven
Link to comment
Share on other sites

I tried messing with that, but it doesn't seem to have solved the issue. The lines are, if anything, even more offset than previously. Entirely possible that I'm doing it wrong, though.

It's entirely possible there's more than one thing wrong at the same time. But trying to both set a local transform to move you to mapFarPos while at the *same time* trying to tell the line to draw itself starting at mapFarPos is definitely a part of what's wrong. No successful solution will be doing both at once. Either you transform to mapFarPos and then start drawing at 0,0,0 - or you don't transform to mapFarPos and then start drawing at mapFarPos. You definitely don't try to do both.

Link to comment
Share on other sites

Alright.

I'm doing what I think would be a simple adding a value to a confignode, but it's going sideways on my and I'm missing something.

In english, I'm trying to do this:

Given ConfigNode Node1 that may or may not have a value Value1, set Value1 to equal text string Test1. If Node1 does not currently have Value1, add it. If Node1 already has Value1, set it to be Test1

Looking at the object browser, I would think ConfigNode.SetValue is what would do this but it does not. I'm actually not sure what .SetValue does, on my experiments the results were never quite what I expected so I believe I'm missing something basic to how .SetNode works.

Rather, right now I have to do this for every value I want to set:


ConfigNode Node1 = new ConfigNode();

//run code here which means I don't know if Value1 exists on Node1 or not

if(Node1.hasValue("Value1")
{
Node1.removeValue("Value1");
}
Node1.addValue("Value1");

I'm 99% sure I should be able to use the following somehow to reduce those 5 lines of code to 1 line:

Node1.SetValue("Value1","Test1");

but I can not for the life of me get it to work.

Anyone know what's going on here?

D.

Link to comment
Share on other sites

I'm 99% sure I should be able to use the following somehow to reduce those 5 lines of code to 1 line:

Node1.SetValue("Value1","Test1");

I was caught by the same thing. SetValue seems to modify existing values only, so I think the simplest you can make it is something like this:

if (!node.SetValue("name", "value")) node.AddValue("name", "value");

Link to comment
Share on other sites

Hrm.

So, the 'better' way then would be to make a constructor method, so that rather then going

ConfigNode Node1 = new ConfigNode("NODE");

I use


public static ConfigNode myNewNode(string NodeType)
{
ConfigNode newNode = new ConfigNode(NodeType);
newNode.addValue("Value1","DefaultValueA");
newNode.addValue("Value2","DefaultValueB");
}

//then back in my main code

ConfigNode Node1 = myNewNode("NODE");

That way I know the values exist and I can just use .SetNode without having to check if the value exists or not.

Too late now for my current mods, but I'll try to remember to test that out on any future ones.

D.

Link to comment
Share on other sites

It's a good candidate for an extension method also:

public static class ConfigNodeExtensions
{
public static void Set(this ConfigNode node, string valueName, string value)
{
if (!node.SetValue(valueName, value)) node.SetValue(valueName, value);
}
}

Node1.Set("Value1","Test1");

I have a set of source files shared between my projects for little fixes and snippets like this

Link to comment
Share on other sites

It's entirely possible there's more than one thing wrong at the same time. But trying to both set a local transform to move you to mapFarPos while at the *same time* trying to tell the line to draw itself starting at mapFarPos is definitely a part of what's wrong. No successful solution will be doing both at once. Either you transform to mapFarPos and then start drawing at 0,0,0 - or you don't transform to mapFarPos and then start drawing at mapFarPos. You definitely don't try to do both.

Fixed it up! Here's the solution, so it's documented if anyone finds this while googling.

  • The LineRenderer needs useWorldSpace = false.
  • The parent transform of the LR object was set to the matching ScaledSpace tranform (in ScaledSpace.Instance.scaledSpaceTransforms) rather than the MapObject. Not sure how necessary this was, but it's working fine.
  • The transform position for the LR was set to the scaled conversion of the origin target's position, using .position rather than .localPosition.
  • The exit vector was run through .xzy to correct the z/y swap.

Here's the final working snippet:

// Directional indicator.
oDirObj = new GameObject("Indicator");
oDirObj.layer = 10; // Map layer!
oDirection = oDirObj.AddComponent<LineRenderer>();
oDirection.useWorldSpace = false;
oOrigin = null; // oOrigin is a Transform.
foreach (Transform sstr in ScaledSpace.Instance.scaledSpaceTransforms)
{
if (sstr.name == far.mainBody.name) // far is a Vessel.
{
oOrigin = sstr;
break;
}
}
oDirection.transform.parent = oOrigin;
oDirection.transform.position = ScaledSpace.LocalToScaledSpace(far.transform.position);
oDirection.material = new Material(Shader.Find("Particles/Additive"));
oDirection.SetColors(Color.clear, Color.red);
oDirection.SetWidth(20.0f, 0.01f);
oDirection.SetVertexCount(2);
oDirection.SetPosition(0, Vector3d.zero + exitTraj.xzy.normalized * 10); // exitTraj is a Vector3d.
oDirection.SetPosition(1, exitTraj.xzy.normalized * 50);
oDirection.enabled = true;

Link to comment
Share on other sites


oDirection.SetPosition(0, Vector3d.zero + exitTraj.xzy.normalized * 10); // exitTraj is a Vector3d.
oDirection.SetPosition(1, exitTraj.xzy.normalized * 50);

Is there some reason you're offsetting the tail of the vector so it's not touching the 'far' vessel? (Why draw from the magnitude*10 to the magnitude*50 rather than from 0 to magnitude*50?)

Oh, and thanks for pointing out the existence of the .xzy property. I didn't know that was a thing so I always had to mess around with swapping the axes manually (why in the heck dis squad swap the axes anyway in some cases that I'll never know).

It might be a good idea to test in cases where the orbit is highly inclined just to make sure the axis swapping is correct and necessary. I don't recall having to swap axes for map view - only for dealing with the planet surface with things like your body-relative position.

Link to comment
Share on other sites

Is there some reason you're offsetting the tail of the vector so it's not touching the 'far' vessel? (Why draw from the magnitude*10 to the magnitude*50 rather than from 0 to magnitude*50?)

Oh, and thanks for pointing out the existence of the .xzy property. I didn't know that was a thing so I always had to mess around with swapping the axes manually (why in the heck dis squad swap the axes anyway in some cases that I'll never know).

It might be a good idea to test in cases where the orbit is highly inclined just to make sure the axis swapping is correct and necessary. I don't recall having to swap axes for map view - only for dealing with the planet surface with things like your body-relative position.

Trust me, the axis swapping is necessary in all cases. I couldn't find a situation where it was helpful not to do it. It only applies to values derived from or input to the Orbit class, though - you'll note that I could skip the coordinate swapping for far.transform.position, but not for exitTraj (which is derived from several Vessel and Celestialbody orbit.vel values).

The line is actually a triangular marker that serves to indicate the direction of travel along the orbit I'm projecting. The resulting drawing looks like this: https://i.imgur.com/QRNsyEs.png

I'm offsetting the marker so it doesn't overlap the icon for the ship I'm using as the origin point.

Link to comment
Share on other sites

These two statements back to back seem somewhat contradictory and confusing:

Trust me, the axis swapping is necessary in all cases.
It only applies to values derived from or input to the Orbit class, though - you'll note that I could skip the coordinate swapping for far.transform.position

I'm pretty sure the second statement is true, but not the first. I've never had to swap them when dealing with the vessel's position or velocity *now* - only for the methods that perform predictions about its future (like the orbit path), and interactions with the PQS solver.

Link to comment
Share on other sites

Greetings!

I am having a small issue with HigherLogic.LoadedScene.

I want to make sure that my plugin does not function while the EDITOR is open (Well, and the SPH for that matter, but one at a time). Here is the code. The plugin continues to drain fuel even when in the VAB, so I know it is at least executing past the first IF. Reversing this and putting the code in an ELSE statement, also does not work.


void FixedUpdate()
{
if (HighLogic.LoadedScene != GameScenes.EDITOR)
{

if(isActive)
{
float offsetMass = part.GetResourceMass();
float calcedECLoss = (chargeRate * TimeWarp.fixedDeltaTime * offsetMass * 2.0f);
float chargeLoss = part.RequestResource("ElectricCharge", calcedECLoss);

//print("NEAR Fuels!! chargeLoss: " + chargeLoss);
}
else
{


float boilOffOne = (rateOneRate * TimeWarp.fixedDeltaTime * part.mass);
float boilOne = part.RequestResource(resourceOneName, boilOffOne);

float boilOffTwo = (2.0f * rateTwoRate * TimeWarp.fixedDeltaTime * part.mass);
float boilTwo = part.RequestResource(resourceTwoName, boilOffTwo);

//print("NEAR Fuels!! chargeLoss: " + boilOne);
//print("NEAR Fuels!! chargeLoss: " + boilTwo);
}
}
}
}

Does anyone have any suggestion about how to proceed?

Edited by saabstory88
Clarity
Link to comment
Share on other sites

I've been working for the last few days on a partmodule to allow for kerbal suspended animation (essentially by unloading the crew members from the vessel and re-adding them later at the behest of the player). So far I think I've got my bases covered for the most part, but the screaming big hole in the process of managing these right now is vessel recovery. Since the kerbals are no longer part of the protovessel; they aren't readded to the roster the way active crew are. I tried override OnInactive, which works well for part distruction, but it doesn't load on vessel recovery.

Is there a way for me to tap into whatever event KSP uses for vessel recovery, read my variable out of the partmodule, and then set the protocrewmember status myself? I've been looking around at other mod's code to look for an approach on this, but so far haven't found anything that looks like it'll do what I need to do.

Edit: The more I ruminate on it, I think I'm going to have to come up with some different solution for vessels on rails.

Edited by scottpaladin
Link to comment
Share on other sites

Is there a way for me to tap into whatever event KSP uses for vessel recovery, read my variable out of the partmodule, and then set the protocrewmember status myself? I've been looking around at other mod's code to look for an approach on this, but so far haven't found anything that looks like it'll do what I need to do.

Have you tried GameEvents.OnVesselRecoveryRequested or GameEvents.OnVesselRecovered? That's where I'd start

Greetings!

I am having a small issue with HigherLogic.LoadedScene.

I want to make sure that my plugin does not function while the EDITOR is open (Well, and the SPH for that matter, but one at a time). Here is the code. The plugin continues to drain fuel even when in the VAB, so I know it is at least executing past the first IF.

You might need to post more code. Nothing jumps out at me, although your if statement could be simplified with HighLogic.LoadedSceneIsEditor which will return true if the player is in the VAB or SPH

Link to comment
Share on other sites

Have you tried GameEvents.OnVesselRecoveryRequested or GameEvents.OnVesselRecovered? That's where I'd start

You might need to post more code. Nothing jumps out at me, although your if statement could be simplified with HighLogic.LoadedSceneIsEditor which will return true if the player is in the VAB or SPH

I should have posted back sooner. Without changing anything, a recompile solved the issue. I don't know what happened. Would love to know what the issue was. Also, thank you very much for the simplified code, I will attempt to implement this immediately.

Link to comment
Share on other sites

Sorry to be such a Noob but I am new to mod development, can I ask a couple of quick questions....

- Since my mod classes get created and destroyed at various times (i.e. scene changes) how do I create variable that persist between the scene changes?

- What are the main classes I should explore (using Visual Studio Object Browser) to learn how to interact with the game?

- What is the best way to access the KSP filesystem -- using standard C# functions or some built-in functions?

Thanks in advance,

Link to comment
Share on other sites

Hello, i begin in modding on KSP and i search a function/variable to disable the recovery possibility of a vessel (or all vessel ...) ? Thanks.

That ok, i've found how to do this ... i've search a long time for a little answer ;)

FlightGlobals.ActiveVessel.Landed = false;
FlightGlobals.ActiveVessel.Splashed = false;

Don't know, if there is a better solution, but that work ;)

Link to comment
Share on other sites

I'd seen OnVesselRecovered but not OnVesselRecoveryRequested, that sounds much more promising. Thanks.

OnVesselRecoveryRequested happens during the flight scene when you push the green recovery button. OnVesselRecovered happens after the R&D center does all of its processing on the vessel's science and part values.

OnVesselRecoveryProcessing is what you want. The problem is that this is also when the R&D center does its thing (the crew stuff might happen elsewhere, but I'm pretty sure the MissionRecoveryDialog must pass through the R&D center at some point); I'm not sure that there is any way to force your code to run before the R&D center's code, so it will be tricky to get your stuff to be counted in the mission recovery dialog.

You can, of course, reset the frozen Kerbals' status manually so that they will be available for the next mission, but they probably won't show up in the dialog, and you would have to manually add in rep for successfully recovering them (you might also need to watch out for losing rep when you set your Kerbals to "dead").

Edit: The crew recovery stuff probably happens in the Reputation scenario module, which is also where you can manually add in more rep.

Edited by DMagic
Link to comment
Share on other sites

That ok, i've found how to do this ... i've search a long time for a little answer ;)

FlightGlobals.ActiveVessel.Landed = false;
FlightGlobals.ActiveVessel.Splashed = false;

Don't know, if there is a better solution, but that work ;)

Wait, you are setting those booleans false to disable recovery? (I see a =, not a == in your code)

Please don't do this, those booleans are used to see if a vessel is landed. (or splashed if in water) At the very least this will cause issues with two of my mods and I imagine there a several other mods out there that also use those to see if a vessel is landed or not that this will mess up.

This is the sort of thing that causes mod conflicts and leads to headaches trying to track down what is happening.

FlightGlobals.ActiveVessel.Landed being false when the vessel is actually landed is wrong.

D.

Link to comment
Share on other sites

You mean a .cfg file on disk?

TWR1Node = ConfigNode.Load(KSPUtil.ApplicationRootPath + "GameData/Diazo/TWR1/TWR1.cfg"); 

This loads the TWR1.cfg file from my mod directory in GameData into the TWR1Node ConfigNode.

Note that the file must exist and cannot be empty. Trying to load an empty file this way will throw and error and TWR1Node will be null.

D.

Link to comment
Share on other sites

Wait, you are setting those booleans false to disable recovery? (I see a =, not a == in your code)

Please don't do this, those booleans are used to see if a vessel is landed. (or splashed if in water) At the very least this will cause issues with two of my mods and I imagine there a several other mods out there that also use those to see if a vessel is landed or not that this will mess up.

This is the sort of thing that causes mod conflicts and leads to headaches trying to track down what is happening.

FlightGlobals.ActiveVessel.Landed being false when the vessel is actually landed is wrong.

D.

Hum, thanks for your answer, i will search an other (better) solution ... but before to post here, i passed a long time to read the assembly-csharp to find how to disable recovery without success :'(

Link to comment
Share on other sites

Join the conversation

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

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

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

×   Your previous content has been restored.   Clear editor

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

×
×
  • Create New...