예제 #1
0
        public static async Task InitializeAsync()
        {
            if (Engine.IsInitialized)
            {
                return;
            }

            var initializationUI = default(ScriptableUIBehaviour);

            if (engineConfig.ShowInitializationUI)
            {
                var initUIPrefab = ObjectUtils.IsValid(engineConfig.CustomInitializationUI) ? engineConfig.CustomInitializationUI : Resources.Load <ScriptableUIBehaviour>(defaultInitUIResourcesPath);
                initializationUI = Instantiate(initUIPrefab);
                initializationUI.Show();
            }

            var behaviour = RuntimeBehaviour.Create();
            var services  = new List <IEngineService>();

            bool isService(Type t) => typeof(IEngineService).IsAssignableFrom(t);
            bool isBehaviour(Type t) => typeof(IEngineBehaviour).IsAssignableFrom(t);
            bool isConfig(Type t) => typeof(Configuration).IsAssignableFrom(t);

            var attrType     = typeof(InitializeAtRuntimeAttribute);
            var serviceTypes = ReflectionUtils.ExportedDomainTypes.Where(type => type.IsDefined(attrType, false));

            serviceTypes = serviceTypes.OrderBy(t => (t.GetCustomAttributes(attrType, false).First() as InitializeAtRuntimeAttribute).InitializationPriority);
            serviceTypes = serviceTypes.TopologicalOrder(t => t.GetConstructors().First().GetParameters().Where(p => isService(p.ParameterType)).Select(p => p.ParameterType));
            var ctorParams = new List <object>();

            foreach (var serviceType in serviceTypes)
            {
                var paramTypes = serviceType.GetConstructors().First().GetParameters().Select(p => p.ParameterType);
                foreach (var paramType in paramTypes)
                {
                    if (isService(paramType) && serviceTypes.Contains(paramType))
                    {
                        ctorParams.Add(services.First(s => s.GetType() == paramType));
                    }
                    else if (isBehaviour(paramType))
                    {
                        ctorParams.Add(behaviour);
                    }
                    else if (isConfig(paramType))
                    {
                        ctorParams.Add(Configuration.LoadOrDefault(paramType));
                    }
                    else
                    {
                        Debug.LogError($"Only `{nameof(Configuration)}`, `{nameof(IEngineBehaviour)}` and `{nameof(IEngineService)}` with an `{nameof(InitializeAtRuntimeAttribute)}` can be requested in an engine service constructor.");
                    }
                }
                var service = Activator.CreateInstance(serviceType, ctorParams.ToArray()) as IEngineService;
                services.Add(service);
                ctorParams.Clear();
            }

            await Engine.InitializeAsync(engineConfig, behaviour, services);

            if (initializationUI)
            {
                await initializationUI.SetIsVisibleAsync(false);

                Destroy(initializationUI.gameObject);
            }

            var moviePlayer = Engine.GetService <MoviePlayer>();

            if (moviePlayer.PlayIntroMovie)
            {
                await moviePlayer.PlayAsync(moviePlayer.IntroMovieName);
            }

            var scriptsConfig = Configuration.LoadOrDefault <ScriptsConfiguration>();

            if (!string.IsNullOrEmpty(scriptsConfig.InitializationScript))
            {
                await Engine.GetService <ScriptPlayer>()?.PreloadAndPlayAsync(scriptsConfig.InitializationScript);
            }

            if (engineConfig.ShowTitleUI)
            {
                Engine.GetService <UIManager>()?.GetUI <UI.ITitleUI>()?.Show();
            }

            if (scriptsConfig.ShowNavigatorOnInit)
            {
                Engine.GetService <ScriptManager>().ShowNavigator();
            }
        }
