Jump to content

Why is this code creating multiple Toolbar buttons when switching scenes?


Recommended Posts

Make appLauncherButton static. Every time you switch scenes, the instance of the class you have is destroyed along with your reference to the button. Going back to the space centre, you have a new class instance and a null button variable, and so another is created. Making it static means it wont be null after you've created it, so your null check here will do its job

Edited by Crzyrndm
Link to comment
Share on other sites

Everytime the CareerManagerUI class is created, it's making a new button but not destroying the button with that instance of the CareerManagerUI class is destroyed.

So KSP keeps the button around because without that explicit button destroy command it's not smart enough to remove the button when the CareerManagerUI class is destroyed.

Note the null check doesn't work because when another instance of the CareerManagerUI class is created, it makes a second button object, it doesn't check the first button object made previously in the other instance of the class.

Hope that helps,

D.

Link to comment
Share on other sites

18 hours ago, Crzyrndm said:

Make appLauncherButton static. Every time you switch scenes, the instance of the class you have is destroyed along with your reference to the button. Going back to the space centre, you have a new class instance and a null button variable, and so another is created. Making it static means it wont be null after you've created it, so your null check here will do its job

Thanks for the reply, and it somewhat helped. It no longer creates a new button which is awesome, but the button now becomes unresponsive after switching scenes. Thanks for anymore help!

18 hours ago, Diazo said:

Everytime the CareerManagerUI class is created, it's making a new button but not destroying the button with that instance of the CareerManagerUI class is destroyed.

So KSP keeps the button around because without that explicit button destroy command it's not smart enough to remove the button when the CareerManagerUI class is destroyed.

Note the null check doesn't work because when another instance of the CareerManagerUI class is created, it makes a second button object, it doesn't check the first button object made previously in the other instance of the class.

Hope that helps,

D.

Is there a way to fix this?

Link to comment
Share on other sites

Make the functions static too :P (they point to a dead instance currently)

Alternatively, you need to destroy the button instance on leaving a scene, which I don't have any examples at hand for because I just use a static class for the toolbar now (I find it more trustworthy when other mods start throwing exceptions around...)

Link to comment
Share on other sites

7 hours ago, Crzyrndm said:

Make the functions static too :P (they point to a dead instance currently)

Alternatively, you need to destroy the button instance on leaving a scene, which I don't have any examples at hand for because I just use a static class for the toolbar now (I find it more trustworthy when other mods start throwing exceptions around...)

Sorry for my incompetence, but which functions should I make static. The only one that I see that affects the appLauncherButton directly is the constructor, and I cant make that static :P . 

Link to comment
Share on other sites

The command to destroy the button is ApplicationLauncher.Instance.RemoveModApplication.

I inherit my classes from MonoBehavior so the OnDisable() method is automatically called by KSP when it destroys the class and I put the button remove method in there.

The Static method Crzyrndm is talking about is making a totally separate class that is entirely static for button management that your UI instance class would call.

D.

Link to comment
Share on other sites

3 hours ago, Diazo said:

The Static method Crzyrndm is talking about is making a totally separate class that is entirely static for button management that your UI instance class would call.

Not quite. Only the functions that the button calls need to be static (which then need to reference atleast one static member to make changes to the live instance, ...). The way he has it setup, its probably easier just to destroy the button on leaving the scene.

Link to comment
Share on other sites

7 hours ago, Diazo said:

The command to destroy the button is ApplicationLauncher.Instance.RemoveModApplication.

I inherit my classes from MonoBehavior so the OnDisable() method is automatically called by KSP when it destroys the class and I put the button remove method in there.

The Static method Crzyrndm is talking about is making a totally separate class that is entirely static for button management that your UI instance class would call.

D.

Adding this doesnt change anything unfortunately:

public void OnDisable()
{
     ApplicationLauncher.Instance.RemoveModApplication(appLauncherButton);
}

4 hours ago, Crzyrndm said:

Not quite. Only the functions that the button calls need to be static (which then need to reference atleast one static member to make changes to the live instance, ...). The way he has it setup, its probably easier just to destroy the button on leaving the scene.

Whats the best way to do that?

Link to comment
Share on other sites

You need to inherit from MonoBehavior for OnDisable() to run, so:

 

public class CareerManagerUI : MonoBehavior
{
public void OnDisable()
{
ApplicationLauncher.Instance.RemoveModApplication(YouButtonObject)
}
}

MonoBehavior being a top-level class in Unity that adds several utility methods like this, you can see them in the Object Browser as part of the MonoBehavior object.

D.

Edited by Diazo
Link to comment
Share on other sites

