Skip to content

Commit

Permalink
Improve Editor UX, extend API
Browse files Browse the repository at this point in the history
  • Loading branch information
Edvinas01 committed Oct 21, 2022
1 parent d796256 commit f472bb6
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 153 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.0.7] - 2022-10-22

### Added
- More properties to `BaseScriptableScene` and `ScriptableScene`.

### Changed
- Scenes not added to build settings can now be Opened, Loaded and Activated in Editor. In Player, a warning will be printed for such scenes.
- Removed `BuildIndex` from `BaseScriptableScene` (want to hide it),

## [0.0.6] - 2022-10-17

### Added
Expand Down
22 changes: 1 addition & 21 deletions Editor/SceneSceneEditor.cs → Editor/ScriptableSceneEditor.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Linq;
using CHARK.ScriptableScenes.Editor.Utilities;
using UnityEditor;
using UnityEditor.Build.Content;
using UnityEngine;

namespace CHARK.ScriptableScenes.Editor
Expand All @@ -11,7 +10,7 @@ namespace CHARK.ScriptableScenes.Editor
/// </summary>
[CanEditMultipleObjects]
[CustomEditor(typeof(BaseScriptableScene), true)]
internal class SceneSceneEditor : UnityEditor.Editor
internal class ScriptableSceneEditor : UnityEditor.Editor
{
#region Private Fields

Expand Down Expand Up @@ -91,25 +90,6 @@ private void DrawAddToBuildSettingsButton()
}
}

private bool TryGetEditorBuildSettingsScene(out EditorBuildSettingsScene scene)
{
scene = null;

var scriptableScenePath = scriptableScene.ScenePath;
var scenes = EditorBuildSettings.scenes.ToList();

foreach (var otherScene in scenes)
{
if (otherScene.path == scriptableScenePath)
{
scene = otherScene;
return true;
}
}

return false;
}

#endregion
}
}
File renamed without changes.
20 changes: 15 additions & 5 deletions Runtime/BaseScriptableScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ public abstract class BaseScriptableScene : ScriptableObject
/// </summary>
public abstract string ScenePath { get; }

/// <summary>
/// Scene build index.
/// </summary>
public abstract int SceneBuildIndex { get; }

/// <summary>
/// Should this scene be activated after loading.
/// </summary>
Expand All @@ -37,6 +32,16 @@ public abstract class BaseScriptableScene : ScriptableObject
/// </summary>
public abstract bool IsPersist { get; }

/// <summary>
/// <c>true</c> if this scene is currently loaded or <c>false</c> otherwise.
/// </summary>
public abstract bool IsLoaded { get; }

/// <summary>
/// <c>true</c> if this scene is valid or <c>false</c> otherwise.
/// </summary>
public abstract bool IsValid { get; }

/// <summary>
/// Event handler assigned to this scene.
/// </summary>
Expand All @@ -61,6 +66,11 @@ public abstract class BaseScriptableScene : ScriptableObject
/// </summary>
public abstract void SetActive();

/// <returns>
/// <c>true</c> if this Scriptable Scene is pointing to <paramref name="otherScene"/>.
/// </returns>
public abstract bool Equals(Scene otherScene);

