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

VContainerSettings collide with Unity RuntimeTests #689

Open
mixedHans opened this issue Jul 1, 2024 · 0 comments
Open

VContainerSettings collide with Unity RuntimeTests #689

mixedHans opened this issue Jul 1, 2024 · 0 comments

Comments

@mixedHans
Copy link

mixedHans commented Jul 1, 2024

I recognized, that when you set a LifetimeScope as the RootLifetimeScope through VContainerSettings, the RootLifetimeScope gets also instantiated, when you run RuntimeTests through Unitys TestRunner. Since this is not what you want most of the time, I would like to make an improvement to the VContainerSettings class.

Add a serialized field, where you give the user the chance to decide, whether to instantiate the root lifetimescope during test runs or not

[SerializeField]
[Tooltip("Instantiates the RootLifetimeScope even in Runtime Tests.")]
public static bool UseInRuntimeTests;

And insert this check somewhere, to prevent the lifetimescope to be instantiated. This check is also beeing used from unity in the XRDeviceSimulatorLoader to prevent automatic instantiation of the XR device simulator. So I guess this would be the way to go right now. Also the upcoming TestFramework 2.0 doesn't seem to have an option to check, if a runtime test is running right now.

var scene = SceneManager.GetActiveScene();
if(scene.IsValid() && scene.name.StartsWith("InitTestScene") && UseInRuntimeTests == false)
     return null;

My custom VContainerSettings class looks like this now. I think it would be nice, if we would see something like that in some of the the next updates.

using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace VContainer.Unity
{
    public sealed class VContainerSettings : ScriptableObject
    {
        public static VContainerSettings Instance { get; private set; }
        public static bool DiagnosticsEnabled => Instance != null && Instance.EnableDiagnostics;

        static LifetimeScope rootLifetimeScopeInstance;

        [SerializeField]
        [Tooltip("Set the Prefab to be the parent of the entire Project.")]
        public LifetimeScope RootLifetimeScope;

        [SerializeField]
        [Tooltip("Enables the collection of information that can be viewed in the VContainerDiagnosticsWindow. Note: Performance degradation")]
        public bool EnableDiagnostics;

        [SerializeField]
        [Tooltip("Disables script modification for LifetimeScope scripts.")]
        public bool DisableScriptModifier;

        [SerializeField]
        [Tooltip("Removes (Clone) postfix in IObjectResolver.Instantiate() and IContainerBuilder.RegisterComponentInNewPrefab().")]
        public bool RemoveClonePostfix;
        
        [SerializeField]
        [Tooltip("Instantiates the RootLifetimeScope in Runtime Tests scenes.")]
        public bool UseInRuntimeTests;

#if UNITY_EDITOR
        [UnityEditor.MenuItem("Assets/Create/VContainer/Custom VContainer Settings")]
        public static void CreateAsset()
        {
            var path = UnityEditor.EditorUtility.SaveFilePanelInProject(
                "Save VContainerSettings",
                "VContainerSettings",
                "asset",
                string.Empty);

            if (string.IsNullOrEmpty(path))
                return;

            var newSettings = CreateInstance<VContainerSettings>();
            UnityEditor.AssetDatabase.CreateAsset(newSettings, path);

            var preloadedAssets = UnityEditor.PlayerSettings.GetPreloadedAssets().ToList();
            preloadedAssets.RemoveAll(x => x is VContainerSettings or VContainerSettings);
            preloadedAssets.Add(newSettings);
            UnityEditor.PlayerSettings.SetPreloadedAssets(preloadedAssets.ToArray());
        }

        public static void LoadInstanceFromPreloadAssets()
        {
            var preloadAsset = UnityEditor.PlayerSettings.GetPreloadedAssets().FirstOrDefault(x => x is VContainerSettings);
            if (preloadAsset is VContainerSettings instance)
            {
                instance.OnDisable();
                instance.OnEnable();
            }
        }

        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
        static void RuntimeInitialize()
        {
            // For editor, we need to load the Preload asset manually.
            LoadInstanceFromPreloadAssets();
        }
#endif

        public LifetimeScope GetOrCreateRootLifetimeScopeInstance()
        {
            var scene = SceneManager.GetActiveScene();
            if(scene.IsValid() && scene.name.StartsWith("InitTestScene") && UseInRuntimeTests == false)
                return null;
            
            if (RootLifetimeScope != null && rootLifetimeScopeInstance == null)
            {
                var activeBefore = RootLifetimeScope.gameObject.activeSelf;
                RootLifetimeScope.gameObject.SetActive(false);

                rootLifetimeScopeInstance = Instantiate(RootLifetimeScope);
                DontDestroyOnLoad(rootLifetimeScopeInstance);
                rootLifetimeScopeInstance.gameObject.SetActive(true);

                RootLifetimeScope.gameObject.SetActive(activeBefore);
            }
            return rootLifetimeScopeInstance;
        }

        public bool IsRootLifetimeScopeInstance(LifetimeScope lifetimeScope) =>
            RootLifetimeScope == lifetimeScope || rootLifetimeScopeInstance == lifetimeScope;

        void OnEnable()
        {
            if (Application.isPlaying)
            {
                Instance = this;

                var activeScene = SceneManager.GetActiveScene();
                if (activeScene.isLoaded)
                {
                    OnFirstSceneLoaded(activeScene, default);
                }
                else
                {
                    SceneManager.sceneLoaded -= OnFirstSceneLoaded;
                    SceneManager.sceneLoaded += OnFirstSceneLoaded;
                }
            }
        }

        void OnDisable()
        {
            Instance = null;
        }

        void OnFirstSceneLoaded(Scene scene, LoadSceneMode mode)
        {
            if (RootLifetimeScope != null &&
                RootLifetimeScope.autoRun &&
                (rootLifetimeScopeInstance == null || rootLifetimeScopeInstance.Container == null))
            {
                GetOrCreateRootLifetimeScopeInstance();
            }
            SceneManager.sceneLoaded -= OnFirstSceneLoaded;
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant