static int CheckMissingTraits <T>(FunctionalityIsland island, HashSet <T> requiredTraits)
            where T : TraitDefinition
        {
            var compareSet     = new HashSet <TraitDefinition>(requiredTraits);
            var existingTraits = new HashSet <TraitDefinition>();

            foreach (var kvp in island.providers)
            {
                var traitsProvider = kvp.Value as IProvidesTraits;
                if (traitsProvider == null)
                {
                    continue;
                }

                var providedTraits = traitsProvider.GetProvidedTraits();
                existingTraits.UnionWith(providedTraits);
            }

            foreach (var definition in existingTraits)
            {
                compareSet.Remove(definition);
            }

            return(compareSet.Count);
        }
コード例 #2
0
 /// <summary>
 /// Inject functionality on all modules using the provided FunctionalityIsland
 /// </summary>
 /// <param name="island">The functionality island to use for functionality injection</param>
 public void InjectFunctionalityInModules(FunctionalityIsland island)
 {
     foreach (var module in m_Modules)
     {
         island.InjectFunctionalitySingle(module);
     }
 }
コード例 #3
0
        void IModule.UnloadModule()
        {
            m_SlowTaskModule.ClearTasks();
            m_SimulationPollTask = null;
            QueryObjectMapping.Map.Clear();
            EditorApplication.update -= Update;
            SimulationSceneModule.SimulationSceneOpened  -= OnSimulationSceneOpened;
            SimulationSceneModule.SimulationSceneClosing -= OnSimulationSceneClosing;
            EditorOnlyDelegates.IsSimulatingTemporal      = null;
            RestoreOriginalActiveIsland();

            m_SimulationRestartNeeded  = false;
            NextSimModeSelection       = SimulationModeSelection.NoModePreference;
            KeepDataBetweenSimulations = false;
            m_SimulationPollTask       = null;
            m_OriginalActiveIsland     = null;

            CleanupProviders();

            simulating          = false;
            simulatingTemporal  = false;
            functionalityIsland = null;
            providersRoot       = null;

            m_SimulationContext.Clear();
        }
        static FunctionalityInjectionModuleEditor()
        {
#if UNITY_2019_2_OR_NEWER
            foreach (var type in TypeCache.GetTypesDerivedFrom <IFunctionalityProvider>())
            {
                if (type.IsAbstract || type.IsInterface)
                {
                    continue;
                }

                k_AllProviderTypes.Add(type);
            }

            foreach (var type in TypeCache.GetTypesDerivedFrom <IFunctionalitySubscriber>())
            {
                if (type.IsAbstract || type.IsInterface)
                {
                    continue;
                }

                k_AllSubscriberTypes.Add(type);
            }
#else
            typeof(IFunctionalityProvider).GetImplementationsOfInterface(k_AllProviderTypes);
            typeof(IFunctionalitySubscriber).GetImplementationsOfInterface(k_AllSubscriberTypes);
#endif

            k_AllProviderTypes.Sort((a, b) =>
            {
                var optionsA = FunctionalityIsland.GetProviderSelectionOptions(a);
                var optionsB = FunctionalityIsland.GetProviderSelectionOptions(b);
                return(optionsB.Priority.CompareTo(optionsA.Priority));
            });
        }
 void OnEnable()
 {
     m_Island = (FunctionalityIsland)target;
     if (ShowAllProviderTypes)
     {
         m_ShowAllProviderTypes = true;
     }
 }
        /// <summary>
        /// Set the active island
        /// </summary>
        /// <param name="island">The island to set as the active island; it must have already been added</param>
        public void SetActiveIsland(FunctionalityIsland island)
        {
            Assert.IsTrue(m_Islands.Contains(island), string.Format("Cannot set active island to {0}. It is not in the list of islands", island));
            activeIsland = island;

            if (activeIslandChanged != null)
            {
                activeIslandChanged(island);
            }
        }
コード例 #7
0
        void CacheOriginalActiveIsland()
        {
            // This module does not override the active island in play mode
            if (Application.isPlaying)
            {
                return;
            }

            m_OriginalActiveIsland = m_FIModule.activeIsland;
        }
