Jump to content

Nonsensical InvalidCastException


Recommended Posts

I'm trying to update the SmartParts Auto Stager so the user can select the resource they wish to monitor, using a KSPAPIExpansion textfield. Unfortunately, as is usually the case with my attempts to code for KSP, I'm running into an issue.

I have the auto stager check it's parent part "OnEditorAttach". Unfortunately, this causes all kinds of weird problems, the most common of which is a "InvalidCastException: Cannot cast from source type to destination type.", which I find amusing, since I'm not casting from anything. If I use "Invoke" to delay it .25 seconds from editor attach, it does seem to work, sort of, at least until I pick up the parent part at which point everything goes sideways again and I get yet another "InvalidCastException". It's as if KSP doesn't know the parent part of the Smart Stager until some arbitrary time AFTER it's attached to a tank. How the devil can I work with that?

So, does anyone have any idea what is causing this? Or, more importantly, what options I have to detect the parent's resources when the Smart Stager is attached? I've tried simply detecting the parent part and passing that to a Part variably, but quite naturally that failed too.

Any help at all would be appreciated. These modifications, if I can get them working, would make this thing much more friendly for users of RealFuels, which is what I'm after.

Log messages showing debug code


[LOG 18:25:04.169] KM Stager Started
[LOG 18:25:05.316] km.smart.fuel(Clone) added to ship - part count: 2
[LOG 18:25:05.317] KM Stager: Monitoring parent tank
[LOG 18:25:05.317] DEBUG:check this part parent resources
[LOG 18:25:05.318] DEBUG:succeed PartResourceList
[LOG 18:25:05.318] stage count is: 0
[EXC 18:25:05.319] InvalidCastException: Cannot cast from source type to destination type.

Code relating (I think) to the problem


[KSPField(isPersistant = true)]
public PartResourceList partRes = null;

public override void OnStart(StartState state) {
if (state == StartState.Editor) {
this.part.OnEditorAttach += OnEditorAttach;
this.part.OnEditorDetach += OnEditorDetach;
this.part.OnEditorDestroy += OnEditorDestroy;
}
print("KM Stager Started");
}

private void findResources() {
if (this.part.Resources.Count > 0) {
print("KM Stager: Monitoring smart tank");
print("DEBUG:check this part resources");
partRes = this.part.Resources;
print("DEBUG:succeed " + partRes.ToString());
smartTank = true;
}
else if (this.part.parent.Resources.Count > 0) {
print("KM Stager: Monitoring parent tank");
print("DEBUG:check this part parent resources");
partRes = this.part.parent.Resources;
print("DEBUG:succeed " + partRes.ToString());
smartTank = false;
}
else {
print("DEBUG:no matches. Setting null");
partRes = null;
}
//updateList();
}

private void OnEditorAttach() {
RenderingManager.AddToPostDrawQueue(99, updateEditor);
findResources();
}

Edited by Firov
Link to comment
Share on other sites

Did you have a look into your output_log.txt? While it's not logging the actual line where the exception occurred, it's logging the method where it did, so that should help you out a bit.

I just checked the output log. If I'm reading this right, it looks like the exception isn't being caused directly by the SmartParts.dll.


(Filename: C:/BuildAgent/work/d63dfc6385190b60/artifacts/StandalonePlayerGenerated/UnityEngineDebug.cpp Line: 49)

InvalidCastException: Cannot cast from source type to destination type.
at BaseField.GetStringValue (System.Object host, Boolean gui) [0x00000] in <filename unknown>:0

at BaseFieldList.Save (.ConfigNode node) [0x00000] in <filename unknown>:0

at PartModule.Save (.ConfigNode node) [0x00000] in <filename unknown>:0

at ShipConstruct.SaveShip () [0x00000] in <filename unknown>:0

at ShipConstruction.CreateBackup (.ShipConstruct ship) [0x00000] in <filename unknown>:0

at EditorLogic.SetBackup () [0x00000] in <filename unknown>:0

