private static void RegisterAssetAssembly(Assembly assembly) { if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); } lock (RegistryLock) { if (RegisteredAssetAssemblies.Contains(assembly)) { return; } RegisteredAssetAssemblies.Add(assembly); var assemblyScanTypes = AssemblyRegistry.GetScanTypes(assembly); if (assemblyScanTypes != null) { List <Type> types; var instantiatedObjects = new Dictionary <Type, object>(); // Register serializer factories if (assemblyScanTypes.Types.TryGetValue(typeof(IYamlSerializableFactory), out types)) { foreach (var type in types) { // Register serializer factories if (!type.IsAbstract && type.GetCustomAttribute <YamlSerializerFactoryAttribute>() != null && type.GetConstructor(Type.EmptyTypes) != null) { try { var instance = Activator.CreateInstance(type); instantiatedObjects.Add(type, instance); RegisteredSerializerFactories.Add((IYamlSerializableFactory)instance); } catch (Exception ex) { Log.Error($"Unable to instantiate serializer factory [{type}]", ex); } } } } // Custom visitors if (assemblyScanTypes.Types.TryGetValue(typeof(IDataCustomVisitor), out types)) { foreach (var type in types) { if (!type.IsAbstract && type.GetConstructor(Type.EmptyTypes) != null) { try { object instance; if (!instantiatedObjects.TryGetValue(type, out instance)) { instance = Activator.CreateInstance(type); instantiatedObjects.Add(type, instance); } RegisteredDataVisitNodes.Add((IDataCustomVisitor)instance); } catch (Exception ex) { Log.Error($"Unable to instantiate custom visitor [{type}]", ex); } } } } // Asset importer if (assemblyScanTypes.Types.TryGetValue(typeof(IAssetImporter), out types)) { foreach (var type in types) { if (!type.IsAbstract && type.GetConstructor(Type.EmptyTypes) != null) { try { object instance; if (!instantiatedObjects.TryGetValue(type, out instance)) { instance = Activator.CreateInstance(type); instantiatedObjects.Add(type, instance); } // Register the importer instance RegisterImporter((IAssetImporter)instance); } catch (Exception ex) { Log.Error($"Unable to instantiate importer [{type.Name}]", ex); } } } } // Register asset factory if (assemblyScanTypes.Types.TryGetValue(typeof(IAssetFactory <>), out types)) { foreach (var type in types) { if (!type.IsAbstract && !type.IsGenericTypeDefinition && type.GetConstructor(Type.EmptyTypes) != null) { object instance; if (!instantiatedObjects.TryGetValue(type, out instance)) { instance = Activator.CreateInstance(type); instantiatedObjects.Add(type, instance); } RegisteredAssetFactories.Add(type.Name, (IAssetFactory <Asset>)instance); } } } // Package upgraders if (assemblyScanTypes.Types.TryGetValue(typeof(PackageUpgraderAttribute), out types)) { foreach (var type in types) { var packageUpgraderAttribute = type.GetCustomAttribute <PackageUpgraderAttribute>(); if (packageUpgraderAttribute != null) { try { var packageUpgrader = (PackageUpgrader)Activator.CreateInstance(type); packageUpgrader.Attribute = packageUpgraderAttribute; RegisteredPackageUpgraders[packageUpgraderAttribute.PackageName] = packageUpgrader; } catch (Exception ex) { Log.Error($"Unable to instantiate package upgrader [{type.Name}]", ex); } } } } // Package analyzers if (assemblyScanTypes.Types.TryGetValue(typeof(PackageSessionAnalysisBase), out types)) { foreach (var type in types) { if (type.GetConstructor(Type.EmptyTypes) != null) { RegisteredPackageSessionAnalysisTypes.Add(type); } } } // Asset types (and Package type) var assemblyContainsPackageType = assembly == typeof(Package).Assembly; if (assemblyScanTypes.Types.TryGetValue(typeof(Asset), out types) || assemblyContainsPackageType) { if (assemblyContainsPackageType) { var extraTypes = new[] { typeof(Package) }; types = types?.Concat(extraTypes).ToList() ?? extraTypes.ToList(); } foreach (var assetType in types) { // Store in a list all asset types loaded if (assetType.IsPublic && !assetType.IsAbstract) { AssetTypes.Add(assetType); } // Asset FileExtensions var assetDescriptionAttribute = assetType.GetCustomAttribute <AssetDescriptionAttribute>(); if (assetDescriptionAttribute != null) { if (assetDescriptionAttribute.FileExtensions != null) { var extensions = FileUtility.GetFileExtensions(assetDescriptionAttribute.FileExtensions); RegisteredDefaultAssetExtension[assetType] = extensions.FirstOrDefault(); foreach (var extension in extensions) { if (!RegisteredAssetFileExtensions.ContainsKey(extension)) { RegisteredAssetFileExtensions.Add(extension, assetType); } } } if (assetDescriptionAttribute.AlwaysMarkAsRoot) { lock (AlwaysMarkAsRootAssetTypes) { AlwaysMarkAsRootAssetTypes.Add(assetType); } } } // Content type associated to assets var assetContentType = assetType.GetCustomAttribute <AssetContentTypeAttribute>(); if (assetContentType != null) { List <Type> assetTypes; if (!ContentToAssetTypes.TryGetValue(assetContentType.ContentType, out assetTypes)) { assetTypes = new List <Type>(); ContentToAssetTypes[assetContentType.ContentType] = assetTypes; } assetTypes.Add(assetType); AssetToContentTypes.Add(assetType, assetContentType.ContentType); } // Asset format version (process name by name) var assetFormatVersions = assetType.GetCustomAttributes <AssetFormatVersionAttribute>(); foreach (var assetFormatVersion in assetFormatVersions) { var formatVersion = assetFormatVersion.Version; var minVersion = assetFormatVersion.MinUpgradableVersion; SortedList <string, PackageVersion> formatVersions; if (!RegisteredFormatVersions.TryGetValue(assetType, out formatVersions)) { RegisteredFormatVersions.Add(assetType, formatVersions = new SortedList <string, PackageVersion>()); } formatVersions.Add(assetFormatVersion.Name, formatVersion); // Asset upgraders (only those matching current name) var assetUpgraders = assetType.GetCustomAttributes <AssetUpgraderAttribute>().Where(x => x.Name == assetFormatVersion.Name); AssetUpgraderCollection upgraderCollection = null; foreach (var upgrader in assetUpgraders) { if (upgraderCollection == null) { upgraderCollection = new AssetUpgraderCollection(assetType, formatVersion); } upgraderCollection.RegisterUpgrader(upgrader.AssetUpgraderType, upgrader.StartVersion, upgrader.TargetVersion); } if (upgraderCollection != null) { upgraderCollection.Validate(minVersion); RegisteredAssetUpgraders.Add(new KeyValuePair <Type, string>(assetType, assetFormatVersion.Name), upgraderCollection); } } // Part reference types for asset composites if (typeof(AssetComposite).IsAssignableFrom(assetType)) { var attributes = assetType.GetCustomAttributes(typeof(AssetPartReferenceAttribute), true).Cast <AssetPartReferenceAttribute>().ToList(); foreach (var attribute in attributes) { HashSet <AssetPartReferenceAttribute> relatedPartTypes; if (!RegisteredAssetCompositePartTypes.TryGetValue(attribute.ReferenceableType, out relatedPartTypes)) { relatedPartTypes = new HashSet <AssetPartReferenceAttribute>(); RegisteredAssetCompositePartTypes.Add(attribute.ReferenceableType, relatedPartTypes); } attributes.ForEach(x => relatedPartTypes.Add(x)); } } } } } } }
/// <summary> /// Registers the asset assembly. This assembly should provide <see cref="Asset"/> objects, associated with /// <see cref="IAssetCompiler"/> and optionaly a <see cref="IAssetImporter"/>. /// </summary> /// <param name="assembly">The assembly.</param> /// <exception cref="System.ArgumentNullException">assembly</exception> /// <exception cref="AssetException"> /// Invalid compiler type [{0}], must inherit from IAssetImporter.ToFormat(assetCompiler.TypeName) /// or /// Unable to instantiate compiler [{0}].ToFormat(assetCompiler.TypeName) /// or /// Invalid importer type [{0}], must inherit from IAssetImporter.ToFormat(assetImporter.ImpoterTypeName) /// or /// Unable to instantiate importer [{0}].ToFormat(assetImporter.ImpoterTypeName) /// </exception> public static void RegisterAssembly(Assembly assembly) { if (assembly == null) { throw new ArgumentNullException("assembly"); } lock (RegisteredAssemblies) { if (RegisteredAssemblies.Contains(assembly)) { return; } RegisteredAssemblies.Add(assembly); } // Process Asset types. foreach (var type in assembly.GetTypes()) { // Register serializer factories if (type.GetCustomAttribute <YamlSerializerFactoryAttribute>() != null) { if (typeof(IYamlSerializableFactory).IsAssignableFrom(type)) { try { var yamlFactory = (IYamlSerializableFactory)Activator.CreateInstance(type); lock (RegisteredSerializerFactories) { RegisteredSerializerFactories.Add(yamlFactory); } // TODO: Handle IDataCustomVisitor on its own instead of relying on the coupling with IYamlSerializableFactory var dataCustomVisitor = yamlFactory as IDataCustomVisitor; if (dataCustomVisitor != null) { lock (RegisteredDataVisitNodes) { RegisteredDataVisitNodes.Add(dataCustomVisitor); } } } catch (Exception ex) { Log.Error("Unable to instantiate serializer factory [{0}]", ex, type); } } } if (type.GetCustomAttribute <DiffNodeBuilderAttribute>() != null) { if (typeof(IDataCustomVisitor).IsAssignableFrom(type)) { try { var dataCustomVisitor = (IDataCustomVisitor)Activator.CreateInstance(type); lock (RegisteredDataVisitNodeBuilders) { RegisteredDataVisitNodeBuilders.Add(dataCustomVisitor); } } catch (Exception ex) { Log.Error("Unable to instantiate diff converter [{0}]", ex, type); } } } // Asset importer if (typeof(IAssetImporter).IsAssignableFrom(type) && type.GetConstructor(new Type[0]) != null) { try { var importerInstance = Activator.CreateInstance(type) as IAssetImporter; // Register the importer instance RegisterImporter(importerInstance); } catch (Exception ex) { Log.Error("Unable to instantiate importer [{0}]", ex, type.Name); } } if (typeof(PackageSessionAnalysisBase).IsAssignableFrom(type) && type.GetConstructor(new Type[0]) != null) { RegisteredPackageSessionAnalysisTypes.Add(type); } { var packageUpgraderAttribute = type.GetCustomAttribute <PackageUpgraderAttribute>(); if (packageUpgraderAttribute != null) { try { var packageUpgrader = (PackageUpgrader)Activator.CreateInstance(type); packageUpgrader.Attribute = packageUpgraderAttribute; RegisteredPackageUpgraders[packageUpgraderAttribute.PackageName] = packageUpgrader; } catch (Exception ex) { Log.Error("Unable to instantiate package upgrader [{0}]", ex, type.Name); } } } // Only process Asset types var assetType = type; if (!typeof(Asset).IsAssignableFrom(assetType) || !assetType.IsClass) { continue; } // Store in a list all asset types loaded if (assetType.IsPublic && !assetType.IsAbstract) { AssetTypes.Add(assetType); } var isSourceCodeAsset = typeof(SourceCodeAsset).IsAssignableFrom(assetType); // Asset FileExtensions var assetDescriptionAttribute = assetType.GetCustomAttribute <AssetDescriptionAttribute>(); if (assetDescriptionAttribute != null) { if (assetDescriptionAttribute.FileExtensions != null) { var extensions = FileUtility.GetFileExtensions(assetDescriptionAttribute.FileExtensions); RegisteredDefaultAssetExtension[assetType] = extensions.FirstOrDefault(); foreach (var extension in extensions) { RegisteredAssetFileExtensions.Add(extension); // If the asset is a pure sourcecode asset, then register the serializer if (isSourceCodeAsset) { SourceCodeAssetSerializer.RegisterExtension(assetType, extension); } } } if (!assetDescriptionAttribute.AllowUserCreation) { RegisteredInternalAssetTypes.Add(assetType); } } // Asset format version var assetFormatVersion = assetType.GetCustomAttribute <AssetFormatVersionAttribute>(); int formatVersion = assetFormatVersion != null ? assetFormatVersion.Version : 0; int minVersion = assetFormatVersion != null ? assetFormatVersion.MinUpgradableVersion : 0; RegisteredFormatVersions.Add(assetType, Tuple.Create(minVersion, formatVersion)); // Asset upgraders var assetUpgraders = assetType.GetCustomAttributes <AssetUpgraderAttribute>(); AssetUpgraderCollection upgraderCollection = null; foreach (var upgrader in assetUpgraders) { if (upgraderCollection == null) { upgraderCollection = new AssetUpgraderCollection(assetType, formatVersion); } upgraderCollection.RegisterUpgrader(upgrader.AssetUpgraderType, upgrader.StartMinVersion, upgrader.StartMaxVersion, upgrader.TargetVersion); } if (upgraderCollection != null) { upgraderCollection.Validate(minVersion); RegisteredAssetUpgraders.Add(assetType, upgraderCollection); } // Asset factory var assetFactory = assetType.GetCustomAttribute <ObjectFactoryAttribute>(); if (assetFactory != null) { try { ObjectFactory.RegisterFactory(assetType); } catch (Exception ex) { Log.Error("Unable to instantiate factory [{0}] for asset [{1}]", ex, assetFactory.FactoryTypeName, assetType); } } else { var assetConstructor = assetType.GetConstructor(Type.EmptyTypes); if (assetConstructor != null) { // Register the asset even if it has no factory (default using empty constructor) ObjectFactory.RegisterFactory(assetType, null); } } // Asset description var thumbnailCompilerAttribute = assetType.GetCustomAttribute <ThumbnailCompilerAttribute>(); if (thumbnailCompilerAttribute != null) { RegisterDynamicThumbnail(assetType, thumbnailCompilerAttribute.DynamicThumbnails); } } }