#endregion
}
}
168 changes: 96 additions & 72 deletions Runtime/ScriptableScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,18 @@ internal sealed class ScriptableScene :
{
#region Editor Fields

[Header("Internal")]
[ReadOnly]
[Tooltip("Build index of the scene")]
#if UNITY_EDITOR
[Header("Scene")]
[SerializeField]
private int sceneBuildIndex;
private UnityEditor.SceneAsset sceneAsset;
#endif

[ReadOnly]
[Tooltip("Path to the scene asset")]
[SerializeField]
private string scenePath;

#if UNITY_EDITOR
[Header("Configuration")]
[SerializeField]
private UnityEditor.SceneAsset sceneAsset;
#endif

[Tooltip("Should this scene be activated on load?")]
[SerializeField]
private bool isActivate;
Expand All @@ -51,25 +46,19 @@ internal sealed class ScriptableScene :

#region Public Properties

public override ISceneEventHandler SceneEvents => sceneEvents;

public override int SceneBuildIndex => sceneBuildIndex;

private bool IsLoaded()
{
var scene = GetScene();
var isLoaded = scene.isLoaded;

return isLoaded;
}
public override string Name => name;

public override string ScenePath => scenePath;

public override bool IsActivate => isActivate;

public override bool IsPersist => isPersist;

public override string Name => name;
public override bool IsLoaded => GetScene().isLoaded;

public override bool IsValid => GetScene().IsValid();

public override ISceneEventHandler SceneEvents => sceneEvents;

#endregion

Expand All @@ -84,10 +73,9 @@ private bool IsLoaded()
public void OnBeforeSerialize()
{
#if UNITY_EDITOR
if (sceneAsset.TryGetSceneDetails(out var newScenePath, out var newSceneBuildIndex))
if (sceneAsset.TryGetSceneDetails(out var newScenePath, out _))
{
scenePath = newScenePath;
sceneBuildIndex = newSceneBuildIndex;
}
#endif
}
Expand All @@ -104,9 +92,28 @@ public override IEnumerator LoadRoutine()
{
sceneEvents.RaiseLoadEntered(this);

if (IsLoaded() == false)
if (IsLoaded == false)
{
#if UNITY_EDITOR
// When scenes are loaded in Editor, in some cases we might want to load a
// scene which is not added to build settings (e.g., during testing). So all checks
// are ignored in this case.
yield return LoadInternalRoutine();
#else
// In the player, checking (not IsValid) by build since the scene might not be
// loaded yet.
if (IsValidBuildIndex())
{
yield return LoadInternalRoutine();
}
else
{
Debug.LogWarning(
$"Cannot load scene - invalid Scene at path \"{scenePath}\"",
this
);
}
#endif
}
else
{
Expand All @@ -119,37 +126,81 @@ public override IEnumerator LoadRoutine()
public override IEnumerator UnloadRoutine()
{
sceneEvents.RaiseUnloadEntered(this);
yield return UnloadInternalRoutine();
if (IsLoaded)
{
#if UNITY_EDITOR
// Same as with scene loading, in Editor we want to unload even invalid scenes.
yield return UnloadInternalRoutine();
#else
// IsValid can be called as the scene had to be loaded to get to this point.
if (IsValid)
{
yield return UnloadInternalRoutine();
}
else
{
Debug.LogWarning(
$"Cannot unload scene - invalid Scene at path \"{scenePath}\"",
this
);
}
#endif
}

sceneEvents.RaiseUnloadExited(this);
}

public override void SetActive()
{
sceneEvents.RaiseActivateEntered(this);
#if UNITY_EDITOR
// Same as with scene loading, in Editor we want to activate invalid scenes.
SetActiveInternal();
#else
// In Player at this point the scene should have been loaded and we can call IsValid.
if (IsValid)
{
SetActiveInternal();
}
else
{
Debug.LogWarning(
$"Cannot activate scene - invalid Scene at path \"{scenePath}\"",
this
);
}
#endif

sceneEvents.RaiseActivateExited(this);
}

public override bool Equals(Scene otherScene)
{
var scene = GetScene();
return scene == otherScene;
}

#endregion

#region Private Methods

private IEnumerator LoadInternalRoutine()
{
if (sceneBuildIndex < 0)
var operation = StartLoadSceneOperation();

AsyncOperation StartLoadSceneOperation()
{
Debug.LogWarning(
"Cannot load scene - invalid Scene Build Index. Make sure a Scene Asset is " +
"assigned, ensure that the scene is added to project Build Settings and is " +
"enabled",
this
);
var parameters = new LoadSceneParameters(LoadSceneMode.Additive);

yield break;
#if UNITY_EDITOR
// Allow to load scenes which are not added to Build Settings (Editor only).
return UnityEditor.SceneManagement.EditorSceneManager
.LoadSceneAsyncInPlayMode(scenePath, parameters);
#else
return SceneManager.LoadSceneAsync(scenePath, parameters);
#endif
}

var operation = SceneManager.LoadSceneAsync(sceneBuildIndex, LoadSceneMode.Additive);

while (operation.isDone == false)
{
// Scene load progress range is [0, 0.9], need to remap to [0, 1] range.
Expand All @@ -162,52 +213,25 @@ private IEnumerator LoadInternalRoutine()

private IEnumerator UnloadInternalRoutine()
{
if (sceneBuildIndex < 0)
{
Debug.LogWarning(
"Cannot unload scene - invalid Scene Build Index. Make sure a Scene Asset is " +
"assigned, ensure that the scene is added to project Build Settings and is " +
"enabled",
this
);

yield break;
}

yield return SceneManager.UnloadSceneAsync(sceneBuildIndex);
yield return SceneManager.UnloadSceneAsync(scenePath);
}

private void SetActiveInternal()
{
var scene = GetScene();
if (scene.IsValid() == false)
{
Debug.LogWarning(
"Cannot activate scene - scene is invalid. Make sure a Scene Asset is " +
"assigned, ensure that the scene is added to project Build Settings and is " +
"enabled",
this
);

return;
}
var sceneByPath = SceneManager.GetSceneByPath(scenePath);
SceneManager.SetActiveScene(sceneByPath);
}

SceneManager.SetActiveScene(scene);
#if UNITY_EDITOR == false
private bool IsValidBuildIndex()
{
return SceneUtility.GetBuildIndexByScenePath(scenePath) >= 0;
}
#endif

private Scene GetScene()
{
if (sceneBuildIndex >= 0)
{
return SceneManager.GetSceneByBuildIndex(sceneBuildIndex);
}

var invalidScene = new Scene
{
name = "Invalid Scene"
};

return invalidScene;
return SceneManager.GetSceneByPath(scenePath);
}

#endregion
Expand Down
Loading

0 comments on commit f472bb6

Please sign in to comment.