Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

Hey. I need help doing the dirty job of killing kerbals. Using ProtoCrewMember.Die() when in the flight scene causes an NRE and doesn't remove the portrait in flight scene, so I've been using this code (PCM is an instance of ProtoCrewMember):

if (PCM.seat != null) PCM.seat.part.RemoveCrewmember(PCM);
PCM.rosterStatus = ProtoCrewMember.RosterStatus.Dead;

However, this doesn't always work well. Sometimes, I have a portrait replaced with white noise; sometimes I still get the NRE or the kerbal even survives. I haven't been able to understand why it has different outcomes (maybe it has something to do with the game's FixedUpdate() cycle or with timewarp). In any case, the deceased kerbals disappear from the roster and are not seen in the Lost tab.

So, how do you kill your kerbals?

Link to comment
Share on other sites

I have two problems that are basic KSP functions that I can't seem to get to work.

I am trying to load a .cfg node into my script. I have a "SavedValues.cfg" in the root gamedata folder that looks like this.

VALUES{
	pitchP = 10;
	pitchI = 10;
	pitchD = 10;
}

Then I access it from my script, but it throws a null reference exception.

 public void Awake()
        {
            ConfigNode savedValues = ConfigNode.Load("GameData/SavedValues.cfg");
            savedValues = savedValues.GetNode("VALUES");
            pitchPValue = float.Parse(savedValues.GetValue("pitchP"));
            //pitchIValue = float.Parse(savedValues.GetValue("pitchI"));
            //pitchDValue = float.Parse(savedValues.GetValue("pitchD"));
        }

It seems pretty straight forward but I can't seem to figure out why its not working.  Additionally I can't get this to work either. Any help on either of these would be very much appreciated.

GamePersistence.LoadGame("quicksave.sfs", "default", false, true);

 

Link to comment
Share on other sites

15 hours ago, clown_baby said:

I have two problems that are basic KSP functions that I can't seem to get to work.

I am trying to load a .cfg node into my script. I have a "SavedValues.cfg" in the root gamedata folder that looks like this.


VALUES{
	pitchP = 10;
	pitchI = 10;
	pitchD = 10;
}

Then I access it from my script, but it throws a null reference exception.


 public void Awake()
        {
            ConfigNode savedValues = ConfigNode.Load("GameData/SavedValues.cfg");
            savedValues = savedValues.GetNode("VALUES");
            pitchPValue = float.Parse(savedValues.GetValue("pitchP"));
            //pitchIValue = float.Parse(savedValues.GetValue("pitchI"));
            //pitchDValue = float.Parse(savedValues.GetValue("pitchD"));
        }

It seems pretty straight forward but I can't seem to figure out why its not working.  Additionally I can't get this to work either. Any help on either of these would be very much appreciated.


GamePersistence.LoadGame("quicksave.sfs", "default", false, true);

 

How about removing the semicolons from the config file?

Link to comment
Share on other sites

9 hours ago, garwel said:

How about removing the semicolons from the config file?

I have tried that as well, then dropping the( savedValues = savedValues.GetNode("VALUES"); ) and getting the root node. no luck though

 

4 hours ago, DMagic said:

I think ConfigNode.Load requires the absolute file location, not the KSP relative location. 

I'll give that a shot, but how would that work if it were to be released as a mod? Everyone would have to put their own file path from wherever the folder is stored on the drive

Link to comment
Share on other sites

2 minutes ago, clown_baby said:

I'll give that a shot, but how would that work if it were to be released as a mod? Everyone would have to put their own file path from wherever the folder is stored on the drive

One common strategy is to look up the path to the mod's DLL.

Link to comment
Share on other sites

On 6/8/2017 at 4:50 AM, garwel said:

Hey. I need help doing the dirty job of killing kerbals. Using ProtoCrewMember.Die() when in the flight scene causes an NRE and doesn't remove the portrait in flight scene, so I've been using this code (PCM is an instance of ProtoCrewMember):


if (PCM.seat != null) PCM.seat.part.RemoveCrewmember(PCM);
PCM.rosterStatus = ProtoCrewMember.RosterStatus.Dead;

However, this doesn't always work well. Sometimes, I have a portrait replaced with white noise; sometimes I still get the NRE or the kerbal even survives. I haven't been able to understand why it has different outcomes (maybe it has something to do with the game's FixedUpdate() cycle or with timewarp). In any case, the deceased kerbals disappear from the roster and are not seen in the Lost tab.

So, how do you kill your kerbals?

PCM.UnregisterExperienceTraits(part);
PCM.Die();
Vessel.CrewWasModified(vessel);
                
If you intend them to respawn as per game settings. Check HighLogic.CurrentGame.Parameters.Difficulty.MissingCrewsRespawn
and then call PCM.StartRespawnPeriod()

Where PCM is the instance of the ProtoCrewMember and vessel is the Vessel they are in and part is the Part they are in.

For crew that die it is stock intended their portrait becomes static. If you don't want this then you can call a refresh
on the KerbalPortraitGallery.Instance.StartRefresh(vessel).

 

Of course this all assumes they are in the ActiveVessel.
If you are still getting NREs please supply more info on the NRE.

Link to comment
Share on other sites

2 hours ago, clown_baby said:

I'll give that a shot, but how would that work if it were to be released as a mod? Everyone would have to put their own file path from wherever the folder is stored on the drive

KSPUtil.ApplicationRootPath + "/GameData"

 

Link to comment
Share on other sites

17 hours ago, JPLRepo said:

PCM.UnregisterExperienceTraits(part);
PCM.Die();
Vessel.CrewWasModified(vessel);
                
If you intend them to respawn as per game settings. Check HighLogic.CurrentGame.Parameters.Difficulty.MissingCrewsRespawn
and then call PCM.StartRespawnPeriod()

Where PCM is the instance of the ProtoCrewMember and vessel is the Vessel they are in and part is the Part they are in.

For crew that die it is stock intended their portrait becomes static. If you don't want this then you can call a refresh
on the KerbalPortraitGallery.Instance.StartRefresh(vessel).

 

Of course this all assumes they are in the ActiveVessel.
If you are still getting NREs please supply more info on the NRE.

Thanks, will try this. The problem is, it also has to happen to unloaded kerbals (including from KSC and Tracking Station scenes). This is where I had most problems.

Edited by garwel
Link to comment
Share on other sites

I'm sorry to keep nagging about this but I just can't get it to work.

On 6/10/2017 at 8:38 AM, DMagic said:

I think ConfigNode.Load requires the absolute file location, not the KSP relative location. 

I tried just hard coding the full address into  ConfigNode.Load() but still no luck. I don't get a null ref exception on the  savedValues =ConfigNode.Load() call, but as soon as I try to access anything via savedValues one gets thrown.

17 hours ago, sarbian said:

KSPUtil.ApplicationRootPath + "/GameData"

 

This returns the KSP_Data folder path

Link to comment
Share on other sites

@clown_baby This is how I've always done it and it works for me: https://github.com/DMagic1/KSP_Better_Maneuvering/blob/master/Source/BetterManeuvering/ManeuverPersistence.cs#L91

I'm no sure if all of that Path.Combine, Path.DirectoryName stuff is actually needed (or converting the \ to /), but it works, so I've just used the same method every time.

Link to comment
Share on other sites

21 hours ago, JPLRepo said:

PCM.UnregisterExperienceTraits(part);
PCM.Die();
Vessel.CrewWasModified(vessel);
                
If you intend them to respawn as per game settings. Check HighLogic.CurrentGame.Parameters.Difficulty.MissingCrewsRespawn
and then call PCM.StartRespawnPeriod()

Where PCM is the instance of the ProtoCrewMember and vessel is the Vessel they are in and part is the Part they are in.

This code appears to work for a kerbal on board ActiveVessel. But when I try it on a kerbal on EVA (I skip the first line because part is null) while being focused on a nearby vessel, he doesn't disappear or anything. Trying then to switch to that kerbal causes an NRE:

NullReferenceException: Object reference not set to an instance of an object
  at KerbalRoster.ValidateAssignments (.Game st) [0x00000] in <filename unknown>:0 
  at Game.Updated () [0x00000] in <filename unknown>:0 
  at GamePersistence.SaveGame (System.String saveFileName, System.String saveFolder, SaveMode saveMode) [0x00000] in <filename unknown>:0 
  at KSP.UI.Screens.AltimeterSliderButtons.returnToSpaceCenter () [0x00000] in <filename unknown>:0 
  at UnityEngine.Events.InvokableCall.Invoke (System.Object[] args) [0x00000] in <filename unknown>:0 
  at UnityEngine.Events.InvokableCallList.Invoke (System.Object[] parameters) [0x00000] in <filename unknown>:0 
  at UnityEngine.Events.UnityEventBase.Invoke (System.Object[] parameters) [0x00000] in <filename unknown>:0 
  at UnityEngine.Events.UnityEvent.Invoke () [0x00000] in <filename unknown>:0 
  at UnityEngine.UI.Button.Press () [0x00000] in <filename unknown>:0 
  at UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) [0x00000] in <filename unknown>:0 
  at UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) [0x00000] in <filename unknown>:0 
  at UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction`1 functor) [0x00000] in <filename unknown>:0 
UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
UnityEngine.DebugLogHandler:LogException(Exception, Object)
UnityEngine.Logger:LogException(Exception, Object)
UnityEngine.Debug:LogException(Exception)
UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1)
UnityEngine.EventSystems.StandaloneInputModule:ProcessMousePress(MouseButtonEventData)
UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent(Int32)
UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent()
UnityEngine.EventSystems.StandaloneInputModule:Process()
UnityEngine.EventSystems.EventSystem:Update()

 

Link to comment
Share on other sites

21 hours ago, DMagic said:

@clown_baby This is how I've always done it and it works for me: https://github.com/DMagic1/KSP_Better_Maneuvering/blob/master/Source/BetterManeuvering/ManeuverPersistence.cs#L91

I'm no sure if all of that Path.Combine, Path.DirectoryName stuff is actually needed (or converting the \ to /), but it works, so I've just used the same method every time.

So I have tried this and every other way to get the correct path as a string. I'm starting to think that isn't the problem however. If the path were wrong I assume I would get a null ref exception when i use:

fullPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "SavedValues.cfg").Replace("\\", "/");
ConfigNode savedValues = ConfigNode.Load(fullPath);

But I don't. I'm starting to think I am just accessing the node incorrectly. So again here is my .cfg file.

VALUES
{
	pitchP = 10;
	pitchI = 10;
	pitchD = 10;
}

So i get the root node of the cfg using the code above, then get the VALUES node with this, which is when the first null ref gets thrown.

 if (savedValues.HasNode("VALUES"))
{
	savedValues = savedValues.GetNode("VALUES");
}

Then I should be able to access the values in the node via.

pitchIValue = float.Parse(savedValues.GetValue("pitchI"));

Is this not the correct way to get info from the nodes?

Link to comment
Share on other sites

On 6/10/2017 at 3:39 AM, garwel said:

How about removing the semicolons from the config file?

 

2 minutes ago, sarbian said:

And you still have ";" at the end of your lines. It is not a C# file.

Oh sorry I totally missed that suggestion the first time. Doesnt fix the problem though

Link to comment
Share on other sites

So I actually fixed it. I copied an existing cfg file and changed the name/values which got it to load.  When I created my "SavedValues.cfg" I must have saved it as a text file.  I knew it was something stupid I did.

Thanks for the help everyone.

Edited by clown_baby
Link to comment
Share on other sites

On 6/12/2017 at 4:36 AM, garwel said:

This code appears to work for a kerbal on board ActiveVessel. But when I try it on a kerbal on EVA (I skip the first line because part is null) while being focused on a nearby vessel, he doesn't disappear or anything. Trying then to switch to that kerbal causes an NRE:


NullReferenceException: Object reference not set to an instance of an object
  at KerbalRoster.ValidateAssignments (.Game st) [0x00000] in <filename unknown>:0 
  at Game.Updated () [0x00000] in <filename unknown>:0 
  at GamePersistence.SaveGame (System.String saveFileName, System.String saveFolder, SaveMode saveMode) [0x00000] in <filename unknown>:0 
  at KSP.UI.Screens.AltimeterSliderButtons.returnToSpaceCenter () [0x00000] in <filename unknown>:0 
  at UnityEngine.Events.InvokableCall.Invoke (System.Object[] args) [0x00000] in <filename unknown>:0 
  at UnityEngine.Events.InvokableCallList.Invoke (System.Object[] parameters) [0x00000] in <filename unknown>:0 
  at UnityEngine.Events.UnityEventBase.Invoke (System.Object[] parameters) [0x00000] in <filename unknown>:0 
  at UnityEngine.Events.UnityEvent.Invoke () [0x00000] in <filename unknown>:0 
  at UnityEngine.UI.Button.Press () [0x00000] in <filename unknown>:0 
  at UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) [0x00000] in <filename unknown>:0 
  at UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) [0x00000] in <filename unknown>:0 
  at UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction`1 functor) [0x00000] in <filename unknown>:0 
UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
UnityEngine.DebugLogHandler:LogException(Exception, Object)
UnityEngine.Logger:LogException(Exception, Object)
UnityEngine.Debug:LogException(Exception)
UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1)
UnityEngine.EventSystems.StandaloneInputModule:ProcessMousePress(MouseButtonEventData)
UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent(Int32)
UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent()
UnityEngine.EventSystems.StandaloneInputModule:Process()
UnityEngine.EventSystems.EventSystem:Update()

 

A kerbal on EVA.. You didn't mention that.
In that case you have to kill the Vessel as well. You can't switch to a vessel that is an EVA Kerbal if the Kerbal is dead. If they die on EVA in stock then the vessel must also be killed and disappear. Stock does not support that use case.

Link to comment
Share on other sites

 I'm not a programmer, but I have a question.  'Hope I'm in the right place.

 If I open a .craft file as a text file I see a line like this for most parts

modMass = 0

 I was hoping this will change the effect gravity has on that part.

 How do I find out what this variable really does, if changing it has any effect, and what acceptable ranges are valid?

Link to comment
Share on other sites

If memory serves correctly this is the scaler that something like tweakscale can use to change the mass of a given part's instance- thus why you'll find this parameter in a .craft file or a .sfs but not in the basic .cfg that defines the part.   Whether it's additive or multiplicative I don't remember!    To figure it out, i'd just start fiddling with it!  Write down your craft's mass, write down a given part's mass, then change that part's modmass and reload to see if the mass of the craft went up by the amount you added or if the mass of the craft increased by the mass of that part TIMES the modmass  scaler. 

 

