using Bootstrap;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Editor.Bootstrap
{
///
/// Edit-mode utilities.
///
/// This class provides a handy mechanism to enable editor bootstrapping.
/// When enabled, the bootstrap system will initialise during edit-mode, allowing
/// developers to preview the effects of the bootstrap system.
///
/// There are several caveats here:
/// 1. DontDestroyOnLoad doesn't work in edit-mode. Any objects loaded by the bootstrap system
/// will be added to the current scene.
/// 2. Entering playmode will cause this script to de-initialise the bootstrapper, if initialised.
/// This means that playmode priority is always given to the boostrapper.
/// 3. If editor bootstrapping is enabled, then the bootstrapper will de-init and re-init
/// whenever the current scene changes. This may not be appropriate for all workflows!
/// 4. If bootstrapping is enabled, and the current scene is saved, then the bootstrapper will be
/// de-initialised prior to the scene being saved to disk, and then re-initialised, thereby
/// avoiding scene pollution.
///
[InitializeOnLoad]
public static class CustomBootEditorUtils
{
///
/// Editor prefs key for the edit-mode bootstrapper.
///
private const string INITIALISE_IN_EDITOR = "bootstrap.editor_init_enabled";
///
/// Menu path for the edit-mode bootstrapper
///
private const string EDITOR_INIT_MENU = "Bootstrap/Editor Initialise";
static CustomBootEditorUtils()
{
InitPlayModeListener();
if (Application.isPlaying) return;
//Don't initialise if we're about to change playmode!
if (EditorInitialisationEnabled && !EditorApplication.isPlayingOrWillChangePlaymode)
{
DoInit();
}
}
///
/// Initialise the playmode change listener.
/// This also sets up a listener for scene saving, so that we can
/// de-init and reinit the bootstrapper when the user saves changes, thereby
/// avoiding bootstrapped objects polluting the saved scene.
///
private static void InitPlayModeListener()
{
EditorApplication.playModeStateChanged += EditorApplicationOnplayModeStateChanged;
EditorSceneManager.sceneSaving += OnSceneSaving;
}
///
/// Handle the event.
/// This de-initialises the bootstrapper, removing objects from the scene,
/// and then listens for the event
/// in order to re-initialise the bootstrapper.
///
///
///
private static void OnSceneSaving(Scene scene, string path)
{
if (CustomBoot.Initialised)
{
DoDeInit();
EditorSceneManager.sceneSaved += EditorSceneManagerOnsceneSaved;
void EditorSceneManagerOnsceneSaved(Scene scene1)
{
EditorSceneManager.sceneSaved -= EditorSceneManagerOnsceneSaved;
CheckInit();
}
}
}
///
/// Deinitialise the playmode change listener
///
private static void DeInitPlayModeListener()
{
EditorApplication.playModeStateChanged -= EditorApplicationOnplayModeStateChanged;
}
///
/// Is play-mode bootstrapping enabled?
///
private static bool EditorInitialisationEnabled
{
get => EditorPrefs.GetBool(INITIALISE_IN_EDITOR, false);
set => EditorPrefs.SetBool(INITIALISE_IN_EDITOR, value);
}
///
/// Menu handler for the edit-mode bootstrapper
///
[MenuItem(EDITOR_INIT_MENU)]
private static void EditorInitialise()
{
EditorInitialisationEnabled = !EditorInitialisationEnabled;
CheckInit();
}
///
/// Menu validator for the edit-mode bootstrapper
///
///
[MenuItem(EDITOR_INIT_MENU, true)]
private static bool EditorInitialiseValidate()
{
Menu.SetChecked(EDITOR_INIT_MENU, EditorPrefs.GetBool(INITIALISE_IN_EDITOR, false));
return true;
}
///
/// Perform initialisation or de-initialisation depending on the current context
///
private static void CheckInit()
{
if (EditorInitialisationEnabled && !CustomBoot.Initialised && !Application.isPlaying)
{
DoInit();
}
else if (CustomBoot.Initialised)
{
DoDeInit();
}
}
///
/// Perform the initialisation process.
/// This adds a listener for the event so that we
/// can handle scene changes once we're initialised
///
private static void DoInit()
{
EditorSceneManager.sceneClosing += OnSceneClosing;
CustomBoot.PerformInitialisation();
}
///
/// Handle the event
/// This de-initialises the bootstrapper and then sets up a listener for the
/// event so that
/// we can safely re-initialise the bootstrapper
///
///
///
private static void OnSceneClosing(Scene scene, bool removingscene)
{
if (!Application.isPlaying && CustomBoot.Initialised)
{
DoDeInit();
EditorSceneManager.activeSceneChangedInEditMode += OnSceneLoaded;
}
}
///
/// Handles the event,
/// allowing the boostrapper to reinitialise if required
///
///
///
private static void OnSceneLoaded(Scene arg0, Scene scene)
{
if (!Application.isPlaying)
{
EditorSceneManager.activeSceneChangedInEditMode -= OnSceneLoaded;
CheckInit();
}
}
///
/// De-Initialises the bootstrapper
///
private static void DoDeInit()
{
CustomBoot.PerformDeInitialisation();
EditorSceneManager.sceneClosing -= OnSceneClosing;
}
///
/// Handles playmode change events. This will de-initialise the bootstrapper
/// when exiting edit-mode, and call when entering edit-mode
///
///
private static void EditorApplicationOnplayModeStateChanged(PlayModeStateChange obj)
{
switch (obj)
{
case PlayModeStateChange.ExitingEditMode:
if (CustomBoot.Initialised)
{
DoDeInit();
}
break;
case PlayModeStateChange.EnteredEditMode:
CheckInit();
break;
}
}
}
}