at EditorLogic.UpdatePartMode () [0x00000] in <filename unknown>:0

at EditorLogic.Update () [0x00000] in <filename unknown>:0

Link to comment
Share on other sites

I'm really getting into guessing-type terrain here, because I'm not at all familiar with it, but could this be the culprit?


[KSPField(isPersistant = true)]
private PartResourceList partRes = null;

Meaning that you're trying to save a PartResourceList into the vessel?

Again, I haven't used [KSPField] at all so far, so please disregard if I'm talking nonsense here.

Link to comment
Share on other sites

Also, note that KSPFields have to be public.

Which makes sense, KSPFields populate the partModule.fields list, so the KSPField is private and you try to reference it from outside the partmodule you'll get a null reference error.

I think this explains blizzy's error as it is in a BaseField.

Might also have to do with type, KSPFields are limited in the type of object they can be.

D.

Link to comment
Share on other sites

That's what I was trying to get at, sorry for not being more specific.

Hmm. Thanks for the suggestion. It makes sense.

Unfortunately, that's not the solution. Even after changing the field to public it still throws that same exception. Also, I don't get that exception if I attach the Smart Stager to something that doesn't have resources, so it doesn't appear to be an issue with "partRes" itself being Null. It's something else.

What's more unusual is that if I invoke "findResources()" after a delay of, say, .25 seconds it will allow me to place it initially without an exception being thrown. Though that's not an acceptable long term solution since it throws that exception again if I try to move a subassembly that the Stager is attached to.

I'm convinced that this is a problem with timing, but I'm not sure how, and I'm especially not sure how to fix it... :(

Edited by Firov
Link to comment
Share on other sites

I think you misunderstood both Diazo and me, so I'll be clear here: We think that KSPField does not accept every type you can think of, but only primitive types like bool, string, and such. At least that's what I have been thinking :)

Edit: Also, I believe it works when it's null, because null can be cast into any type.

Edited by blizzy78
Link to comment
Share on other sites

I think you misunderstood both Diazo and me, so I'll be clear here: We think that KSPField does not accept every type you can think of, but only primitive types like bool, string, and such. At least that's what I have been thinking :)

Edit: Also, I believe it works when it's null, because null can be cast into any type.

Hmm. Now I see, and that does make sense. When I get back from the office I'll check that and report back. Thanks for the help so far, Diazo and Blizzy.

Link to comment
Share on other sites

Which reminds me we have that list. From the dev's release notes when they implemented KSPField:

The limitation for adding the KSPField attribute is that it can only be applied to classes which implement the IConfigNode interface (more on this later) or one of the types; string, bool, int, float, Vector2, Vector3, Vector4 or Quaternion

Note that double is not on the list, that has caused plenty of headaches before.

D.

Link to comment
Share on other sites

And even stuff that does implement IConfigNode is iffy. I've been fighting with the ConfigNode stuff all weekend and still scratching my head half the time. There seems to be some unwritten rules on what works and doesn't work, and annoyingly the original sample given by the devs when this stuff was released doesn't even work.

In your case specifically the error is happening because its trying to cast values to a different type for persistence and can't.

Link to comment
Share on other sites

Sweet. Now on to some real programming instead of bug chasing :D

Heh. Hopefully. At least for the next few minutes until I get mired in another endless bug hunt. :D

Anyway, thanks again guys. You've spared my sanity once again.

Link to comment
Share on other sites

Yes. This was the issue. It works perfectly now. Thanks for the input and help everyone. I appreciate it!

Care to share how you got it working? I'm still fighting with properly loading and persisting ConfigNodes.

Link to comment
Share on other sites

Care to share how you got it working? I'm still fighting with properly loading and persisting ConfigNodes.

Agathorn, I just made the resource list not persistent, and not a field, which allows me to attach it without throwing an exception. I'm now reconfiguring it so it rechecks the resources every time it loads/changes scenes, rather than relying on persistence. Not as convenient, but I don't see another option.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

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