Cephei

The official unoffical "help a fellow plugin developer" thread

Recommended Posts

6 hours ago, CrayzeeMonkey said:

Is there an elegant way to disable collisions for an entire vessel? Just setting the rigidbody detectCollisions false on all the parts of a vessel seems problematic (nullrefs are thrown).

I'm using this, when moving vessels up/down through terrain:

// Vessel v
v.ResetCollisionIgnores();

// execution code here

v.ResetGroundContact();
v.IgnoreGForces(20);
v.SetWorldVelocity(Vector3.zero);
v.angularMomentum = Vector3.zero;
v.angularVelocity = Vector3.zero;
VesselSleep(v);

-------------------------------------
  
private static void VesselSleep(Vessel v)
{
  foreach (Part p in v.parts)
  {
    if (p.Rigidbody != null)
      p.Rigidbody.Sleep();
  }
}

 

Share this post


Link to post
Share on other sites

Hi, I'm trying to control my rover. I'm able to make it drive straight forward by modifying the wheelThrottleTrim and pitchTrim fields from Vessel.ctrlState. However, I couldn't get the rover to steer by modifying the wheelSteerTrim and yawTrim fields.

void Update()
{
  FlightCtrlState vesselCtrl = FlightGlobals.ActiveVessel.ctrlState;

  vesselCtrl.wheelThrottleTrim = this.Drive;
  vesselCtrl.pitchTrim = this.Drive;

  vesselCtrl.wheelSteerTrim = -1f*this.Steer;
  vesselCtrl.yawTrim = this.Steer;
}

The Steer property is modified by some button listeners, and gets the value -1f if steering left and 1f if steering right. The sign of wheelSteerTrim field is inverted, because the steer direction of my wheels are also set to inverted (this is the way it would be if I gave user input and observed the ctrlState object through a debugger).

Also, here's a picture of a the rover I'm using to test my  mod:

e5q3ptr.png

So the problem is: I can't steer the wheels through an instance of the FlightCtrlState class. Am I missing something here?

Edited by Hydrawx

Share this post


Link to post
Share on other sites
8 hours ago, Hydrawx said:

Hi, I'm trying to control my rover. I'm able to make it drive straight forward by modifying the wheelThrottleTrim and pitchTrim fields from Vessel.ctrlState. However, I couldn't get the rover to steer by modifying the wheelSteerTrim and yawTrim fields.


void Update()
{
  FlightCtrlState vesselCtrl = FlightGlobals.ActiveVessel.ctrlState;

  vesselCtrl.wheelThrottleTrim = this.Drive;
  vesselCtrl.pitchTrim = this.Drive;

  vesselCtrl.wheelSteerTrim = -1f*this.Steer;
  vesselCtrl.yawTrim = this.Steer;
}

The Steer property is modified by some button listeners, and gets the value -1f if steering left and 1f if steering right. The sign of wheelSteerTrim field is inverted, because the steer direction of my wheels are also set to inverted (this is the way it would be if I gave user input and observed the ctrlState object through a debugger).

Also, here's a picture of a the rover I'm using to test my  mod:

[snip]

So the problem is: I can't steer the wheels through an instance of the FlightCtrlState class. Am I missing something here?

I think your problem might be that you've made a copy of ctrlState. I have code which modifies the ctrlState directly, without copying it to a new variable, which behaves itself.

  • Like 1

Share this post


Link to post
Share on other sites
8 hours ago, 0111narwhalz said:

I think your problem might be that you've made a copy of ctrlState. I have code which modifies the ctrlState directly, without copying it to a new variable, which behaves itself.

Thank you for your answer! I thought C# only implicitly copied the reference to that object. Also the wheelThrottleTrim and pitchTrim do behave like expected, but if accessing the ctrlState directly through the vessel works for you, then I will try this as well later on.

Edit: tried it, still doesn't work. As I thought, it's not the reference to the object that is the problem here, because I can observe it through a debugger and I can clearly see that the right object is modified. However, there is still something you're doing right which I am not. Does your code also handle the steering of the wheels? If so, could you show me the part of your code where you control the wheels? It would be greatly appreciated.

Edit 2: Somehow wheelSteerTrim doesn't get registered and wheelThrottleTrim does:

qHcIlcd.png

