godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.24k stars 21.22k forks source link

Editor Crash when using Tool attribute in C# script #30907

Closed Schazzwozzer closed 5 years ago

Schazzwozzer commented 5 years ago

Godot version: Godot 3.1.1 Mono 64-bit

OS/device including version: Windows 10 Home 64-bit, build 18362

Issue description: Editor immediately crashes on opening project. Issue seems to be with a C# script, part of the Main Scene, which uses the [Tool] attribute.

It builds and runs fine the first time, but when I try to re-open the project, the crash occurs. The crash can be avoided if the .mono folder in the project directory is deleted. However, it reoccurs once .mono is regenerated.

May be a duplicate of #29064

Steps to reproduce: Open project in Editor. Hit play or otherwise build the project. Close the project and re-open in Editor. Should cause immediate crash.

Minimal reproduction project: Crash Test.zip

morgash1989 commented 5 years ago

After some test, and readings... Well your _ready func is useless inside the editor, and cause the crash, so using Engine.EditorHint like this will forbid the execution inside the editor but work in game :

        public override void _Ready()
        {
            if(!Engine.EditorHint){
                // Define Singleton Instance
                if( instance != null )
                    throw new InvalidOperationException(
                        typeof( Game ) + ": Tried to create multiple instances of Singleton class." );
                instance = this;
#if DEBUG
                GD.Print( "Game Singleton instance set." );
#endif
                LoadStartingLevel();
            }
        }

or if you want to keep the instance thing :

        public override void _Ready()
        {
            // Define Singleton Instance
            if( instance != null )
                throw new InvalidOperationException(
                    typeof( Game ) + ": Tried to create multiple instances of Singleton class." );
            instance = this;
#if DEBUG
                GD.Print( "Game Singleton instance set." );
#endif
            if(!Engine.EditorHint){
                LoadStartingLevel();
            }
        }

Both resolve the crash.

If you let LoadStartingLevel call you get a crash at the line :

throw new ArgumentException( "Starting Level \"" + levelInstance.Name + "\" was not of correct type, " + typeof( Level ) );

Be warned if you don't catch exception you crash... godot don't catch them for you. So you should not throw them in _Ready or any function you don't call yourself. And surround your call to LoadStartingLevel by a try-catch if you really want to use them

Edit ; forgot s at csharp on the third code.

Schazzwozzer commented 5 years ago

Thank you for bringing Engine.EditorHint to my attention—a very useful tool to have in the toolbox— and for pointing out that the editor doesn't handle exceptions.

I should perhaps explain that I was simply trying to implement an editor warning, shown when the 'levelInstance' member wasn't set, as explained here and recently highlighted by GDQuest. Nothing ambitious.

I think I'll just steer clear of the Tool attribute, unless I'm coding something that actually is a tool meant to run in the editor.