33 minutes ago, Diazo said:

You need to inherit from MonoBehavior for OnDisable() to run, so:

 


public class CareerManagerUI : MonoBehavior
{
public void OnDisable()
{
ApplicationLauncher.Instance.RemoveModApplication(YouButtonObject)
}
}

MonoBehavior being a top-level class in Unity that adds several utility methods like this, you can see them in the Object Browser as part of the MonoBehavior object.

D.

Weird, still isnt working for me, any other ideas?

Link to comment
Share on other sites

Odd. I actually inherit from PartModule not MonoBehavior in my own code for other reasons, maybe the OnDisable() method exists at that level instead?

I'm looking at my object browser now and I can't actually find the method, so I'm actually not sure what Class it's actually attached to.

D.

 

edit: Nope, it's off MonoBehavior: http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnDisable.html


Here's where I actually use it in my own code so you can compare.

Can you stick a Debug.Log in and see if is the OnDisable not being called, or the RemoveModButton code that's not working?

Edited by Diazo
Link to comment
Share on other sites

16 minutes ago, Diazo said:

Odd. I actually inherit from PartModule not MonoBehavior in my own code for other reasons, maybe the OnDisable() method exists at that level instead?

I'm looking at my object browser now and I can't actually find the method, so I'm actually not sure what Class it's actually attached to.

D.

 

edit: Nope, it's off MonoBehavior: http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnDisable.html


Here's where I actually use it in my own code so you can compare.

I'm trying to somewhat replicate your code, but I cant do "toolbarButton.Destroy();", as it throws "No overload for method "Destroy" takes 0 arguments. Any help?

Nvm, that was something else

Edited by bananashavings
Link to comment
Share on other sites

20 minutes ago, Diazo said:

Odd. I actually inherit from PartModule not MonoBehavior in my own code for other reasons, maybe the OnDisable() method exists at that level instead?

I'm looking at my object browser now and I can't actually find the method, so I'm actually not sure what Class it's actually attached to.

D.

 

edit: Nope, it's off MonoBehavior: http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnDisable.html


Here's where I actually use it in my own code so you can compare.

Can you stick a Debug.Log in and see if is the OnDisable not being called, or the RemoveModButton code that's not working?

Arrrgghhh, just changed it to practically what you have and it still didnt work! Do you think it could have to do with my main class?

Link to comment
Share on other sites

3 minutes ago, Diazo said:

It shouldn't have anything to do with your main class I would think.

Can you paste-bin your current code? Including where you initialize the CareerManagerUI class.

D.

Sure, heres the CareerManager.cs and heres the CareerManagerUI.cs. Additionally heres the ToolbarWrapper.cs if you want to see it. Thanks for all this help again, I sincerely appreciate it!

Link to comment
Share on other sites

Okay, you have both Destroy() and OnDisable() methods, you only need one as they are doing the same thing.

Things look right to me otherwise though.

Having said that, can you stick a debug line into the OnDisable method?

Debug.Log("UI OnDisable called okay");
ApplicationLauncher.Instance.RemoveModApplication(appLauncherButton);

That will tell you if the code is even trying to remove the Toolbar button or not so you can confirm you are focusing on the right issue.

D.

Link to comment
Share on other sites

8 minutes ago, Diazo said:

Okay, you have both Destroy() and OnDisable() methods, you only need one as they are doing the same thing.

Things look right to me otherwise though.

Having said that, can you stick a debug line into the OnDisable method?


Debug.Log("UI OnDisable called okay");
ApplicationLauncher.Instance.RemoveModApplication(appLauncherButton);

That will tell you if the code is even trying to remove the Toolbar button or not so you can confirm you are focusing on the right issue.

D.

YAY, I removed the Destroy() function and changed the corresponding code in the main file to OnDisable() and it works now! Thanks for all the help and hopefully I wont have to bug you any more!

Link to comment
Share on other sites

Glad to hear you got it!

While I'm not 100% sure, I'm assuming that the Destroy() ran before OnDisable() and pre-empted it so that OnDisable() was simply never running. It depends on how exactly MonoBehavoir was coded by the Unity programmers and I'm not privy to that.

D.

Link to comment
Share on other sites

That page contains contradictory information (though the bits concerning creation and destruction are probably correct ;) ).  This bit:

FixedUpdate: FixedUpdate is often called more frequently than Update. It can be called multiple times per frame, if the frame rate is low and it may not be called between frames at all if the frame rate is high.

...says that FixedUpdate may not be called between two calls to Update but the flowchart further down the page doesn't allow this.

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