I made sure to use wheels that are steerable and I also checked if the steering was enabled for those wheels.

Edited by Hydrawx

Share this post


Link to post
Share on other sites
9 hours ago, Hydrawx said:

Does your code also handle the steering of the wheels? If so, could you show me the part of your code where you control the wheels? It would be greatly appreciated.

It should be noted at this point that my code is a few KSP versions old by now, but this bit probably shouldn't have changed.

public void Update(Vessel ves, NeuralNetwork nn)
{
	ves.ctrlState.wheelSteer = nn.nodeValues[nn.nodeValues.Length - 1][0];
	ves.ctrlState.wheelThrottle = nn.nodeValues[nn.nodeValues.Length - 1][1];
}

The nn stuff just ends up being a float between -1 and 1.

  • Like 1

Share this post


Link to post
Share on other sites
21 hours ago, Hydrawx said:

Thanks, I appreciate it. Still no luck though.. odd..

You need to use the callbacks to control the vessel or you will fight with the stock code (and other mods).

Somewhere in your OnStart

public override void OnStart(PartModule.StartState state)
{
	if (vessel != null)
	{
		vessel.OnFlyByWire += MyControlMethod; 
		// or OnPreAutopilotUpdate / OnAutopilotUpdate / OnPostAutopilotUpdate depending on how soon/late you want to do it in the controls orders
	}	
}

Make sure you have a OnDestroy

void OnDestroy()
{
    if (vessel != null)
    {
        vessel.OnFlyByWire -= MyControlMethod;
    }
}

And somewhere else

private void MyControlMethod(FlightCtrlState s)
{
    s.wheelSteer = 0.5
}

 

 

 

  • Like 1

Share this post


Link to post
Share on other sites
12 minutes ago, sarbian said:

You need to use the callbacks to control the vessel or you will fight with the stock code (and other mods).

Excellent! That's exactly what I needed! Thank you!

Edited by Hydrawx

Share this post


Link to post
Share on other sites

I'm new to KSP modding, and am trying to figure out what is the best way for one component to talk to another.  Mainly I've been following the example from @RoverDude's mods, which look to be the most polished of the code I've seen (and as a result, easiest to follow).  But even within his mods there's variance.  Maybe there's a rhythm to it?  Maybe it's just some is older/comes from different  sources?  Anyway, one method is this:

public class LifeSupportScenario : ScenarioModule
{

        public LifeSupportScenario()
   {
       Instance = this;
   }

   public static LifeSupportScenario Instance { get; private set; }

And the other is

public class LifeSupportManager : MonoBehaviour
{
    // Static singleton instance
    private static LifeSupportManager instance;