コード例 #8
0
        void IModuleDependency <FunctionalityInjectionModule> .ConnectDependency(FunctionalityInjectionModule dependency)
        {
            m_FIModule = dependency;
            // TODO: Collect all scenes and add islands if modules persist between scene loads
#if UNITY_EDITOR
            var session = Application.isPlaying ?
                          MARSSession.Instance :
                          MarsRuntimeUtils.GetMarsSessionInActiveScene();
#else
            var session = MARSSession.Instance;
#endif

            // TODO: Don't load modules for non-MARS scenes
            if (session == null)
            {
                return;
            }

            FunctionalityIsland island = null;

            if (session.island)
            {
                island = session.island;
            }

#if UNITY_EDITOR
            if (Application.isPlaying && m_SimulateInPlayMode)
            {
                if (m_SimulateDiscovery)
                {
                    if (m_SimulatedDiscoveryIsland == null)
                    {
                        Debug.LogWarning("There is no simulated discovery island set in the MARSSceneModule to be used for play mode simulation");
                        return;
                    }

                    island = m_SimulatedDiscoveryIsland;
                }
                else
                {
                    if (m_SimulationIsland == null)
                    {
                        Debug.LogWarning("There is no simulation island set in the MARSSceneModule to be used for play mode simulation");
                        return;
                    }

                    island = m_SimulationIsland;
                }
            }
#endif
            if (island)
            {
                dependency.AddIsland(island);
            }
        }
        /// <summary>
        /// Set up a Functionality Island and add it to the list of islands
        /// This must be done before the FunctionalityInjectionModule is loaded
        /// The recommended pattern is to implement IModuleDependency&lt;FunctionalityInjectionModule&gt; and add the
        /// island in ConnectDependency. If a hard dependency is not possible, ensure your module has a load order
        /// which is earlier than FunctionalityInjectionModule and add the island in LoadModule
        /// </summary>
        /// <param name="island">The functionality island to add to the list of islands</param>
        public void AddIsland(FunctionalityIsland island)
        {
            // Do not add the default island, as it will be added automatically
            if (island == m_DefaultIsland)
            {
                return;
            }

            Assert.IsFalse(m_Loaded, "It is too late to add a functionality island. All modules are loaded");
            Assert.IsNotNull(island, "Trying to add an island that is null");
            var wasAdded = m_Islands.Add(island);

            Assert.IsTrue(wasAdded, "Island has already been added");

            island.Setup();
        }
        /// <summary>
        /// Called before system shuts down
        /// </summary>
        void IModule.UnloadModule()
        {
            foreach (var island in m_Islands)
            {
                if (island)
                {
                    island.Unload();
                }
                else
                {
                    Debug.LogError("Encountered a null island during Unload--this should only happen if you recently deleted a Functionality Island asset");
                }
            }

            activeIsland = null;
            m_Islands.Clear();
            m_Loaded = false;
        }
        public static void GetProvidedTraits(this FunctionalityIsland island, HashSet <TraitDefinition> traits)
        {
            if (traits.Count == 0)
            {
                return;
            }

            foreach (var kvp in island.providers)
            {
                var traitsProvider = kvp.Value as IProvidesTraits;
                if (traitsProvider == null)
                {
                    continue;
                }

                var providedTraits = traitsProvider.GetProvidedTraits();
                traits.UnionWith(providedTraits);
            }
        }
        // We have to set up islands before the other modules get loaded so they can use FI
        internal void PreLoad()
        {
            if (!m_DefaultIsland)
            {
#if UNITY_EDITOR
                DebugUtils.Log("You must set up a default functionality island. One has been created for you.");
                m_DefaultIsland = CreateInstance <FunctionalityIsland>();
                AssetDatabase.CreateAsset(m_DefaultIsland, k_DefaultIslandPath);
                EditorUtility.SetDirty(this);
                if (!Application.isBatchMode)
                {
                    AssetDatabase.SaveAssets();
                }
#else
                Debug.LogError("You must set up a default functionality island.");
                return;
#endif
            }

            m_DefaultIsland.Setup();
            m_Islands.Add(m_DefaultIsland);
            activeIsland = m_DefaultIsland;
        }
 public static void DrawProviders(FunctionalityIsland island)
 {
     using (new EditorGUI.DisabledScope(true))
     {
         using (new EditorGUI.IndentLevelScope())
         {
             foreach (var row in island.providers)
             {
                 var provider     = row.Value;
                 var providerType = row.Key.GetNameWithGenericArguments();
                 var unityObject  = provider as UnityObject;
                 if (unityObject)
                 {
                     EditorGUILayout.ObjectField(providerType, unityObject, typeof(UnityObject), true);
                 }
                 else
                 {
                     EditorGUILayout.LabelField(providerType, row.Value.GetType().GetNameWithGenericArguments());
                 }
             }
         }
     }
 }
