Files
dungeons/Assets/Plugins/Zenject/Source/Install/Contexts/ProjectContext.cs

299 lines
9.2 KiB
C#

#if !NOT_UNITY3D
using System;
using System.Collections.Generic;
using System.Threading;
using ModestTree;
using UnityEngine;
using Zenject.Internal;
namespace Zenject
{
public class ProjectContext : Context
{
public static event Action PreInstall;
public static event Action PostInstall;
public static event Action PreResolve;
public static event Action PostResolve;
public const string ProjectContextResourcePath = "ProjectContext";
public const string ProjectContextResourcePathOld = "ProjectCompositionRoot";
static ProjectContext _instance;
// TODO: Set this to false the next time major version is incremented
[Tooltip("When true, objects that are created at runtime will be parented to the ProjectContext")]
[SerializeField]
bool _parentNewObjectsUnderContext = true;
[SerializeField]
ReflectionBakingCoverageModes _editorReflectionBakingCoverageMode = ReflectionBakingCoverageModes.FallbackToDirectReflection;
[SerializeField]
ReflectionBakingCoverageModes _buildsReflectionBakingCoverageMode = ReflectionBakingCoverageModes.FallbackToDirectReflection;
[SerializeField]
ZenjectSettings _settings = null;
DiContainer _container;
public override DiContainer Container
{
get { return _container; }
}
public static bool HasInstance
{
get { return _instance != null; }
}
public static ProjectContext Instance
{
get
{
if (_instance == null)
{
InstantiateAndInitialize();
Assert.IsNotNull(_instance);
}
return _instance;
}
}
public static bool ValidateOnNextRun
{
get;
set;
}
public override IEnumerable<GameObject> GetRootGameObjects()
{
return new[] { gameObject };
}
public static GameObject TryGetPrefab()
{
var prefabs = Resources.LoadAll(ProjectContextResourcePath, typeof(GameObject));
if (prefabs.Length > 0)
{
Assert.That(prefabs.Length == 1,
"Found multiple project context prefabs at resource path '{0}'", ProjectContextResourcePath);
return (GameObject)prefabs[0];
}
prefabs = Resources.LoadAll(ProjectContextResourcePathOld, typeof(GameObject));
if (prefabs.Length > 0)
{
Assert.That(prefabs.Length == 1,
"Found multiple project context prefabs at resource path '{0}'", ProjectContextResourcePathOld);
return (GameObject)prefabs[0];
}
return null;
}
static void InstantiateAndInitialize()
{
#if UNITY_EDITOR
ProfileBlock.UnityMainThread = Thread.CurrentThread;
#endif
Assert.That(FindObjectsOfType<ProjectContext>().IsEmpty(),
"Tried to create multiple instances of ProjectContext!");
var prefab = TryGetPrefab();
var prefabWasActive = false;
#if ZEN_INTERNAL_PROFILING
using (ProfileTimers.CreateTimedBlock("GameObject.Instantiate"))
#endif
{
if (prefab == null)
{
_instance = new GameObject("ProjectContext")
.AddComponent<ProjectContext>();
}
else
{
prefabWasActive = prefab.activeSelf;
GameObject gameObjectInstance;
#if UNITY_EDITOR
if(prefabWasActive)
{
// This ensures the prefab's Awake() methods don't fire (and, if in the editor, that the prefab file doesn't get modified)
gameObjectInstance = GameObject.Instantiate(prefab, ZenUtilInternal.GetOrCreateInactivePrefabParent());
gameObjectInstance.SetActive(false);
gameObjectInstance.transform.SetParent(null, false);
}
else
{
gameObjectInstance = GameObject.Instantiate(prefab);
}
#else
if(prefabWasActive)
{
prefab.SetActive(false);
gameObjectInstance = GameObject.Instantiate(prefab);
prefab.SetActive(true);
}
else
{
gameObjectInstance = GameObject.Instantiate(prefab);
}
#endif
_instance = gameObjectInstance.GetComponent<ProjectContext>();
Assert.IsNotNull(_instance,
"Could not find ProjectContext component on prefab 'Resources/{0}.prefab'", ProjectContextResourcePath);
}
}
// Note: We use Initialize instead of awake here in case someone calls
// ProjectContext.Instance while ProjectContext is initializing
_instance.Initialize();
if (prefabWasActive)
{
#if ZEN_INTERNAL_PROFILING
using (ProfileTimers.CreateTimedBlock("User Code"))
#endif
{
// We always instantiate it as disabled so that Awake and Start events are triggered after inject
_instance.gameObject.SetActive(true);
}
}
}
public bool ParentNewObjectsUnderContext
{
get { return _parentNewObjectsUnderContext; }
set { _parentNewObjectsUnderContext = value; }
}
public void EnsureIsInitialized()
{
// Do nothing - Initialize occurs in Instance property
}
public void Awake()
{
if (Application.isPlaying)
// DontDestroyOnLoad can only be called when in play mode and otherwise produces errors
// ProjectContext is created during design time (in an empty scene) when running validation
// and also when running unit tests
// In these cases we don't need DontDestroyOnLoad so just skip it
{
DontDestroyOnLoad(gameObject);
}
}
void Initialize()
{
Assert.IsNull(_container);
if (Application.isEditor)
{
TypeAnalyzer.ReflectionBakingCoverageMode = _editorReflectionBakingCoverageMode;
}
else
{
TypeAnalyzer.ReflectionBakingCoverageMode = _buildsReflectionBakingCoverageMode;
}
var isValidating = ValidateOnNextRun;
// Reset immediately to ensure it doesn't get used in another run
ValidateOnNextRun = false;
_container = new DiContainer(
new[] { StaticContext.Container }, isValidating);
// Do this after creating DiContainer in case it's needed by the pre install logic
if (PreInstall != null)
{
PreInstall();
}
var injectableMonoBehaviours = new List<MonoBehaviour>();
GetInjectableMonoBehaviours(injectableMonoBehaviours);
foreach (var instance in injectableMonoBehaviours)
{
_container.QueueForInject(instance);
}
_container.IsInstalling = true;
try
{
InstallBindings(injectableMonoBehaviours);
}
finally
{
_container.IsInstalling = false;
}
if (PostInstall != null)
{
PostInstall();
}
if (PreResolve != null)
{
PreResolve();
}
_container.ResolveRoots();
if (PostResolve != null)
{
PostResolve();
}
}
protected override void GetInjectableMonoBehaviours(List<MonoBehaviour> monoBehaviours)
{
ZenUtilInternal.AddStateMachineBehaviourAutoInjectersUnderGameObject(gameObject);
ZenUtilInternal.GetInjectableMonoBehavioursUnderGameObject(gameObject, monoBehaviours);
}
void InstallBindings(List<MonoBehaviour> injectableMonoBehaviours)
{
if (_parentNewObjectsUnderContext)
{
_container.DefaultParent = transform;
}
else
{
_container.DefaultParent = null;
}
_container.Settings = _settings ?? ZenjectSettings.Default;
_container.Bind<ZenjectSceneLoader>().AsSingle();
ZenjectManagersInstaller.Install(_container);
_container.Bind<Context>().FromInstance(this);
_container.Bind(typeof(ProjectKernel), typeof(MonoKernel))
.To<ProjectKernel>().FromNewComponentOn(gameObject).AsSingle().NonLazy();
_container.Bind<SceneContextRegistry>().AsSingle();
InstallSceneBindings(injectableMonoBehaviours);
InstallInstallers();
}
}
}
#endif