I wish there was great documentation to point you towards but...  that's what KSP modmakers have always had to do - trial and error.

 

That said, you question was specific-  you want to change the effect of gravity ONLY?  Not actually change the mass of the part?  You want OTHER accelerations to continue to act unaffected?  That's a tough one that might take a bit more explaining before we come up with an answer for you...

Link to comment
Share on other sites

I was wondering if anyone has seen this behavior before when using FlightGlobals.ForceSetActiveVessel. The throttle settings seem to be overriding the settings of the vessel I switch to. When using the  [ ] Brackets to switch this does not occur.

  Vessel A (Active) = 0% Throttle
  Vessel B (Inactive) = 100% Throttle

  FlightGlobals.ForceSetActiveVessel(Vessel B)

  Vessel A (Inactive) = 0% Throttle
  Vessel B (Active) = 0% Throttle 
Link to comment
Share on other sites

I did a simple test with an internal module I've been tinkering with, and caused all kinds of mayhem. The module is simple. It finds a prop transform for a screen model and an empty gameObject, then adds a camera component to the empty gameObject and adds a renderTexture to the screen model. The camera then has its targetTexture assigned to the renderTexture. That's it. 

The game loads fine but when I load the IVA on the pad the main cam is rotated 90 degrees on the x axis or sometimes is flung into deep space before the game crashes. I'm guessing it has something to do with layers and tags. I'm sure there's some camera voodoo I'm unaware of. @linuxgurugamer would probably know what the best practices are.

 

public class UtilisDisplay : InternalModule
	{
		[KSPField]
		public string dTransform = "dTransform"; 

		[KSPField]
		public string cameraName = "utilisCamera";

		[KSPField]
		public int dPixelWidth = 512;

		[KSPField]
		public int dPixelHeight = 256;

		private Camera cameraFeed;

		private Transform cTransform;

		private RenderTexture displayTexture;

		private Material displayMaterial;

		public override void OnAwake()
		{
			if(HighLogic.LoadedSceneIsFlight)
			{
				UtilisTools.Log(this, "Start!");

				displayTexture = new RenderTexture(dPixelWidth, dPixelHeight, 24, RenderTextureFormat.ARGB32);

				displayMaterial = internalProp.FindModelTransform(dTransform).GetComponent<Renderer>().material;

				cTransform = internalProp.internalModel.FindModelTransform(cameraName);

				cTransform.gameObject.AddComponent<Camera>();

				UtilisTools.Log(this, "Camera created");

				cameraFeed = cTransform.gameObject.GetComponent<Camera>();

				cameraFeed.fieldOfView = 110;

				cameraFeed.transform.parent = cTransform;

				cameraFeed.transform.localPosition = Vector3.zero;

				cameraFeed.transform.localEulerAngles = Vector3.zero;

				displayMaterial.mainTexture = displayTexture;
			}
		}
	}

The log is spamming "Look rotation viewing vector is zero"

Link to comment
Share on other sites

Quick question. I want to setup a UI_FloatEdit with values from the config file. When attempting to pass another field as the arguments for minValue, or maxValue, I get the following error:

An object reference is required for the non-static field, method, or property

At the moment, the only way it compiles is if I hard code the values:

[KSPField(isPersistant = true, guiName = "Length", guiFormat = "F3", guiUnits = "m"),
         UI_FloatEdit(scene = UI_Scene.Editor, minValue = 0.25f, incrementLarge = 2.0f, incrementSmall = 0.25f, incrementSlide = 0.001f)]
        public float tankLength = 1.0f;

What is the proper way to make this work?

Link to comment
Share on other sites

2 minutes ago, saabstory88 said:

Quick question. I want to setup a UI_FloatEdit with values from the config file. What is the proper way to make this work?

I think you would need to set those values at run time in your module's Start().

	BaseField field = Fields["MyField"];
	UI_FloatEdit edit = (UI_FloatEdit)field.uiControlEditor;
	if (edit != null) {
		edit.minValue = 0f;
	}

 

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...