Supert
Supert

Reputation: 88

Prevent Unity Editor application from entering play mode

Is it possible to prevent Unity from changing the playmode after the user has pressed the button?

Let's say I have a custom editor which may have a state which can't be properly serialized; if user changes Unity Editor mode at this moment, their changes will be lost.

It is an option to completely get rid of non-serializeable state, but this is the task of completely different complexity. Would like to avoid that.

UPD:

I've tested derHugo's answer with the following script:

using UnityEditor;
using UnityEngine;

namespace Innoactive.Hub.Training.Editors
{
    [InitializeOnLoad]
    public class ProveThatDudeWrongWindow : EditorWindow
    {
        private static ProveThatDudeWrongWindow windowInstance;

        private string notSerializedString = "default";

        static ProveThatDudeWrongWindow()
        {
            EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
        }

        [MenuItem("Test/I'm damn sure he's wrong")]
        private static void MenuItem()
        {
            if (windowInstance == null)
            {
                windowInstance = GetWindow<ProveThatDudeWrongWindow>();
            }

            windowInstance.notSerializedString = "some value";
        }

        [MenuItem("Test/Display current value")]
        private static void DisplayCurrentNonSerializedValue()
        {
            windowInstance = GetWindow<ProveThatDudeWrongWindow>();
            Debug.Log("string: " + windowInstance.notSerializedString);
        }

        private static void OnPlayModeStateChanged(PlayModeStateChange state)
        {
            if (state == PlayModeStateChange.ExitingEditMode)
            {
                EditorApplication.isPlaying = false;
            }

            Debug.Log("state: " + state);
        }
    }
}

Then I've done the following:

  1. Press Test/I'm damn sure he's wrong option to set non-serialized value from default value to some value
  2. Press Test/Display current value to make sure the value is changed
  3. Press play button
  4. Press Test/Display current value to see current value. If it is default, derHugo's solution does not work, if it is some value, it works.

Result: derHugo is cool.

Upvotes: 3

Views: 2939

Answers (1)

derHugo
derHugo

Reputation: 90779

Yes there is I think

You can register to EditorApplication.playModeStateChanged

Look at the example from the doc I modified:

using UnityEngine;
using UnityEditor;

public static class PlayModeStateChangedExample
{   
    private static void LogPlayModeState(PlayModeStateChange state)
    {
        Debug.Log(state);
    }

    public static void SetPlayModeEnabled(bool enabled)
    {
        //This is possible since you allways can remove
        //a listener even if there is none so far
        //This allways removes the listener making sure it is only added once  
          EditorApplication.playModeStateChanged -= LogPlayModeState;

        if(!enabled)
        {
            EditorApplication.playModeStateChanged += LogPlayModeState;
        }
    }
}

Now all that's left is resetting EditorApplication.isPlaying back to false e.g. by replacing

Debug.Log(state);

with

// This mode occures right before entering PlayMode
// and is the moment in which we want to intervene
if(state == PlayModeStateChange.ExitingEditMode)
{
    EditorApplication.isPlaying = false;
}

to kill the PlayMode.

So you can call from anywhere e.g.

PlayModeStateChangedExample.SetPlayModeEnabled(false);

I'm not sure however if this would completely prevent the serialization part since it also states in the doc

Setting isPlaying delays the result until after all script code has completed for this frame.

Upvotes: 4

Related Questions