internal static void Initialize() { using (ProfilingUtility.SampleBlock("Plugin Container Initialization")) { initializing = true; pluginTypesById = Codebase.ludiqEditorTypes .Where(t => typeof(Plugin).IsAssignableFrom(t) && t.IsConcrete()) .ToDictionary(GetPluginID); pluginDependencies = new Dictionary <string, HashSet <string> >(); foreach (var pluginTypeById in pluginTypesById) { pluginDependencies.Add(pluginTypeById.Key, pluginTypeById.Value.GetAttributes <PluginDependencyAttribute>().Select(pda => pda.id).ToHashSet()); } var moduleTypes = Codebase.ludiqEditorTypes .Where(t => typeof(IPluginModule).IsAssignableFrom(t) && t.HasAttribute <PluginModuleAttribute>(false)) .OrderByDependencies(t => t.GetAttributes <PluginModuleDependencyAttribute>().Select(pmda => pmda.moduleType)) .ToArray(); pluginsById = new Dictionary <string, Plugin>(); var allModules = new List <IPluginModule>(); foreach (var pluginId in pluginTypesById.Keys.OrderByDependencies(pluginId => pluginDependencies[pluginId])) { var pluginType = pluginTypesById[pluginId]; Plugin plugin; try { using (ProfilingUtility.SampleBlock($"{pluginType.Name} (Instantiation)")) { plugin = (Plugin)pluginType.Instantiate(); } } catch (Exception ex) { throw new TargetInvocationException($"Could not instantiate plugin '{pluginId}' ('{pluginType.CSharpName()}').", ex); } var modules = new List <IPluginModule>(); foreach (var moduleType in moduleTypes) { try { var required = moduleType.GetAttribute <PluginModuleAttribute>(false).required; var moduleProperty = pluginType.GetProperties().FirstOrDefault(p => p.PropertyType.IsAssignableFrom(moduleType)); if (moduleProperty == null) { continue; } IPluginModule module = null; var moduleOverrideType = Codebase.ludiqEditorTypes .FirstOrDefault(t => moduleType.IsAssignableFrom(t) && t.IsConcrete() && t.HasAttribute <PluginAttribute>() && t.GetAttribute <PluginAttribute>().id == pluginId); if (moduleOverrideType != null) { try { using (ProfilingUtility.SampleBlock($"{moduleOverrideType.Name} (Instantiation)")) { module = (IPluginModule)InstantiateLinkedType(moduleOverrideType, plugin); } } catch (Exception ex) { throw new TargetInvocationException($"Failed to instantiate user-defined plugin module '{moduleOverrideType.CSharpName()}' for '{pluginId}'.", ex); } } else if (moduleType.IsConcrete()) { try { using (ProfilingUtility.SampleBlock($"{moduleType.Name} (Instantiation)")) { module = (IPluginModule)InstantiateLinkedType(moduleType, plugin); } } catch (Exception ex) { throw new TargetInvocationException($"Failed to instantiate built-in plugin module '{moduleType.CSharpName()}' for '{pluginId}'.", ex); } } else if (required) { throw new InvalidImplementationException($"Missing implementation of plugin module '{moduleType.CSharpName()}' for '{pluginId}'."); } if (module != null) { moduleProperty.SetValue(plugin, module, null); modules.Add(module); allModules.Add(module); } } catch (Exception ex) { Debug.LogException(ex); } } pluginsById.Add(plugin.id, plugin); foreach (var module in modules) { try { using (ProfilingUtility.SampleBlock($"{module.GetType().Name} (Initialization)")) { module.Initialize(); } } catch (Exception ex) { Debug.LogException(new Exception($"Failed to initialize plugin module '{plugin.id}.{module.GetType().CSharpName()}'.", ex)); } } if (plugin.manifest.versionMismatch) { anyVersionMismatch = true; } } foreach (var module in allModules) { try { using (ProfilingUtility.SampleBlock($"{module.GetType().Name} (Late Initialization)")) { module.LateInitialize(); } } catch (Exception ex) { Debug.LogException(new Exception($"Failed to late initialize plugin module '{module.plugin.id}.{module.GetType().CSharpName()}'.", ex)); } } var afterPluginTypes = Codebase.ludiqEditorTypes .Where(t => t.HasAttribute <InitializeAfterPluginsAttribute>()); using (ProfilingUtility.SampleBlock($"BeforeInitializeAfterPlugins")) { EditorApplicationUtility.BeforeInitializeAfterPlugins(); } foreach (var afterPluginType in afterPluginTypes) { using (ProfilingUtility.SampleBlock($"{afterPluginType.Name} (Static Initializer)")) { RuntimeHelpers.RunClassConstructor(afterPluginType.TypeHandle); } } using (ProfilingUtility.SampleBlock($"AfterInitializeAfterPlugins")) { EditorApplicationUtility.AfterInitializeAfterPlugins(); } using (ProfilingUtility.SampleBlock($"Delayed Calls")) { while (delayQueue.TryDequeue(out var a)) { a.Invoke(); } } InternalEditorUtility.RepaintAllViews(); ProfilingUtility.Clear(); using (ProfilingUtility.SampleBlock($"Product Container Initialization")) { ProductContainer.Initialize(); } initializing = false; initialized = true; using (ProfilingUtility.SampleBlock($"Update Process")) { // Automatically show update wizard if (!EditorApplication.isPlayingOrWillChangePlaymode && plugins.Any(plugin => plugin.manifest.versionMismatch)) { // Delay call seems to be needed here to avoid arcane exceptions... // Too lazy to debug why, it works that way. EditorApplication.delayCall += PerformUpdate; } } } }
private static void Initialize() { using (ProfilingUtility.SampleBlock("Plugin Container Initialization")) { if (initialized || initializing) { Debug.LogWarning("Attempting to re-initialize plugin container, ignoring.\n"); return; } if (!isAssetDatabaseReliable) { Debug.LogWarning("Initializing plugin container while asset database is not initialized.\nLoading assets might fail!"); } initializing = true; pluginTypesById = Codebase.GetTypeRegistrations <RegisterPluginAttribute>() .ToDictionary(r => r.id, r => r.type); pluginDependencies = new Dictionary <string, HashSet <string> >(); foreach (var pluginId in pluginTypesById.Keys) { pluginDependencies.Add(pluginId, new HashSet <string>()); } foreach (var pluginDependencyRegistration in Codebase.GetAssemblyAttributes <RegisterPluginDependencyAttribute>()) { if (!pluginDependencies.TryGetValue(pluginDependencyRegistration.dependerId, out var dependencies)) { dependencies = new HashSet <string>(); pluginDependencies.Add(pluginDependencyRegistration.dependerId, dependencies); } dependencies.Add(pluginDependencyRegistration.dependencyId); } var moduleTypeRegistrations = Codebase.GetTypeRegistrations <RegisterPluginModuleTypeAttribute>(); pluginsById = new Dictionary <string, Plugin>(); var allModules = new List <IPluginModule>(); foreach (var pluginId in pluginTypesById.Keys.OrderByDependencies(pluginId => pluginDependencies[pluginId])) { var pluginType = pluginTypesById[pluginId]; Plugin plugin; try { using (ProfilingUtility.SampleBlock($"{pluginType.Name} (Instantiation)")) { plugin = (Plugin)pluginType.Instantiate(); } } catch (Exception ex) { throw new TargetInvocationException($"Could not instantiate plugin '{pluginId}' ('{pluginType}').", ex); } var modules = new List <IPluginModule>(); foreach (var moduleTypeRegistration in moduleTypeRegistrations) { var moduleType = moduleTypeRegistration.type; var required = moduleTypeRegistration.required; try { var moduleProperty = pluginType.GetProperties().FirstOrDefault(p => p.PropertyType.IsAssignableFrom(moduleType)); if (moduleProperty == null) { continue; } IPluginModule module = null; var moduleOverrideType = Codebase.GetTypeRegistrations <MapToPluginAttribute>() .FirstOrDefault(r => r.pluginId == pluginId && moduleType.IsAssignableFrom(r.type) && r.type.IsConcrete())?.type; if (moduleOverrideType != null) { try { using (ProfilingUtility.SampleBlock($"{moduleOverrideType.Name} (Instantiation)")) { module = (IPluginModule)InstantiateMappedType(moduleOverrideType, plugin); } } catch (Exception ex) { throw new TargetInvocationException($"Failed to instantiate user-defined plugin module '{moduleOverrideType}' for '{pluginId}'.", ex); } } else if (moduleType.IsConcrete()) { try { using (ProfilingUtility.SampleBlock($"{moduleType.Name} (Instantiation)")) { module = (IPluginModule)InstantiateMappedType(moduleType, plugin); } } catch (Exception ex) { throw new TargetInvocationException($"Failed to instantiate built-in plugin module '{moduleType}' for '{pluginId}'.", ex); } } else if (required) { throw new InvalidImplementationException($"Missing implementation of plugin module '{moduleType}' for '{pluginId}'."); } if (module != null) { moduleProperty.SetValue(plugin, module, null); modules.Add(module); allModules.Add(module); } } catch (Exception ex) { Debug.LogException(ex); } } pluginsById.Add(plugin.id, plugin); foreach (var module in modules) { try { using (ProfilingUtility.SampleBlock($"{module.GetType().Name} (Initialization)")) { module.Initialize(); } } catch (Exception ex) { Debug.LogException(new Exception($"Failed to initialize plugin module '{plugin.id}.{module.GetType()}'.", ex)); } } if (plugin.manifest.versionMismatch) { anyVersionMismatch = true; } } initializing = false; initialized = true; using (ProfilingUtility.SampleBlock($"Product Container Initialization")) { ProductContainer.Initialize(); } foreach (var module in allModules) { try { using (ProfilingUtility.SampleBlock($"{module.GetType().Name} (Late Initialization)")) { module.LateInitialize(); } } catch (Exception ex) { Debug.LogException(new Exception($"Failed to late initialize plugin module '{module.plugin.id}.{module.GetType()}'.", ex)); } } var afterPluginTypes = Codebase.GetRegisteredTypes <InitializeAfterPluginsAttribute>(); using (ProfilingUtility.SampleBlock($"BeforeInitializeAfterPlugins")) { EditorApplicationUtility.BeforeInitializeAfterPlugins(); } foreach (var afterPluginType in afterPluginTypes) { using (ProfilingUtility.SampleBlock($"{afterPluginType.Name} (Static Initializer)")) { RuntimeHelpers.RunClassConstructor(afterPluginType.TypeHandle); } } using (ProfilingUtility.SampleBlock($"AfterInitializeAfterPlugins")) { EditorApplicationUtility.AfterInitializeAfterPlugins(); } using (ProfilingUtility.SampleBlock($"Launch Setup Wizards")) { // Automatically show setup wizards if (!EditorApplication.isPlayingOrWillChangePlaymode) { var productsRequiringSetup = ProductContainer.products.Where(product => product.requiresSetup).ToHashSet(); var productsHandlingAllSetups = productsRequiringSetup.ToHashSet(); // Do not show product setups if another product already // includes all the same plugins or more. For example, // if both Bolt and Ludiq require setup, but Bolt requires // all of the Ludiq plugins, then only the Bolt setup wizard // should be shown. foreach (var product in productsRequiringSetup) { foreach (var otherProduct in productsRequiringSetup) { if (product == otherProduct) { continue; } var productPlugins = product.plugins.ResolveDependencies().ToHashSet(); var otherProductPlugins = otherProduct.plugins.ResolveDependencies().ToHashSet(); if (productPlugins.IsSubsetOf(otherProductPlugins)) { productsHandlingAllSetups.Remove(product); } } } foreach (var product in productsHandlingAllSetups) { // Delay call is used here to avoid showing multiple wizards during an import EditorApplication.delayCall += () => SetupWizard.Show(product); } } } using (ProfilingUtility.SampleBlock($"Launch Update Wizard")) { // Automatically show update wizard if (!EditorApplication.isPlayingOrWillChangePlaymode && plugins.Any(plugin => plugin.manifest.versionMismatch)) { // Delay call seems to be needed here to avoid arcane exceptions... // Too lazy to debug why, it works that way. EditorApplication.delayCall += UpdateWizard.Show; } } using (ProfilingUtility.SampleBlock($"Delayed Calls")) { lock (delayQueue) { while (delayQueue.Count > 0) { delayQueue.Dequeue().Invoke(); } } } InternalEditorUtility.RepaintAllViews(); ProfilingUtility.Clear(); //ConsoleProfiler.Dump(); } }
internal static void Initialize() { EditorApplication.delayCall -= initializeCallbackFunction; using (ProfilingUtility.SampleBlock("Plugin Container Initialization")) { initializing = true; pluginTypesById = Codebase.ludiqEditorTypes .Where(t => typeof(Plugin).IsAssignableFrom(t) && t.IsConcrete()) .ToDictionary(GetPluginID); pluginDependencies = new Dictionary <string, HashSet <string> >(); foreach (var pluginTypeById in pluginTypesById) { pluginDependencies.Add(pluginTypeById.Key, pluginTypeById.Value.GetAttributes <PluginDependencyAttribute>().Select(pda => pda.id).ToHashSet()); } var moduleTypes = Codebase.ludiqEditorTypes .Where(t => typeof(IPluginModule).IsAssignableFrom(t) && t.HasAttribute <PluginModuleAttribute>(false)) .OrderByDependencies(t => t.GetAttributes <PluginModuleDependencyAttribute>().Select(pmda => pmda.moduleType)) .ToArray(); pluginsById = new Dictionary <string, Plugin>(); var allModules = new List <IPluginModule>(); foreach (var pluginId in pluginTypesById.Keys.OrderByDependencies(pluginId => pluginDependencies[pluginId])) { var pluginType = pluginTypesById[pluginId]; Plugin plugin; try { using (ProfilingUtility.SampleBlock($"{pluginType.Name} (Instantiation)")) { plugin = (Plugin)pluginType.Instantiate(); } } catch (Exception ex) { throw new TargetInvocationException($"Could not instantiate plugin '{pluginId}' ('{pluginType.CSharpName()}').", ex); } var modules = new List <IPluginModule>(); foreach (var moduleType in moduleTypes) { try { var required = moduleType.GetAttribute <PluginModuleAttribute>(false).required; var moduleProperty = pluginType.GetProperties().FirstOrDefault(p => p.PropertyType.IsAssignableFrom(moduleType)); if (moduleProperty == null) { continue; } IPluginModule module = null; var moduleOverrideType = Codebase.ludiqEditorTypes .FirstOrDefault(t => moduleType.IsAssignableFrom(t) && t.IsConcrete() && t.HasAttribute <PluginAttribute>() && t.GetAttribute <PluginAttribute>().id == pluginId); if (moduleOverrideType != null) { try { using (ProfilingUtility.SampleBlock($"{moduleOverrideType.Name} (Instantiation)")) { module = (IPluginModule)InstantiateLinkedType(moduleOverrideType, plugin); } } catch (Exception ex) { throw new TargetInvocationException($"Failed to instantiate user-defined plugin module '{moduleOverrideType.CSharpName()}' for '{pluginId}'.", ex); } } else if (moduleType.IsConcrete()) { try { using (ProfilingUtility.SampleBlock($"{moduleType.Name} (Instantiation)")) { module = (IPluginModule)InstantiateLinkedType(moduleType, plugin); } } catch (Exception ex) { throw new TargetInvocationException($"Failed to instantiate built-in plugin module '{moduleType.CSharpName()}' for '{pluginId}'.", ex); } } else if (required) { throw new InvalidImplementationException($"Missing implementation of plugin module '{moduleType.CSharpName()}' for '{pluginId}'."); } if (module != null) { moduleProperty.SetValue(plugin, module, null); modules.Add(module); allModules.Add(module); } } catch (Exception ex) { Debug.LogException(ex); } } pluginsById.Add(plugin.id, plugin); foreach (var module in modules) { try { using (ProfilingUtility.SampleBlock($"{module.GetType().Name} (Initialization)")) { module.Initialize(); } } catch (Exception ex) { Debug.LogException(new Exception($"Failed to initialize plugin module '{plugin.id}.{module.GetType().CSharpName()}'.", ex)); } } if (plugin.manifest.versionMismatch) { anyVersionMismatch = true; } } initializing = false; initialized = true; foreach (var module in allModules) { try { using (ProfilingUtility.SampleBlock($"{module.GetType().Name} (Late Initialization)")) { module.LateInitialize(); } } catch (Exception ex) { Debug.LogException(new Exception($"Failed to late initialize plugin module '{module.plugin.id}.{module.GetType().CSharpName()}'.", ex)); } } var afterPluginTypes = Codebase.ludiqEditorTypes .Where(t => t.HasAttribute <InitializeAfterPluginsAttribute>()); using (ProfilingUtility.SampleBlock($"BeforeInitializeAfterPlugins")) { EditorApplicationUtility.BeforeInitializeAfterPlugins(); } foreach (var afterPluginType in afterPluginTypes) { using (ProfilingUtility.SampleBlock($"{afterPluginType.Name} (Static Initializer)")) { RuntimeHelpers.RunClassConstructor(afterPluginType.TypeHandle); } } using (ProfilingUtility.SampleBlock($"AfterInitializeAfterPlugins")) { EditorApplicationUtility.AfterInitializeAfterPlugins(); } using (ProfilingUtility.SampleBlock($"Delayed Calls")) { lock (delayQueue) { while (delayQueue.Count > 0) { delayQueue.Dequeue().Invoke(); } } } InternalEditorUtility.RepaintAllViews(); ProfilingUtility.Clear(); using (ProfilingUtility.SampleBlock($"Product Container Initialization")) { ProductContainer.Initialize(); } using (ProfilingUtility.SampleBlock($"Launch Setup Wizards")) { // Automatically show setup wizards if (!EditorApplication.isPlayingOrWillChangePlaymode) { var productsRequiringSetup = ProductContainer.products.Where(product => product.requiresSetup).ToHashSet(); var productsHandlingAllSetups = productsRequiringSetup.ToHashSet(); // Do not show product setups if another product already // includes all the same plugins or more. For example, // if both Bolt and Ludiq require setup, but Bolt requires // all of the Ludiq plugins, then only the Bolt setup wizard // should be shown. foreach (var product in productsRequiringSetup) { foreach (var otherProduct in productsRequiringSetup) { if (product == otherProduct) { continue; } var productPlugins = product.plugins.ResolveDependencies().ToHashSet(); var otherProductPlugins = otherProduct.plugins.ResolveDependencies().ToHashSet(); if (productPlugins.IsSubsetOf(otherProductPlugins)) { productsHandlingAllSetups.Remove(product); } } } foreach (var product in productsHandlingAllSetups) { // Delay call is used here to avoid showing multiple wizards during an import EditorApplication.delayCall += () => product.setupWizard.Show(); } } } using (ProfilingUtility.SampleBlock($"Launch Update Wizard")) { // Automatically show update wizard if (!EditorApplication.isPlayingOrWillChangePlaymode && plugins.Any(plugin => plugin.manifest.versionMismatch)) { // Delay call seems to be needed here to avoid arcane exceptions... // Too lazy to debug why, it works that way. EditorApplication.delayCall += () => UpdateWizard.global.Show(); } } } }