예제 #2
0
        /// <summary>
        /// Invokes default engine initialization routine.
        /// </summary>
        /// <param name="configurationProvider">Configuration provider to use for engine initialization.</param>
        public static async UniTask InitializeAsync(IConfigurationProvider configurationProvider = null)
        {
            if (Engine.Initialized)
            {
                return;
            }
            if (initializeTCS != null)
            {
                await initializeTCS.Task; return;
            }

            initializeTCS = new UniTaskCompletionSource();

            if (configurationProvider is null)
            {
                configurationProvider = new ProjectConfigurationProvider();
            }
            var engineConfig = configurationProvider.GetConfiguration <EngineConfiguration>();

            UniTaskScheduler.UnobservedExceptionWriteLogType = engineConfig.AsyncExceptionLogType;

            var initializationUI = default(ScriptableUIBehaviour);

            if (engineConfig.ShowInitializationUI)
            {
                var initUIPrefab = ObjectUtils.IsValid(engineConfig.CustomInitializationUI) ? engineConfig.CustomInitializationUI : Resources.Load <ScriptableUIBehaviour>(defaultInitUIResourcesPath);
                initializationUI = Instantiate(initUIPrefab);
                initializationUI.Show();
            }

            var initData       = new List <ServiceInitData>();
            var overridenTypes = new List <Type>();

            foreach (var type in Engine.Types)
            {
                var initAttribute = Attribute.GetCustomAttribute(type, typeof(InitializeAtRuntimeAttribute), false) as InitializeAtRuntimeAttribute;
                if (initAttribute is null)
                {
                    continue;
                }
                initData.Add(new ServiceInitData(type, initAttribute));
                if (initAttribute.Override != null)
                {
                    overridenTypes.Add(initAttribute.Override);
                }
            }
            initData = initData.Where(d => !overridenTypes.Contains(d.Type)).ToList(); // Exclude services overriden by user.

            bool IsService(Type t) => typeof(IEngineService).IsAssignableFrom(t);
            bool IsBehaviour(Type t) => typeof(IEngineBehaviour).IsAssignableFrom(t);
            bool IsConfig(Type t) => typeof(Configuration).IsAssignableFrom(t);

            // Order by initialization priority and then perform topological order to make sure ctor references initialized before they're used.
            // ReSharper disable once AccessToModifiedClosure (false positive: we're assigning result of the closure to the variable in question)
            IEnumerable <ServiceInitData> GetDependencies(ServiceInitData d) => d.CtorArgs.Where(IsService).SelectMany(argType => initData.Where(dd => d != dd && argType.IsAssignableFrom(dd.Type)));

            initData = initData.OrderBy(d => d.Priority).TopologicalOrder(GetDependencies).ToList();

            var behaviour  = RuntimeBehaviour.Create(engineConfig.SceneIndependent);
            var services   = new List <IEngineService>();
            var ctorParams = new List <object>();

            foreach (var data in initData)
            {
                foreach (var argType in data.CtorArgs)
                {
                    if (IsService(argType))
                    {
                        ctorParams.Add(services.First(s => argType.IsInstanceOfType(s)));
                    }
                    else if (IsBehaviour(argType))
                    {
                        ctorParams.Add(behaviour);
                    }
                    else if (IsConfig(argType))
                    {
                        ctorParams.Add(configurationProvider.GetConfiguration(argType));
                    }
                    else
                    {
                        throw new Exception($"Only `{nameof(Configuration)}`, `{nameof(IEngineBehaviour)}` and `{nameof(IEngineService)}` with an `{nameof(InitializeAtRuntimeAttribute)}` can be requested in an engine service constructor.");
                    }
                }
                var service = Activator.CreateInstance(data.Type, ctorParams.ToArray()) as IEngineService;
                services.Add(service);
                ctorParams.Clear();
            }

            await Engine.InitializeAsync(configurationProvider, behaviour, services);

            if (!Engine.Initialized) // In case terminated in the midst of initialization.
            {
                if (initializationUI != null)
                {
                    ObjectUtils.DestroyOrImmediate(initializationUI.gameObject);
                }
                DisposeTCS();
                return;
            }

            ExpressionEvaluator.Initialize();

            if (initializationUI != null)
            {
                await initializationUI.ChangeVisibilityAsync(false);

                ObjectUtils.DestroyOrImmediate(initializationUI.gameObject);
            }

            var moviePlayer = Engine.GetService <IMoviePlayer>();

            if (moviePlayer.Configuration.PlayIntroMovie)
            {
                await moviePlayer.PlayAsync(moviePlayer.Configuration.IntroMovieName);
            }

            var scriptPlayer  = Engine.GetService <IScriptPlayer>();
            var scriptManager = Engine.GetService <IScriptManager>();

            if (!string.IsNullOrEmpty(scriptManager.Configuration.InitializationScript))
            {
                await scriptPlayer.PreloadAndPlayAsync(scriptManager.Configuration.InitializationScript);

                while (scriptPlayer.Playing)
                {
                    await AsyncUtils.WaitEndOfFrame;
                }
            }

            if (engineConfig.ShowTitleUI)
            {
                Engine.GetService <IUIManager>().GetUI <UI.ITitleUI>()?.Show();
            }

            if (scriptManager.Configuration.ShowNavigatorOnInit && scriptManager.ScriptNavigator)
            {
                scriptManager.ScriptNavigator.Show();
            }

            DisposeTCS();
        }