Jump to content

onPartDie


Recommended Posts

Greetings!

I am trying to have a part, within a partmodule, detect when another part (directly) connected on either side (parent or children) is destroyed. I can't for my life make it work. I tried using IDs (craftID, flightID etc.) but with no luck, and I couldn't find any information on other unique part identifiers. Initially I thought it would work something like this:

        private void onPartDie(Part p)
        {
           if (p == this.part.parent)
           {
               //Do stuff
           }
           foreach (Part cp in this.part.children)
           {
               if (p == cp)
               {
			//Do stuff
               }
           }
        }

... But, alas.. Any help would be appreciated! : D

Of course I could probably assign identifiers myself, but I'd think something like that already existed, no?

(also any tip on how to efficiently looping through directly connected (on step down the hierarchy) child-parts would also be nice!)

Link to comment
Share on other sites

How is it failing? Are you receiving a callback to that function from the GameEvent when a part is destroyed? Is it failing to recognise a dying part as the parent/child?...

Presuming that it is the latter since it seems rather likely if the joints are already removed, you can try caching the connected parts during OnStart and comparing the destroyed part against that list which is then independent of whether a part is still connected (the cache will need to be refreshed for events which create and destroy joints (docking, joint break, etc.))

Link to comment
Share on other sites

It seems that the issue was as you suggested, the part was removed before the it was able to compare it! Thanks a lot! : D

Now I just have to find a smooth way of refreshing the cache, as you said, without making it too taxing on the system.

Link to comment
Share on other sites

Is your class a new subclass of part, or of partmodule, because we're mixing the two a bit here...

Now, I'm talking without trying and haven't done my own plugin in a year or so, so I could be wrong about some of this... but... the problems I see are...  

If you're subclassing part and trying to override onPartDie...  it's called inside the part that is doing the dying, not any other part.  So you'd actually need to tell the parent and children how to recognize that they're the parts in question and THEY would take action or communicate that they were dying to other stuff that needs to know.  Would perhaps overriding onPartJointBreak be a better idea?  This will tell you if any part attached to your part has been destroyed?  And it returns the partjoint that has been destroyed, so if you previously stashed the parent and children's joints, you'll be able to test and figure out which one broke?

Also, for testing if a part equals another part...  instead of trying to hold onto an integer ID or string name or some other indirect method of telling if the part we're talking about now is the part we were talking about earlier, just save the part itself and test against that.

But I think all of that is...  not at all what you want if you're making a part module, because a part module doesn't have an onPartDie event to override...  so you have to stash the values you want when the part initializes, then check to see if they're still attached every fixed update?

 

Edited by artwhaley
Link to comment
Share on other sites

9 hours ago, artwhaley said:

But I think all of that is...  not at all what you want if you're making a part module, because a part module doesn't have an onPartDie event to override...  so you have to stash the values you want when the part initializes, then check to see if they're still attached every fixed update?

GameEvents.OnPartDie is the method I presume he is using from a PartModule

Link to comment
Share on other sites

I'd still do it internally to your partmodule instead of tying into game events though, this way you don't have to remember to clean up for such a simple task.  This code compiles, but I don't have my testing machine with me on the holiday trip, so I could have missed something...  but it should be close:  

 

    public class ksptest : PartModule
    {
        List<Part> myparts;

        public override void OnStart(StartState state)
        {
            refreshMyParts();
        }

        public override void OnFixedUpdate()
        {
            if (myparts.Count == (this.part.children.Count + 1)) return;  //I'm just testing the count, as this seems good enough for what you need?  If you can imagine any situation where a part would be lost and another part gained on the same physics update frame, then replace this with a part to part comparison.
            if(this.part.parent== null)
            {
                //parent is dead, do stuff
                refreshMyParts();
            }
            else
            {
                //it was the children that died...
                refreshMyParts();
            }
        }

        public void refreshMyParts()  //method to clear the list and repopulate it
        {
            myparts = new List<Part>();
            myparts.Add(this.part.parent);
            foreach (Part p in this.part.children)
            {
                myparts.Add(p);
            }
        }
    }
}

In what I'm doing there, you really COULD just store an int...  replacing refreshMyParts() with 

public void refreshMyParts() //stores the original part count in an integer in the class named mycount
        {

            mycount = 0;
            if (this.part.parent != null) mycount++;
            mycount += this.part.children.Count;
           
        }

But I wanted to show how to store the actual parts in case they needed to be able to figure out specifically which one blew up for some reason, or... for some other task that required holding on to parts.

Link to comment
Share on other sites

That looks a lot better than what I have been cooking up (thanks! I may be able to use some of that! : D), but I wanted to use GameEvents.onPartDie, as my goal was to detect parts that blow up unintentionally, and not parts that is lost in e.g. decoupling etc. I saw some other mods using it, which I have installed in my on-going game, and it seemed to work very well. In addition, it has to know specifically what blew up so it can detect the specific attached parts, but I also I want to use it from within partmodule(s) as I want to use ModuleManager to assign which part which uses the partmodule I'm making, that way it's easier to make it compatible with other mods (and possibly less hard-coding when other things change). The goal is have the module work from within a assigned part to detect dying parts connected to it, and everything has to work with the part that is "still alive", though I fear it may cause some performance issues depending on how many parts have this module assigned to it.

In any rate making a cache of surrounding parts worked out great, and it now functions as I'd like. Now I'm only looking around for some practical way timing the caching, I've been looking around and onVesselWasModified seems to be a good contender, but I really don't have any clue at this moment.

Currently I'm simply targeting part.parent, and then foreach-looping all the childparts, which has the current part as part.parent, into a Stack<Part> in order to make the cache, but I've heard it is potentially very taxing with foreach-loops, and I have very little clue in how the Stack-functionality actually works... It just works.. somehow...

Link to comment
Share on other sites

If speed is an issue, a for loop on a basic array may give some minor benefits over the foreach loop, or a HashSet<Part> may be a better option than iterating over a collection (small average collection size counts against this method). That's only if you need the speed though, which really depends on how many parts this module will be active on and even then is probably not worthwhile (if it's on lots of parts, it would most likely be a better optimisation to approach it from a vessel level instead of from individual parts).

Edited by Crzyrndm
Link to comment
Share on other sites

As a general rule, the only place you need to be worried about how fast code executes is if it's in an Update() or FixedUpdate() method as those run several times a second. (Or in code called from it.)

Code anywhere else it usually triggered on an as needed basis and only runs once, so I don't worry about execution speed there.

Note this doesn't mean you can ignore how much load your code is putting on the CPU, but 99.9% of the time you don't have to worry about it outside the Update() methods.

D.

Edited by Diazo
Link to comment
Share on other sites

On ‎26‎/‎12‎/‎2015 at 4:40 AM, Diazo said:

Code anywhere else it usually triggered on an as needed basis and only runs once, so I don't worry about execution speed there.

It may only be run occasionally but, unless this is during scene change or some other point the player wouldn't notice (e.g. while paused, during save/load etc), any code that takes a long time to execute will introduce a nasty stall unless you look into using coroutines and/or background threads.

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