コード例 #14
0
 void OnActiveIslandChanged(FunctionalityIsland island)
 {
     ResetReasoningAPIs();
 }
        /// <summary>
        /// Set up functionality providers from the list of default providers
        /// This allows custom serialized data to be set up on prefabs for providers
        /// </summary>
        /// <param name="island">The functionality island on which to set up default providers</param>
        /// <param name="requiredTraits">The required traits that must be satisfied by providers</param>
        /// <param name="newProviders">(Optional) A list to which new providers will be added</param>
        public static void RequireProvidersWithDefaultProviders(this FunctionalityIsland island, HashSet <TraitDefinition> requiredTraits, List <IFunctionalityProvider> newProviders = null)
        {
            if (requiredTraits.Count == 0)
            {
                return;
            }

            Profiler.BeginSample(FunctionalityIsland.SetupDefaultProvidersProfilerLabel);

            island.CheckSetup();

            var functionalityInjectionModuleLogging = ModuleLoaderDebugSettings.instance.functionalityInjectionModuleLogging;

            if (functionalityInjectionModuleLogging)
            {
                var list = new StringBuilder();

                if (requiredTraits.Count > 0)
                {
                    foreach (var trait in requiredTraits)
                    {
                        list.Append(trait);
                        list.Append(", ");
                    }

                    list.Length -= 2;
                }

                Debug.LogFormat("Requiring providers with defaults on: {0}", string.Join(", ", list));
            }

            // Copy the collection so that we don't modify the original
            requiredTraits = new HashSet <TraitDefinition>(requiredTraits);

            // Clear out traits that are already being provided
            foreach (var provider in island.uniqueProviders)
            {
                var traitsProvider = provider as IProvidesTraits;
                if (traitsProvider != null)
                {
                    var providedTraits = traitsProvider.GetProvidedTraits();
                    foreach (var trait in providedTraits)
                    {
                        requiredTraits.Remove(trait);
                    }
                }
            }

            k_DefaultProviderMap.Clear();
            foreach (var row in island.defaultProviders)
            {
                var providerTypeName = row.providerTypeName;

                var prefab = row.defaultProviderPrefab;
                if (prefab != null)
                {
                    var providersInPrefab = prefab.GetComponentsInChildren <IFunctionalityProvider>();
                    foreach (var provider in providersInPrefab)
                    {
                        k_DefaultProviderMap[provider.GetType()] = row;
                    }

                    continue;
                }

                var defaultProviderType = row.defaultProviderType;
                if (defaultProviderType == null)
                {
                    var defaultProviderTypeName = row.defaultProviderTypeName;
                    Debug.LogWarningFormat("Cannot set up default provider for {0} in {1}. Type {2} cannot be found.", providerTypeName, island.name, defaultProviderTypeName);
                    continue;
                }

                k_DefaultProviderMap[defaultProviderType] = row;
            }

            // Determine which provider interfaces are needed for the given subscribers
            k_NewProviderPrefabInstances.Clear();
            var currentPlatform = ModuleLoaderCore.GetCurrentPlatform();

            while (CheckMissingTraits(island, requiredTraits) > 0)
            {
                var providerAdded = false;
                k_RequiredTraits.Clear();
                k_RequiredTraits.UnionWith(requiredTraits); // Copy the collection in order to modify requiredTraits
                foreach (var trait in k_RequiredTraits)
                {
                    List <Type> providerTypes;
                    if (!k_TraitProviderMap.TryGetValue(trait, out providerTypes))
                    {
                        continue;
                    }

                    // Make sure potential provider types can be added
                    k_ProviderTypes.Clear();
                    foreach (var providerType in providerTypes)
                    {
                        var options = FunctionalityIsland.GetProviderSelectionOptions(providerType);
                        if (options != null)
                        {
                            if (options.DisallowAutoCreation)
                            {
                                if (!k_DefaultProviderMap.TryGetValue(providerType, out var defaultProvider) || defaultProvider.defaultProviderPrefab == null)
                                {
                                    continue;
                                }
                            }

                            var excludedPlatforms = options.ExcludedPlatforms;
                            if (excludedPlatforms != null && options.ExcludedPlatforms.Contains(currentPlatform))
                            {
                                continue;
                            }
                        }

                        if (island.CanAddProviderType(providerType))
                        {
                            k_ProviderTypes.Add(providerType);
                        }
                    }

                    if (k_ProviderTypes.Count == 0)
                    {
                        continue;
                    }

                    k_ProviderTypes.Sort((a, b) =>
                    {
                        var compare = GetProviderScore(b, requiredTraits).CompareTo(GetProviderScore(a, requiredTraits));
                        if (compare != 0)
                        {
                            return(compare);
                        }

                        compare = k_DefaultProviderMap.ContainsKey(b).CompareTo(k_DefaultProviderMap.ContainsKey(a));
                        if (compare != 0)
                        {
                            return(compare);
                        }

                        var optionsA = FunctionalityIsland.GetProviderSelectionOptions(a);
                        var optionsB = FunctionalityIsland.GetProviderSelectionOptions(b);
                        return(optionsB.Priority.CompareTo(optionsA.Priority));
                    });

                    var firstProvider = k_ProviderTypes[0];
                    if (k_ProviderTypes.Count > 1)
                    {
                        var secondProvider  = k_ProviderTypes[1];
                        var firstScore      = GetProviderScore(firstProvider, requiredTraits);
                        var secondScore     = GetProviderScore(secondProvider, requiredTraits);
                        var firstIsDefault  = k_DefaultProviderMap.ContainsKey(firstProvider);
                        var secondIsDefault = k_DefaultProviderMap.ContainsKey(secondProvider);
                        var firstPriority   = FunctionalityIsland.GetProviderSelectionOptions(firstProvider).Priority;
                        var secondPriority  = FunctionalityIsland.GetProviderSelectionOptions(secondProvider).Priority;
                        if (firstScore == secondScore && firstIsDefault == secondIsDefault && firstPriority == secondPriority)
                        {
                            Debug.LogWarning(string.Format(k_EqualScoreMessage, trait, firstProvider, secondProvider, island.name), island);
                        }
                    }

                    if (k_DefaultProviderMap.TryGetValue(firstProvider, out var row))
                    {
                        var prefab = row.defaultProviderPrefab;
                        var providesRequiredTrait = false;
                        if (prefab != null)
                        {
                            var prefabComponents = prefab.gameObject.GetComponentsInChildren <IProvidesTraits>();
                            foreach (var prefabComponent in prefabComponents)
                            {
                                var providedTraits = prefabComponent.GetProvidedTraits();
                                foreach (var providedTrait in providedTraits)
                                {
                                    providesRequiredTrait |= requiredTraits.Remove(providedTrait);
                                }
                            }

                            if (!providesRequiredTrait)
                            {
                                continue;
                            }

                            GameObject instance;
                            if (!k_NewProviderPrefabInstances.TryGetValue(prefab, out instance))
                            {
                                if (functionalityInjectionModuleLogging)
                                {
                                    Debug.LogFormat("Functionality Injection Module creating default provider: {0}", prefab);
                                }

                                instance = GameObjectUtils.Instantiate(prefab);
                                k_NewProviderPrefabInstances[prefab] = instance;
                            }

                            var providersInPrefab = instance.GetComponentsInChildren <IFunctionalityProvider>();
                            foreach (var provider in providersInPrefab)
                            {
                                AddRequirementsAndRemoveProvidedTraits(requiredTraits, provider);
                                island.AddProvider(provider.GetType(), provider);
                            }

                            continue;
                        }

                        var defaultProviderTypeName = row.defaultProviderTypeName;
                        var defaultProviderType     = row.defaultProviderType;
                        var providerType            = row.providerType;

                        TraitDefinition[] staticProvided;
                        if (!k_ProvidedTraits.TryGetValue(defaultProviderType, out staticProvided))
                        {
                            continue;
                        }

                        foreach (var providedTrait in staticProvided)
                        {
                            providesRequiredTrait |= requiredTraits.Remove(providedTrait);
                        }

                        if (!providesRequiredTrait)
                        {
                            continue;
                        }

                        var vanillaProvider = FunctionalityIsland.GetOrCreateProviderInstance(defaultProviderType, providerType);
                        if (vanillaProvider == null)
                        {
                            Debug.LogWarningFormat("Cannot instantiate {0} as an IFunctionalityProvider.", defaultProviderTypeName);
                            continue;
                        }

                        if (newProviders != null)
                        {
                            newProviders.Add(vanillaProvider);
                        }

                        providerAdded = true;
                        AddRequirementsAndRemoveProvidedTraits(requiredTraits, vanillaProvider);
                        island.AddProvider(defaultProviderType, vanillaProvider);
                    }
                    else
                    {
                        // Spawn or gain access to the class needed to support the functionality
                        var provider = FunctionalityIsland.GetOrCreateProviderInstance(firstProvider, firstProvider);
                        if (provider == null)
                        {
                            Debug.LogWarningFormat("Cannot instantiate {0} as an IFunctionalityProvider.", firstProvider.Name);
                            continue;
                        }

                        if (newProviders != null)
                        {
                            newProviders.Add(provider);
                        }

                        providerAdded = true;
                        AddRequirementsAndRemoveProvidedTraits(requiredTraits, provider);
                        island.AddProvider(firstProvider, provider);
                    }

                    break;
                }

                if (!providerAdded)
                {
                    break;
                }
            }

            island.InjectFunctionalityInDefaultProviders(k_NewProviderPrefabInstances, newProviders);
            island.ActivateProviderGameObjects();

            Profiler.EndSample();
        }
        public override void OnInspectorGUI()
        {
            using (var check = new EditorGUI.ChangeCheckScope())
            {
                EditorGUILayout.PropertyField(m_DefaultIslandProperty);
                m_ShowIslands = EditorGUILayout.Foldout(m_ShowIslands, "Current Islands", true);
                if (m_ShowIslands)
                {
                    DrawCurrentIslands();
                }

                if (check.changed)
                {
                    serializedObject.ApplyModifiedProperties();
                }
            }

            const float providerColumnWidthRatio = 0.5f;
            var         providerWidth            = EditorGUIUtility.currentViewWidth * providerColumnWidthRatio;
            var         foldoutStyle             = styles.ProviderTypesFoldoutStyle;

            styles.ProviderTypesFoldoutStyle.fixedWidth = providerWidth;
            var providerColumnWidth = GUILayout.Width(providerWidth);
            var priorityColumnWidth = GUILayout.Width(k_PriorityColumnWidth);

            using (new EditorGUILayout.HorizontalScope())
            {
                m_ShowProviderTypeList = EditorGUILayout.Foldout(m_ShowProviderTypeList, "Provider Types", true, foldoutStyle);
                if (m_ShowProviderTypeList)
                {
                    GUILayout.Space(providerWidth - k_PriorityHeaderOffset);
                    GUILayout.Label("Priorities", priorityColumnWidth);
                    GUILayout.Label("Excluded Platforms");
                }
            }

            if (m_ShowProviderTypeList)
            {
                using (new EditorGUI.IndentLevelScope())
                {
                    foreach (var type in k_AllProviderTypes)
                    {
                        using (new EditorGUILayout.HorizontalScope())
                        {
                            var priority          = 0;
                            var excludedPlatforms = string.Empty;
                            var priorityAttribute = FunctionalityIsland.GetProviderSelectionOptions(type);
                            if (priorityAttribute != null)
                            {
                                priority = priorityAttribute.Priority;
                                var platforms = priorityAttribute.ExcludedPlatforms;
                                if (platforms != null)
                                {
                                    excludedPlatforms = String.Join(", ", platforms);
                                }
                            }

                            MonoScript script;
                            if (k_MonoScripts.TryGetValue(type, out script))
                            {
                                EditorGUILayout.ObjectField(script, typeof(MonoScript), false, providerColumnWidth);
                            }
                            else
                            {
                                EditorGUILayout.LabelField(type.GetFullNameWithGenericArguments(), providerColumnWidth);
                            }

                            EditorGUILayout.LabelField(priority.ToString(), priorityColumnWidth);
                            EditorGUILayout.LabelField(string.Join(", ", excludedPlatforms));
                        }
                    }
                }
            }

            m_ShowSubscriberTypeList = EditorGUILayout.Foldout(m_ShowSubscriberTypeList, "Subscriber Types", true);
            if (m_ShowSubscriberTypeList)
            {
                using (new EditorGUI.IndentLevelScope())
                {
                    foreach (var type in k_AllSubscriberTypes)
                    {
                        MonoScript script;
                        if (k_MonoScripts.TryGetValue(type, out script))
                        {
                            EditorGUILayout.ObjectField(script, typeof(MonoScript), false);
                        }
                        else
                        {
                            EditorGUILayout.LabelField(type.GetFullNameWithGenericArguments());
                        }
                    }
                }
            }
        }