Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: do not add GlobalActivator if there are no avatars in the scene #318

Merged
merged 2 commits into from
Aug 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG-PRERELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog].
### Added

### Changed
- ApplyOnPlayGlobalActivator is no longer added for scens without avatars `#318`

### Deprecated

Expand Down
15 changes: 13 additions & 2 deletions Internal/ApplyOnPlay/Editor/ApplyOnPlayCaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,23 @@ static ApplyOnPlayCaller()
ApplyOnPlayCallbackRegistry.GetCallbacks());
};

EditorSceneManager.sceneOpened += (scene, _) => GlobalActivator.CreateIfNotPresent(scene);
EditorSceneManager.newSceneCreated += (scene, _1, _2) =>
EditorApplication.delayCall += () => SceneChangeReceiver.CreateIfNotExists(scene);
EditorSceneManager.sceneOpened += (scene, _) => GlobalActivator.CreateIfNotNeeded(scene);

EditorApplication.playModeStateChanged += state =>
{
if (state != PlayModeStateChange.EnteredEditMode) return;
foreach (var scene in Enumerable.Range(0, SceneManager.sceneCount)
.Select(SceneManager.GetSceneAt))
SceneChangeReceiver.CreateIfNotNeeded(scene);
};

EditorApplication.delayCall += () =>
{
foreach (var scene in Enumerable.Range(0, SceneManager.sceneCount)
.Select(SceneManager.GetSceneAt))
GlobalActivator.CreateIfNotPresent(scene);
GlobalActivator.CreateIfNotNeeded(scene);
};
}

Expand Down
2 changes: 2 additions & 0 deletions Internal/ApplyOnPlay/Runtime/ApplyOnPlayActivator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace Anatawa12.ApplyOnPlay
{
[DefaultExecutionOrder(-100000)]
[ExecuteAlways]
[AddComponentMenu("")]
[DisallowMultipleComponent]
internal class ApplyOnPlayActivator : MonoBehaviour
{
#if UNITY_EDITOR
Expand Down
55 changes: 51 additions & 4 deletions Internal/ApplyOnPlay/Runtime/GlobalActivator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
using UnityEditor.SceneManagement;
#endif
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
using VRC.SDKBase;

namespace Anatawa12.ApplyOnPlay
{
[DefaultExecutionOrder(-100000)]
[ExecuteAlways]
[AddComponentMenu("")]
[DisallowMultipleComponent]
internal class GlobalActivator : MonoBehaviour
{
#if UNITY_EDITOR
Expand All @@ -21,17 +25,42 @@ private void Awake()
activate?.Invoke(this);
}

internal static void CreateIfNotPresent(Scene scene)
internal static bool HasAvatarInScene(Scene scene)
{
return scene.GetRootGameObjects().Any(x => x.GetComponentInChildren<VRC_AvatarDescriptor>(true));
}

internal static void CreateIfNotNeeded(Scene scene)
{
if (!scene.IsValid() || EditorSceneManager.IsPreviewScene(scene)) return;
if (EditorApplication.isPlayingOrWillChangePlaymode) return;

if (HasAvatarInScene(scene))
{
CreateIfNotExists(scene);
}
else
{
SceneChangeReceiver.CreateIfNotExists(scene);
foreach (var root in scene.GetRootGameObjects())
{
if (root.GetComponent<GlobalActivator>() != null)
{
DestroyImmediate(root);
EditorSceneManager.MarkSceneDirty(scene);
}
}
}
}

private static void CreateIfNotExists(Scene scene)
{
bool rootPresent = false;
foreach (var root in scene.GetRootGameObjects())
{
if (root.GetComponent<GlobalActivator>() != null)
{
root.hideFlags = HIDE_FLAGS;
root.hideFlags = HideFlags;
root.SetActive(true);
if (rootPresent) DestroyImmediate(root);
rootPresent = true;
Expand All @@ -46,15 +75,33 @@ internal static void CreateIfNotPresent(Scene scene)
SceneManager.SetActiveScene(scene);
var gameObject = new GameObject("ApplyOnPlayGlobalActivator");
gameObject.AddComponent<GlobalActivator>();
gameObject.hideFlags = HIDE_FLAGS;
gameObject.hideFlags = HideFlags;
}
finally
{
SceneManager.SetActiveScene(oldActiveScene);
}
}

private void OnValidate()
{
if (EditorApplication.isPlayingOrWillChangePlaymode) return;

EditorApplication.delayCall += () =>
{
if (this == null) return;

gameObject.hideFlags = HideFlags;
if (!HasAvatarInScene(gameObject.scene))
{
var scene = gameObject.scene;
DestroyImmediate(gameObject);
EditorSceneManager.MarkSceneDirty(scene);
}
};
}

private const HideFlags HIDE_FLAGS = HideFlags.HideInHierarchy;
private const HideFlags HideFlags = UnityEngine.HideFlags.HideInHierarchy;
#endif
}
}
73 changes: 73 additions & 0 deletions Internal/ApplyOnPlay/Runtime/SceneChangeReceiver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Anatawa12.ApplyOnPlay
{
[ExecuteAlways]
[AddComponentMenu("")]
[DisallowMultipleComponent]
public class SceneChangeReceiver : MonoBehaviour
{
#if UNITY_EDITOR
public Scene scene;

void Update()
{
if (scene.IsValid())
{
if (GlobalActivator.HasAvatarInScene(scene))
{
GlobalActivator.CreateIfNotNeeded(scene);
DestroyImmediate(this);
}
}
else
{
DestroyImmediate(this);
}
}

internal static void CreateIfNotNeeded(Scene scene)
{
if (!scene.IsValid() || UnityEditor.SceneManagement.EditorSceneManager.IsPreviewScene(scene)) return;
if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode) return;
if (GlobalActivator.HasAvatarInScene(scene)) return;
CreateIfNotExists(scene);
}

internal static void CreateIfNotExists(Scene scene)
{
bool rootPresent = false;
foreach (var root in scene.GetRootGameObjects())
{
if (root.GetComponent<SceneChangeReceiver>() != null)
{
root.hideFlags = HideFlags;
root.SetActive(true);
if (rootPresent) DestroyImmediate(root);
rootPresent = true;
}
}

if (rootPresent) return;

var oldActiveScene = SceneManager.GetActiveScene();
try
{
SceneManager.SetActiveScene(scene);
var gameObject = new GameObject("ApplyOnPlaySceneChangeReceiver");
var component = gameObject.AddComponent<SceneChangeReceiver>();
component.scene = scene;
gameObject.hideFlags = HideFlags;
component.hideFlags = HideFlags;
}
finally
{
SceneManager.SetActiveScene(oldActiveScene);
}
}

private const HideFlags HideFlags = UnityEngine.HideFlags.HideAndDontSave;
#endif
}
}
3 changes: 3 additions & 0 deletions Internal/ApplyOnPlay/Runtime/SceneChangeReceiver.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [],
"precompiledReferences": [
"VRCSDKBase.dll"
],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
Expand Down