    // Static singleton property
    public static LifeSupportManager Instance
    {
        get { return instance ?? (instance = new GameObject("LifeSupportManager").AddComponent<LifeSupportManager>()); }
    }

 

(And if anybody cares, that implementation could be made a little nicer with .net's 'Lazy' class).

Unity does a lot of reflecto-magic with classes, and I, at one point, thought that the static instance object got some of this love.  I'm not finding any clear evidence of it in the Unity docs, but that could be because my search-fu on Unity stuff is not all it could be.

Share this post


Link to post
Share on other sites
On 12/23/2018 at 10:33 PM, NermNermNerm said:

I'm new to KSP modding, and am trying to figure out what is the best way for one component to talk to another

I don't know if this is the BEST way to do it, but this is the way I do it, because it's simple when writing the code. 

I make a static instance of the class I want to access, and assign it in Awake() (assuming the class I want to talk to is a MonoBehaviour) then from my ScenarioModule I can then reference it by <MyClass.Instance>. Example of this below, look at FlightTracker and Stripes Data 

https://github.com/severedsolo/EarnYourStripes/tree/master/EarnYourStripes

Share this post


Link to post
Share on other sites
On 12/23/2018 at 11:33 PM, NermNermNerm said:

public static LifeSupportManager Instance
    {
        get { return instance ?? (instance = new GameObject("LifeSupportManager").AddComponent<LifeSupportManager>()); }
    }

KSP includes the KSPAddon annotation to do that and it provides far better control over the object life than this.

Share this post


Link to post
Share on other sites
5 hours ago, sarbian said:

KSP includes the KSPAddon annotation to do that and it provides far better control over the object life than this.

I'm not sure I understand what you mean here - [KSPAddOn]class foo does indeed control the lifetime of 'foo' - but what I'm asking for is how, if I'm in 'bar', can I get the correct instance of 'foo'.

Share this post


Link to post
Share on other sites
22 hours ago, NermNermNerm said:

I'm not sure I understand what you mean here - [KSPAddOn]class foo does indeed control the lifetime of 'foo' - but what I'm asking for is how, if I'm in 'bar', can I get the correct instance of 'foo'.

Use the method described by severedsolo, set the instance field in the Awake method (and remove it in OnDestroy, if needed). Then access it by using  public property that only returns the instance.

Sarbian was saying not to use AddComponent in the instance property as a method of creating the MonoBehaviour.

Edited by DMagic

Share this post


Link to post
Share on other sites

Is there a good way to detect a "Revert to launch"? Neither the ActiveVessel.id nor the SceneManager.GetActiveScene().buildIndex seem to change.

Share this post


Link to post
Share on other sites
On 12/31/2018 at 1:01 PM, c4ooo said:

Is there a good way to detect a "Revert to launch"? Neither the ActiveVessel.id nor the SceneManager.GetActiveScene().buildIndex seem to change.

This probably isn't "the" way, but it's "a" way:  you could look for a shift backwards in system time - Planetarium.GetUniversalTime()  -- I suspect that might also pick up on loading quicksaves, however...  But maybe that's a good thing for your scenario.

 

Share this post


Link to post
Share on other sites

I'm starting to get the hang of these PartModules - is there a stock part module that handles the notion that it takes a power-load to do its thing, and that the thing can be toggled on and off?

I could go with a Resource Converter, with just "Electric Charge" as an input and no outputs.  That seems like a good way to go, but it seems like this is probably a common need and there's something else out there like it.

Share this post


Link to post
Share on other sites
On 12/31/2018 at 4:01 PM, c4ooo said:

Is there a good way to detect a "Revert to launch"? Neither the ActiveVessel.id nor the SceneManager.GetActiveScene().buildIndex seem to change.

There’s a series of GameEvents that get fired when the scene loads. Maybe there’s a unique sequence or attached data for a revert?

https://kerbalspaceprogram.com/api/class_game_events.htm

 

Share this post


Link to post
Share on other sites

I know that ScreenMessages.PostScreenMessage is a thing - but I'd like something fancier, like the tutorial messages - where it's a full-on dialog with a picture of Wernher Von Kerman in the corner.  Anybody know how to do that?

Share this post


Link to post
Share on other sites
On 1/2/2019 at 11:21 PM, NermNermNerm said:

This probably isn't "the" way, but it's "a" way:  you could look for a shift backwards in system time - Planetarium.GetUniversalTime()  -- I suspect that might also pick up on loading quicksaves, however...  But maybe that's a good thing for your scenario.

 

Ha well- simple solution but it works; thanks!

Share this post


Link to post
Share on other sites
On 1/4/2019 at 12:18 PM, NermNermNerm said:

I know that ScreenMessages.PostScreenMessage is a thing - but I'd like something fancier, like the tutorial messages - where it's a full-on dialog with a picture of Wernher Von Kerman in the corner.  Anybody know how to do that?

The short version is that you have to use the TutorialScenario (there are some very old examples if you search github).

An alternative is to build your own dialog boxes using KerbalInstructor (that's what provides the picture).  This is what Contract Configurator does, although it uses the old GUI system and is...  overly complex.

Share this post


Link to post
Share on other sites

Hi all, apologies if this has been asked before, but is there some documentation/reference for KSP UI transforms? I want to make edits to certain panels but I feel like I'm fumbling around in the dark trying to guess what I need to be modifying.

A couple of examples of what I want to learn more about can be found in Strategia and MKS. They both do it slightly differently though: MKS has the exact path to hand apparently, whereas Strategia searches for a transform with the right name.

Any resources or help on this would be appreciated.

Share this post


Link to post
Share on other sites
13 minutes ago, Firex said:

Hi all, apologies if this has been asked before, but is there some documentation/reference for KSP UI transforms? I want to make edits to certain panels but I feel like I'm fumbling around in the dark trying to guess what I need to be modifying.

A couple of examples of what I want to learn more about can be found in Strategia and MKS. They both do it slightly differently though: MKS has the exact path to hand apparently, whereas Strategia searches for a transform with the right name.

Any resources or help on this would be appreciated.

Accessing specific UI prefabs, or any other type of prefab, is different for each one. There isn't really one database of prefabs. There are references to them held in various different types of controller MonoBehaviours, but the real trouble is finding exactly where they are stored, and how to access those controllers.

If all else fails when trying to get at a controller object you can use something like FindObjectOfType<ControllerType> to find any active instance of that type.

You can see MKS is using FindObjectOfType, whereas the prefab Strategia is looking for has a more accessible prefab. In both cases the real problem is finding where that prefab is stored. Sometimes it can be obvious by the name, like the Tracking Station Widget prefab (the thing that shows each vessel in the list) is held in SpaceTracking. Or the staging group icon prefab is held in StageManager.

You can use Debug Stuff in UI mode in some cases to help with this. A lot of the time the UI components are ultimately the child of whatever component is managing them, so that can help narrow it down.

Share this post


Link to post
Share on other sites
3 hours ago, DMagic said:

Accessing specific UI prefabs, or any other type of prefab, is different for each one. There isn't really one database of prefabs. There are references to them held in various different types of controller MonoBehaviours, but the real trouble is finding exactly where they are stored, and how to access those controllers.

If all else fails when trying to get at a controller object you can use something like FindObjectOfType<ControllerType> to find any active instance of that type.

You can see MKS is using FindObjectOfType, whereas the prefab Strategia is looking for has a more accessible prefab. In both cases the real problem is finding where that prefab is stored. Sometimes it can be obvious by the name, like the Tracking Station Widget prefab (the thing that shows each vessel in the list) is held in SpaceTracking. Or the staging group icon prefab is held in StageManager.

You can use Debug Stuff in UI mode in some cases to help with this. A lot of the time the UI components are ultimately the child of whatever component is managing them, so that can help narrow it down.

Thanks for showing me this DebugStuff, it's helping a lot. I am still kind of stuck though, as sometimes DebugStuff will show an object with "(Clone)" after it's name and I'm unable to access these like other things. I thought this might be just the case in certain areas of the UI (with there being a "root" object somewhere), but even using FindObjectType doesn't work.

I'm specifically trying to modify the currency widgets in the topbar of the SpaceCenter scene, and have so far successfully been able to remove the widget group as a whole, but I can't target each individual widget.

Share this post


Link to post
Share on other sites
12 hours ago, Firex said:

Thanks for showing me this DebugStuff, it's helping a lot. I am still kind of stuck though, as sometimes DebugStuff will show an object with "(Clone)" after it's name and I'm unable to access these like other things. I thought this might be just the case in certain areas of the UI (with there being a "root" object somewhere), but even using FindObjectType doesn't work.

I'm specifically trying to modify the currency widgets in the topbar of the SpaceCenter scene, and have so far successfully been able to remove the widget group as a whole, but I can't target each individual widget.

The "(Clone)" in the name just means that the game object was instantiated as a copy of another object, usually the prefab. This would affect trying to find objects by name, but not by component type, it's just a name that can be changed to basically anything.

If you can access the parent object, then you can get to the child objects, one way or another. This could be by accessing the components through GetComponentsInChildren<Type>, or by going through the GameObject's transform, using transform.GetChild(index). For UI objects you would have to cast the Transform (which all Unity GameObjects have) to a RectTransform, which has more controls about the object's position in the UI.

  • Like 1

Share this post


Link to post
Share on other sites
1 hour ago, DMagic said:

The "(Clone)" in the name just means that the game object was instantiated as a copy of another object, usually the prefab. This would affect trying to find objects by name, but not by component type, it's just a name that can be changed to basically anything.

 If you can access the parent object, then you can get to the child objects, one way or another. This could be by accessing the components through GetComponentsInChildren<Type>, or by going through the GameObject's transform, using transform.GetChild(index). For UI objects you would have to cast the Transform (which all Unity GameObjects have) to a RectTransform, which has more controls about the object's position in the UI.

Thanks so much for your help! Combined with this, I'm actually starting to get somewhere! :D

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now