/// <summary>
        /// Implementation of ScriptedImporter.OnImportAsset
        /// </summary>
        /// <param name="ctx">
        /// This argument contains all the contextual information needed to process the import
        /// event and is also used by the custom importer to store the resulting Unity Asset.
        /// </param>
        public override void OnImportAsset(AssetImportContext ctx)
        {
            var spriteLib = ScriptableObject.CreateInstance <SpriteLibraryAsset>();

            spriteLib.name = System.IO.Path.GetFileNameWithoutExtension(assetPath);
            var sourceAsset = UnityEditorInternal.InternalEditorUtility.LoadSerializedFileAndForget(assetPath);

            if (sourceAsset?.Length > 0)
            {
                var sourceLibraryAsset = sourceAsset[0] as SpriteLibrarySourceAsset;
                if (sourceLibraryAsset != null)
                {
                    foreach (var cat in sourceLibraryAsset.library)
                    {
                        spriteLib.AddCategoryLabel(null, cat.name, null);
                        foreach (var entry in cat.overrideEntries)
                        {
                            spriteLib.AddCategoryLabel(entry.spriteOverride, cat.name, entry.name);
                        }
                    }
                }
                if (!string.IsNullOrEmpty(sourceLibraryAsset.primaryLibraryID))
                {
                    var primaryAssetPath = AssetDatabase.GUIDToAssetPath(sourceLibraryAsset.primaryLibraryID);
                    if (primaryAssetPath != assetPath)
                    {
                        ctx.DependsOnArtifact(AssetDatabase.GUIDToAssetPath(sourceLibraryAsset.primaryLibraryID));
                        m_PrimaryLibrary = AssetDatabase.LoadAssetAtPath <SpriteLibraryAsset>(primaryAssetPath);
                    }
                }
            }

            ctx.AddObjectToAsset("SpriteLib", spriteLib, IconUtility.LoadIconResource("Sprite Library", "Icons/Light", "Icons/Dark"));
        }
Beispiel #2
0
        public override void OnImportAsset(AssetImportContext ctx)
        {
            ScriptableObjectVariant variantBase = ScriptableObject.CreateInstance <ScriptableObjectVariant>();

            ctx.AddObjectToAsset(nameof(variantBase), variantBase);
            ctx.SetMainObject(variantBase);
            if (Origin == default)
            {
                return;
            }

            string dependencyPath = AssetDatabase.GUIDToAssetPath(Origin);

            if (string.IsNullOrEmpty(dependencyPath))
            {
                return;
            }
            ctx.DependsOnArtifact(new GUID(Origin));

            // We need to reload the dependency from the asset database or else it doesn't know we depend on it.
            var dependency = AssetDatabase.LoadAssetAtPath <ScriptableObject>(dependencyPath);

            ScriptableObject variant = Instantiate(dependency);

            var overrideData = string.IsNullOrEmpty(Json) ? null : JsonConvert.DeserializeObject <OverrideData>(Json);

            if (overrideData?.Overrides.Count > 0)
            {
                using var so = new SerializedObject(variant);
                foreach (KeyValuePair <string, JToken> dataOverride in overrideData.Overrides)
                {
                    SerializedProperty property = so.FindProperty(dataOverride.Key);
                    if (property == null)
                    {
                        Debug.LogWarning($"{dataOverride.Key} no longer exists in {variant}");
                        continue;
                    }
                    SetProperty(property, dataOverride.Value);
                }

                so.ApplyModifiedPropertiesWithoutUndo();
            }

            variantBase.Variant = variant;
            variant.name        = Path.GetFileNameWithoutExtension(assetPath);
            ctx.AddObjectToAsset(nameof(variant), variant);
        }
        public override void OnImportAsset(AssetImportContext ctx)
        {
            var graphAsset   = ScriptableObject.CreateInstance <SubGraphAsset>();
            var subGraphPath = ctx.assetPath;
            var subGraphGuid = AssetDatabase.AssetPathToGUID(subGraphPath);

            graphAsset.assetGuid = subGraphGuid;
            var textGraph      = File.ReadAllText(subGraphPath, Encoding.UTF8);
            var messageManager = new MessageManager();
            var graphData      = new GraphData
            {
                isSubGraph = true, assetGuid = subGraphGuid, messageManager = messageManager
            };

            MultiJson.Deserialize(graphData, textGraph);

            try
            {
                ProcessSubGraph(graphAsset, graphData);
            }
            catch (Exception e)
            {
                graphAsset.isValid = false;
                Debug.LogException(e, graphAsset);
            }
            finally
            {
                if (messageManager.AnyError())
                {
                    graphAsset.isValid = false;
                    foreach (var pair in messageManager.GetNodeMessages())
                    {
                        var node = graphData.GetNodeFromId(pair.Key);
                        foreach (var message in pair.Value)
                        {
                            MessageManager.Log(node, subGraphPath, message, graphAsset);
                        }
                    }
                }
                messageManager.ClearAll();
            }

            Texture2D texture = Resources.Load <Texture2D>("Icons/sg_subgraph_icon@64");

            ctx.AddObjectToAsset("MainAsset", graphAsset, texture);
            ctx.SetMainObject(graphAsset);

            var metadata = ScriptableObject.CreateInstance <ShaderSubGraphMetadata>();

            metadata.hideFlags         = HideFlags.HideInHierarchy;
            metadata.assetDependencies = new List <UnityEngine.Object>();

            AssetCollection assetCollection = new AssetCollection();

            MinimalGraphData.GatherMinimalDependenciesFromFile(assetPath, assetCollection);

            foreach (var asset in assetCollection.assets)
            {
                if (asset.Value.HasFlag(AssetCollection.Flags.IncludeInExportPackage))
                {
                    // this sucks that we have to fully load these assets just to set the reference,
                    // which then gets serialized as the GUID that we already have here.  :P

                    var dependencyPath = AssetDatabase.GUIDToAssetPath(asset.Key);
                    if (!string.IsNullOrEmpty(dependencyPath))
                    {
                        metadata.assetDependencies.Add(
                            AssetDatabase.LoadAssetAtPath(dependencyPath, typeof(UnityEngine.Object)));
                    }
                }
            }
            ctx.AddObjectToAsset("Metadata", metadata);

            // declare dependencies
            foreach (var asset in assetCollection.assets)
            {
                if (asset.Value.HasFlag(AssetCollection.Flags.SourceDependency))
                {
                    ctx.DependsOnSourceAsset(asset.Key);

                    // I'm not sure if this warning below is actually used or not, keeping it to be safe
                    var assetPath = AssetDatabase.GUIDToAssetPath(asset.Key);

                    // Ensure that dependency path is relative to project
                    if (!string.IsNullOrEmpty(assetPath) && !assetPath.StartsWith("Packages/") && !assetPath.StartsWith("Assets/"))
                    {
                        Debug.LogWarning($"Invalid dependency path: {assetPath}", graphAsset);
                    }
                }

                // NOTE: dependencies declared by GatherDependenciesFromSourceFile are automatically registered as artifact dependencies
                // HOWEVER: that path ONLY grabs dependencies via MinimalGraphData, and will fail to register dependencies
                // on GUIDs that don't exist in the project.  For both of those reasons, we re-declare the dependencies here.
                if (asset.Value.HasFlag(AssetCollection.Flags.ArtifactDependency))
                {
                    ctx.DependsOnArtifact(asset.Key);
                }
            }
        }
        public override void OnImportAsset(AssetImportContext ctx)
        {
            var oldShader = AssetDatabase.LoadAssetAtPath <Shader>(ctx.assetPath);

            if (oldShader != null)
            {
                ShaderUtil.ClearShaderMessages(oldShader);
            }

            List <PropertyCollector.TextureInfo> configuredTextures;
            string path = ctx.assetPath;

            AssetCollection assetCollection = new AssetCollection();

            MinimalGraphData.GatherMinimalDependenciesFromFile(assetPath, assetCollection);

            var textGraph = File.ReadAllText(path, Encoding.UTF8);
            var graph     = new GraphData
            {
                messageManager = new MessageManager(), assetGuid = AssetDatabase.AssetPathToGUID(path)
            };

            MultiJson.Deserialize(graph, textGraph);
            graph.OnEnable();
            graph.ValidateGraph();

            Shader shader = null;

#if VFX_GRAPH_10_0_0_OR_NEWER
            if (!graph.isOnlyVFXTarget)
#endif
            {
                // build the shader text
                // this will also add Target dependencies into the asset collection
                var text = GetShaderText(path, out configuredTextures, assetCollection, graph);

#if UNITY_2021_1_OR_NEWER
                // 2021.1 or later is guaranteed to have the new version of this function
                shader = ShaderUtil.CreateShaderAsset(ctx, text, false);
#else
                // earlier builds of Unity may or may not have it
                // here we try to invoke the new version via reflection
                var createShaderAssetMethod = typeof(ShaderUtil).GetMethod(
                    "CreateShaderAsset",
                    System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.ExactBinding,
                    null,
                    new Type[] { typeof(AssetImportContext), typeof(string), typeof(bool) },
                    null);

                if (createShaderAssetMethod != null)
                {
                    shader = createShaderAssetMethod.Invoke(null, new Object[] { ctx, text, false }) as Shader;
                }
                else
                {
                    // method doesn't exist in this version of Unity, call old version
                    // this doesn't create dependencies properly, but is the best that we can do
                    shader = ShaderUtil.CreateShaderAsset(text, false);
                }
#endif

                if (graph.messageManager.nodeMessagesChanged)
                {
                    foreach (var pair in graph.messageManager.GetNodeMessages())
                    {
                        var node = graph.GetNodeFromId(pair.Key);
                        MessageManager.Log(node, path, pair.Value.First(), shader);
                    }
                }

                EditorMaterialUtility.SetShaderDefaults(
                    shader,
                    configuredTextures.Where(x => x.modifiable).Select(x => x.name).ToArray(),
                    configuredTextures.Where(x => x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray());
                EditorMaterialUtility.SetShaderNonModifiableDefaults(
                    shader,
                    configuredTextures.Where(x => !x.modifiable).Select(x => x.name).ToArray(),
                    configuredTextures.Where(x => !x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray());
            }

            UnityEngine.Object mainObject = shader;
#if VFX_GRAPH_10_0_0_OR_NEWER
            ShaderGraphVfxAsset vfxAsset = null;
            if (graph.hasVFXTarget)
            {
                vfxAsset = GenerateVfxShaderGraphAsset(graph);
                if (mainObject == null)
                {
                    mainObject = vfxAsset;
                }
                else
                {
                    //Correct main object if we have a shader and ShaderGraphVfxAsset : save as sub asset
                    vfxAsset.name = Path.GetFileNameWithoutExtension(path);
                    ctx.AddObjectToAsset("VFXShaderGraph", vfxAsset);
                }
            }
#endif

            Texture2D texture = Resources.Load <Texture2D>("Icons/sg_graph_icon");
            ctx.AddObjectToAsset("MainAsset", mainObject, texture);
            ctx.SetMainObject(mainObject);

            foreach (var target in graph.activeTargets)
            {
                if (target is IHasMetadata iHasMetadata)
                {
                    var metadata = iHasMetadata.GetMetadataObject();
                    if (metadata == null)
                    {
                        continue;
                    }

                    metadata.hideFlags = HideFlags.HideInHierarchy;
                    ctx.AddObjectToAsset($"{iHasMetadata.identifier}:Metadata", metadata);
                }
            }

            var sgMetadata = ScriptableObject.CreateInstance <ShaderGraphMetadata>();
            sgMetadata.hideFlags         = HideFlags.HideInHierarchy;
            sgMetadata.assetDependencies = new List <UnityEngine.Object>();

            foreach (var asset in assetCollection.assets)
            {
                if (asset.Value.HasFlag(AssetCollection.Flags.IncludeInExportPackage))
                {
                    // this sucks that we have to fully load these assets just to set the reference,
                    // which then gets serialized as the GUID that we already have here.  :P

                    var dependencyPath = AssetDatabase.GUIDToAssetPath(asset.Key);
                    if (!string.IsNullOrEmpty(dependencyPath))
                    {
                        sgMetadata.assetDependencies.Add(
                            AssetDatabase.LoadAssetAtPath(dependencyPath, typeof(UnityEngine.Object)));
                    }
                }
            }
            ctx.AddObjectToAsset("SGInternal:Metadata", sgMetadata);

            // declare dependencies
            foreach (var asset in assetCollection.assets)
            {
                if (asset.Value.HasFlag(AssetCollection.Flags.SourceDependency))
                {
                    ctx.DependsOnSourceAsset(asset.Key);

                    // I'm not sure if this warning below is actually used or not, keeping it to be safe
                    var assetPath = AssetDatabase.GUIDToAssetPath(asset.Key);

                    // Ensure that dependency path is relative to project
                    if (!string.IsNullOrEmpty(assetPath) && !assetPath.StartsWith("Packages/") && !assetPath.StartsWith("Assets/"))
                    {
                        Debug.LogWarning($"Invalid dependency path: {assetPath}", mainObject);
                    }
                }

                // NOTE: dependencies declared by GatherDependenciesFromSourceFile are automatically registered as artifact dependencies
                // HOWEVER: that path ONLY grabs dependencies via MinimalGraphData, and will fail to register dependencies
                // on GUIDs that don't exist in the project.  For both of those reasons, we re-declare the dependencies here.
                if (asset.Value.HasFlag(AssetCollection.Flags.ArtifactDependency))
                {
                    ctx.DependsOnArtifact(asset.Key);
                }
            }
        }
Beispiel #5
0
        public override void OnImportAsset(AssetImportContext ctx)
        {
            var width         = 64;
            var mipmapEnabled = true;
            var textureFormat = TextureFormat.RGBA32;
            var srgbTexture   = true;

            // Mark all input textures as dependency to the CubemapArray.
            // This causes the CubemapArray to get re-generated when any input texture changes or when the build target changed.
            for (var n = 0; n < m_Cubemaps.Count; ++n)
            {
                var source = m_Cubemaps[n];
                if (source != null)
                {
                    var path = AssetDatabase.GetAssetPath(source);
#if UNITY_2020_1_OR_NEWER
                    ctx.DependsOnArtifact(path);
#else
                    ctx.DependsOnSourceAsset(path);
#endif
                }
            }

#if !UNITY_2020_1_OR_NEWER
            // This value is not really used in this importer,
            // but getting the build target here will add a dependency to the current active buildtarget.
            // Because DependsOnArtifact does not exist in 2019.4, adding this dependency on top of the DependsOnSourceAsset
            // will force a re-import when the target platform changes in case it would have impacted any texture this importer depends on.
            var buildTarget = ctx.selectedBuildTarget;
#endif

            // Check if the input textures are valid to be used to build the texture array.
            var isValid = Verify(ctx, false);
            if (isValid)
            {
                // Use the texture assigned to the first slice as "master".
                // This means all other textures have to use same settings as the master texture.
                var sourceTexture = m_Cubemaps[0];
                width         = sourceTexture.width;
                textureFormat = sourceTexture.format;

                var sourceTexturePath = AssetDatabase.GetAssetPath(sourceTexture);
                var textureImporter   = (TextureImporter)AssetImporter.GetAtPath(sourceTexturePath);
                mipmapEnabled = textureImporter.mipmapEnabled;
                srgbTexture   = textureImporter.sRGBTexture;
            }

            CubemapArray cubemapArray;
            try
            {
                // Create the texture array.
                // When the texture array asset is being created, there are no input textures added yet,
                // thus we do Max(1, Count) to make sure to add at least 1 slice.
                cubemapArray = new CubemapArray(width, Mathf.Max(1, m_Cubemaps.Count), textureFormat, mipmapEnabled, !srgbTexture);
            }
            catch (System.Exception e)
            {
                Debug.LogException(e);
                ctx.LogImportError($"Import failed '{ctx.assetPath}'.", ctx.mainObject);

                isValid       = false;
                textureFormat = TextureFormat.RGBA32;
                cubemapArray  = new CubemapArray(width, Mathf.Max(1, m_Cubemaps.Count), textureFormat, mipmapEnabled, !srgbTexture);
            }

            cubemapArray.wrapMode   = m_WrapMode;
            cubemapArray.filterMode = m_FilterMode;
            cubemapArray.anisoLevel = m_AnisoLevel;

            if (isValid)
            {
                // If everything is valid, copy source textures over to the texture array.
                for (int face = 0; face < 6; face++)
                {
                    for (var n = 0; n < m_Cubemaps.Count; ++n)
                    {
                        var source = m_Cubemaps[n];
                        Graphics.CopyTexture(source, face, cubemapArray, face + (n * 6));
                    }
                }
            }
            else
            {
                // If there is any error, copy a magenta colored texture into every slice.
                // I was thinking to only make the invalid slice magenta, but then it's way less obvious that
                // something isn't right with the texture array. Thus I mark the entire texture array as broken.
                var errorTexture = new Cubemap(width, textureFormat, mipmapEnabled);
                try
                {
                    for (var face = 0; face < 6; ++face)
                    {
                        var errorPixels = errorTexture.GetPixels((CubemapFace)face);
                        for (var n = 0; n < errorPixels.Length; ++n)
                        {
                            errorPixels[n] = Color.magenta;
                        }
                        errorTexture.SetPixels(errorPixels, (CubemapFace)face);
                    }
                    errorTexture.Apply();

                    for (int face = 0; face < 6; face++)
                    {
                        for (var n = 0; n < cubemapArray.cubemapCount; ++n)
                        {
                            Graphics.CopyTexture(errorTexture, face, cubemapArray, face + (n * 6));
                        }
                    }
                }
                finally
                {
                    DestroyImmediate(errorTexture);
                }
            }

            // this should have been named "MainAsset" to be conform with Unity, but changing it now
            // would break all existing CubemapArray assets, so we don't touch it.
            cubemapArray.Apply(false, !m_IsReadable);
            ctx.AddObjectToAsset("CubemapArray", cubemapArray);
            ctx.SetMainObject(cubemapArray);

            if (!isValid)
            {
                // Run the verify step again, but this time we have the main object asset.
                // Console logs should ping the asset, but they don't in 2019.3 beta, bug?
                Verify(ctx, true);
            }
        }
        /// <inheritdoc />
        public override void OnImportAsset(AssetImportContext ctx)
        {
            if (ctx == null)
            {
                return;
            }

            var outputFilePath = Path.Combine(Path.GetDirectoryName(ctx.assetPath), Path.GetFileNameWithoutExtension(ctx.assetPath) + ".cs");
            var src            = File.ReadAllText(ctx.assetPath);

            TemplateGenerator generator;

            switch (importerVersion)
            {
            case ImporterVersion.Stable:
                generator = new TemplateGenerator();
                break;

            case ImporterVersion.Beta:
            {
                generator = UnityDataHost <Object> .CreateInstance(embeddedData, additionalTypes);

                break;
            }

            default:
                throw new InvalidOperationException();
            }

            if (generator.ProcessTemplate(ctx.assetPath, src, ref outputFilePath, out string dst))
            {
                if (!removeIfEmptyGeneration || dst.Length > 0)
                {
                    File.WriteAllText(outputFilePath, dst);
                }

                EditorUtils.Once(() =>
                {
                    // TODO(bengreenier): is there a less expensive way to force it to reload scripts/appdomain?
                    AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
                });
            }
            else
            {
                for (var i = 0; i < generator.Errors.Count; i++)
                {
                    var err = generator.Errors[i];

                    Debug.LogError(err.ToString());
                }
            }

            // core asset import
            var asset = new TextAsset(src);

            ctx.AddObjectToAsset("text", asset);
            ctx.SetMainObject(asset);

            // setup data dependency
            if (embeddedData != null && importerVersion == ImporterVersion.Beta)
            {
                var dataPath = AssetDatabase.GetAssetPath(embeddedData);
                var dataGuid = AssetDatabase.GUIDFromAssetPath(dataPath);

                ctx.DependsOnArtifact(dataGuid);

                // needed to enforce the dependency
                AssetDatabase.LoadAssetAtPath <Object>(dataPath);
            }
        }
Beispiel #7
0
        public override void OnImportAsset(AssetImportContext ctx)
        {
            var width         = 8;
            var height        = 8;
            var mipmapEnabled = true;
            var textureFormat = TextureFormat.ARGB32;
            //var srgbTexture = true;

            // Check if the input textures are valid to be used to build the texture array.
            var isValid = Verify(ctx, false);

            if (isValid)
            {
                // Use the texture assigned to the first slice as "master".
                // This means all other textures have to use same settings as the master texture.
                var sourceTexture = m_Textures[0];
                width         = sourceTexture.width;
                height        = sourceTexture.height;
                textureFormat = sourceTexture.format;

                var sourceTexturePath = AssetDatabase.GetAssetPath(sourceTexture);
                var textureImporter   = (TextureImporter)AssetImporter.GetAtPath(sourceTexturePath);
                mipmapEnabled = textureImporter.mipmapEnabled;
                //srgbTexture = textureImporter.sRGBTexture;
            }

            // Create the texture array.
            // When the texture array asset is being created, there are no input textures added yet,
            // thus we do Max(1, Count) to make sure to add at least 1 slice.
            var texture3D = new Texture3D(width, height, Mathf.Max(1, m_Textures.Count), textureFormat, mipmapEnabled);//, !srgbTexture);

            texture3D.wrapMode   = m_WrapMode;
            texture3D.filterMode = m_FilterMode;
            texture3D.anisoLevel = m_AnisoLevel;

            if (isValid)
            {
                // If everything is valid, copy source textures over to the texture array.
                for (var n = 0; n < m_Textures.Count; ++n)
                {
                    var source = m_Textures[n];
                    Graphics.CopyTexture(source, 0, texture3D, n);
                }
            }
            else
            {
                // If there is any error, copy a magenta colored texture into every slice.
                // I was thinking to only make the invalid slice magenta, but then it's way less obvious that
                // something isn't right with the texture array. Thus I mark the entire texture array as broken.

                var errorPixels = new Color32[width * height];
                for (var n = 0; n < errorPixels.Length; ++n)
                {
                    errorPixels[n] = Color.magenta;
                }

                var texture3DPixels = new Color32[width * height * texture3D.depth];

                for (var n = 0; n < texture3D.depth; ++n)
                {
                    System.Array.Copy(errorPixels, 0, texture3DPixels, width * height * n, errorPixels.Length);
                }

                texture3D.SetPixels32(texture3DPixels);
                texture3D.Apply();
            }

            // Mark all input textures as dependency to the texture array.
            // This causes the texture array to get re-generated when any input texture changes or when the build target changed.
            for (var n = 0; n < m_Textures.Count; ++n)
            {
                var source = m_Textures[n];
                if (source != null)
                {
                    var path = AssetDatabase.GetAssetPath(source);
#if UNITY_2020_1_OR_NEWER
                    ctx.DependsOnArtifact(path);
#else
                    ctx.DependsOnSourceAsset(path);
#endif
                }
            }

#if !UNITY_2020_1_OR_NEWER
            // This value is not really used in this importer,
            // but getting the build target here will add a dependency to the current active buildtarget.
            // Because DependsOnArtifact does not exist in 2019.4, adding this dependency on top of the DependsOnSourceAsset
            // will force a re-import when the target platform changes in case it would have impacted any texture this importer depends on.
            var buildTarget = ctx.selectedBuildTarget;
#endif

            // this should have been named "MainAsset" to be conform with Unity, but changing it now
            // would break all existing Texture3DAtlas assets, so we don't touch it.
            ctx.AddObjectToAsset("Texture3D", texture3D);
            ctx.SetMainObject(texture3D);

            if (!isValid)
            {
                // Run the verify step again, but this time we have the main object asset.
                // Console logs should ping the asset, but they don't in 2019.3 beta, bug?
                Verify(ctx, true);
            }
        }
        public override void OnImportAsset(AssetImportContext ctx)
        {
            try
            {
                var sceneWithBuildConfiguration = SceneWithBuildConfigurationGUIDs.ReadFromFile(ctx.assetPath);

                // Ensure we have as many dependencies as possible registered early in case an exception is thrown
                EditorEntityScenes.AddEntityBinaryFileDependencies(ctx, sceneWithBuildConfiguration.BuildConfiguration);
                EditorEntityScenes.DependOnSceneGameObjects(sceneWithBuildConfiguration.SceneGUID, ctx);

                var config = BuildConfiguration.LoadAsset(sceneWithBuildConfiguration.BuildConfiguration);

                var scenePath = AssetDatabaseCompatibility.GuidToPath(sceneWithBuildConfiguration.SceneGUID);
                var scene     = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Additive);
                try
                {
                    EditorSceneManager.SetActiveScene(scene);

                    var settings = new GameObjectConversionSettings();

                    settings.SceneGUID = sceneWithBuildConfiguration.SceneGUID;
                    if (!sceneWithBuildConfiguration.IsBuildingForEditor)
                    {
                        settings.ConversionFlags |= GameObjectConversionUtility.ConversionFlags.IsBuildingForPlayer;
                    }

                    settings.BuildConfiguration = config;
                    settings.AssetImportContext = ctx;
                    settings.FilterFlags        = WorldSystemFilterFlags.HybridGameObjectConversion;

                    WriteEntitySceneSettings writeEntitySettings = new WriteEntitySceneSettings();
                    if (config != null && config.TryGetComponent <DotsRuntimeBuildProfile>(out var profile))
                    {
                        if (config.TryGetComponent <DotsRuntimeRootAssembly>(out var rootAssembly))
                        {
                            writeEntitySettings.Codec              = Codec.LZ4;
                            writeEntitySettings.IsDotsRuntime      = true;
                            writeEntitySettings.BuildAssemblyCache = new BuildAssemblyCache()
                            {
                                BaseAssemblies = rootAssembly.RootAssembly.asset,
                                PlatformName   = profile.Target.UnityPlatformName
                            };
                            settings.FilterFlags = WorldSystemFilterFlags.DotsRuntimeGameObjectConversion;

                            //Updating the root asmdef references or its references should re-trigger conversion
                            ctx.DependsOnArtifact(AssetDatabase.GetAssetPath(rootAssembly.RootAssembly.asset));
                            foreach (var assemblyPath in writeEntitySettings.BuildAssemblyCache.AssembliesPath)
                            {
                                ctx.DependsOnArtifact(assemblyPath);
                            }
                        }
                    }

                    var sectionRefObjs = new List <ReferencedUnityObjects>();
                    var sectionData    = EditorEntityScenes.ConvertAndWriteEntityScene(scene, settings, sectionRefObjs, writeEntitySettings);

                    WriteAssetDependencyGUIDs(sectionRefObjs, sectionData, ctx);

                    foreach (var objRefs in sectionRefObjs)
                    {
                        DestroyImmediate(objRefs);
                    }
                }
                finally
                {
                    EditorSceneManager.CloseScene(scene, true);
                }
            }
            // Currently it's not acceptable to let the asset database catch the exception since it will create a default asset without any dependencies
            // This means a reimport will not be triggered if the scene is subsequently modified
            catch (Exception e)
            {
                Debug.Log($"Exception thrown during SubScene import: {e}");
            }
        }
Beispiel #9
0
        public override void OnImportAsset(AssetImportContext ctx)
        {
            var    importLog = new AssetImportErrorLog(ctx);
            string path      = ctx.assetPath;

            AssetCollection assetCollection = new AssetCollection();

            MinimalGraphData.GatherMinimalDependenciesFromFile(assetPath, assetCollection);

            var textGraph = File.ReadAllText(path, Encoding.UTF8);
            var graph     = new GraphData
            {
                messageManager = new MessageManager(),
                assetGuid      = AssetDatabase.AssetPathToGUID(path)
            };

            MultiJson.Deserialize(graph, textGraph);
            graph.OnEnable();
            graph.ValidateGraph();

            UnityEngine.Object mainObject = null;
#if VFX_GRAPH_10_0_0_OR_NEWER
            if (!graph.isOnlyVFXTarget)
#endif
            {
                // build shaders
                mainObject = BuildAllShaders(ctx, importLog, assetCollection, graph);
            }

#if VFX_GRAPH_10_0_0_OR_NEWER
            ShaderGraphVfxAsset vfxAsset = null;
            if (graph.hasVFXTarget)
            {
                vfxAsset = GenerateVfxShaderGraphAsset(graph);
                if (mainObject == null)
                {
                    mainObject = vfxAsset;
                }
                else
                {
                    //Correct main object if we have a shader and ShaderGraphVfxAsset : save as sub asset
                    vfxAsset.name = Path.GetFileNameWithoutExtension(path);
                    ctx.AddObjectToAsset("VFXShaderGraph", vfxAsset);
                }
            }
#endif

            Texture2D texture = Resources.Load <Texture2D>("Icons/sg_graph_icon");
            ctx.AddObjectToAsset("MainAsset", mainObject, texture);
            ctx.SetMainObject(mainObject);

            foreach (var target in graph.activeTargets)
            {
                if (target is IHasMetadata iHasMetadata)
                {
                    var metadata = iHasMetadata.GetMetadataObject();
                    if (metadata == null)
                    {
                        continue;
                    }

                    metadata.hideFlags = HideFlags.HideInHierarchy;
                    ctx.AddObjectToAsset($"{iHasMetadata.identifier}:Metadata", metadata);
                }
            }

            var sgMetadata = ScriptableObject.CreateInstance <ShaderGraphMetadata>();
            sgMetadata.hideFlags         = HideFlags.HideInHierarchy;
            sgMetadata.assetDependencies = new List <UnityEngine.Object>();

            foreach (var asset in assetCollection.assets)
            {
                if (asset.Value.HasFlag(AssetCollection.Flags.IncludeInExportPackage))
                {
                    // this sucks that we have to fully load these assets just to set the reference,
                    // which then gets serialized as the GUID that we already have here.  :P

                    var dependencyPath = AssetDatabase.GUIDToAssetPath(asset.Key);
                    if (!string.IsNullOrEmpty(dependencyPath))
                    {
                        sgMetadata.assetDependencies.Add(
                            AssetDatabase.LoadAssetAtPath(dependencyPath, typeof(UnityEngine.Object)));
                    }
                }
            }

            List <GraphInputData> inputInspectorDataList = new List <GraphInputData>();
            foreach (AbstractShaderProperty property in graph.properties)
            {
                // Don't write out data for non-exposed blackboard items
                if (!property.isExposed)
                {
                    continue;
                }

                // VTs are treated differently
                if (property is VirtualTextureShaderProperty virtualTextureShaderProperty)
                {
                    inputInspectorDataList.Add(MinimalCategoryData.ProcessVirtualTextureProperty(virtualTextureShaderProperty));
                }
                else
                {
                    inputInspectorDataList.Add(new GraphInputData()
                    {
                        referenceName = property.referenceName, propertyType = property.propertyType, isKeyword = false
                    });
                }
            }
            foreach (ShaderKeyword keyword in graph.keywords)
            {
                // Don't write out data for non-exposed blackboard items
                if (!keyword.isExposed)
                {
                    continue;
                }

                var sanitizedReferenceName = keyword.referenceName;
                if (keyword.keywordType == KeywordType.Boolean && keyword.referenceName.Contains("_ON"))
                {
                    sanitizedReferenceName = sanitizedReferenceName.Replace("_ON", String.Empty);
                }

                inputInspectorDataList.Add(new GraphInputData()
                {
                    referenceName = sanitizedReferenceName, keywordType = keyword.keywordType, isKeyword = true
                });
            }

            sgMetadata.categoryDatas = new List <MinimalCategoryData>();
            foreach (CategoryData categoryData in graph.categories)
            {
                // Don't write out empty categories
                if (categoryData.childCount == 0)
                {
                    continue;
                }

                MinimalCategoryData mcd = new MinimalCategoryData()
                {
                    categoryName  = categoryData.name,
                    propertyDatas = new List <GraphInputData>()
                };
                foreach (var input in categoryData.Children)
                {
                    GraphInputData propData;
                    // Only write out data for exposed blackboard items
                    if (input.isExposed == false)
                    {
                        continue;
                    }

                    // VTs are treated differently
                    if (input is VirtualTextureShaderProperty virtualTextureShaderProperty)
                    {
                        propData = MinimalCategoryData.ProcessVirtualTextureProperty(virtualTextureShaderProperty);
                        inputInspectorDataList.RemoveAll(inputData => inputData.referenceName == propData.referenceName);
                        mcd.propertyDatas.Add(propData);
                        continue;
                    }
                    else if (input is ShaderKeyword keyword)
                    {
                        var sanitizedReferenceName = keyword.referenceName;
                        if (keyword.keywordType == KeywordType.Boolean && keyword.referenceName.Contains("_ON"))
                        {
                            sanitizedReferenceName = sanitizedReferenceName.Replace("_ON", String.Empty);
                        }

                        propData = new GraphInputData()
                        {
                            referenceName = sanitizedReferenceName, keywordType = keyword.keywordType, isKeyword = true
                        };
                    }
                    else
                    {
                        var prop = input as AbstractShaderProperty;
                        propData = new GraphInputData()
                        {
                            referenceName = input.referenceName, propertyType = prop.propertyType, isKeyword = false
                        };
                    }

                    mcd.propertyDatas.Add(propData);
                    inputInspectorDataList.Remove(propData);
                }
                sgMetadata.categoryDatas.Add(mcd);
            }

            // Any uncategorized elements get tossed into an un-named category at the top as a fallback
            if (inputInspectorDataList.Count > 0)
            {
                sgMetadata.categoryDatas.Insert(0, new MinimalCategoryData()
                {
                    categoryName = "", propertyDatas = inputInspectorDataList
                });
            }

            ctx.AddObjectToAsset("SGInternal:Metadata", sgMetadata);

            // declare dependencies
            foreach (var asset in assetCollection.assets)
            {
                if (asset.Value.HasFlag(AssetCollection.Flags.SourceDependency))
                {
                    ctx.DependsOnSourceAsset(asset.Key);

                    // I'm not sure if this warning below is actually used or not, keeping it to be safe
                    var assetPath = AssetDatabase.GUIDToAssetPath(asset.Key);

                    // Ensure that dependency path is relative to project
                    if (!string.IsNullOrEmpty(assetPath) && !assetPath.StartsWith("Packages/") && !assetPath.StartsWith("Assets/"))
                    {
                        importLog.LogWarning($"Invalid dependency path: {assetPath}", mainObject);
                    }
                }

                // NOTE: dependencies declared by GatherDependenciesFromSourceFile are automatically registered as artifact dependencies
                // HOWEVER: that path ONLY grabs dependencies via MinimalGraphData, and will fail to register dependencies
                // on GUIDs that don't exist in the project.  For both of those reasons, we re-declare the dependencies here.
                if (asset.Value.HasFlag(AssetCollection.Flags.ArtifactDependency))
                {
                    ctx.DependsOnArtifact(asset.Key);
                }
            }
        }
        public override void OnImportAsset(AssetImportContext ctx)
        {
            var oldShader = AssetDatabase.LoadAssetAtPath <Shader>(ctx.assetPath);

            if (oldShader != null)
            {
                ShaderUtil.ClearShaderMessages(oldShader);
            }

            List <PropertyCollector.TextureInfo> configuredTextures;
            string path = ctx.assetPath;

            AssetCollection assetCollection = new AssetCollection();

            MinimalGraphData.GatherMinimalDependenciesFromFile(assetPath, assetCollection);

            var textGraph = File.ReadAllText(path, Encoding.UTF8);
            var graph     = new GraphData
            {
                messageManager = new MessageManager(), assetGuid = AssetDatabase.AssetPathToGUID(path)
            };

            MultiJson.Deserialize(graph, textGraph);
            graph.OnEnable();
            graph.ValidateGraph();

            Shader shader = null;

#if VFX_GRAPH_10_0_0_OR_NEWER
            if (!graph.isOnlyVFXTarget)
#endif
            {
                // build the shader text
                // this will also add Target dependencies into the asset collection
                var text = GetShaderText(path, out configuredTextures, assetCollection, graph);

#if UNITY_2021_1_OR_NEWER
                // 2021.1 or later is guaranteed to have the new version of this function
                shader = ShaderUtil.CreateShaderAsset(ctx, text, false);
#else
                // earlier builds of Unity may or may not have it
                // here we try to invoke the new version via reflection
                var createShaderAssetMethod = typeof(ShaderUtil).GetMethod(
                    "CreateShaderAsset",
                    System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.ExactBinding,
                    null,
                    new Type[] { typeof(AssetImportContext), typeof(string), typeof(bool) },
                    null);

                if (createShaderAssetMethod != null)
                {
                    shader = createShaderAssetMethod.Invoke(null, new Object[] { ctx, text, false }) as Shader;
                }
                else
                {
                    // method doesn't exist in this version of Unity, call old version
                    // this doesn't create dependencies properly, but is the best that we can do
                    shader = ShaderUtil.CreateShaderAsset(text, false);
                }
#endif

                ReportErrors(graph, shader, path);

                EditorMaterialUtility.SetShaderDefaults(
                    shader,
                    configuredTextures.Where(x => x.modifiable).Select(x => x.name).ToArray(),
                    configuredTextures.Where(x => x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray());
                EditorMaterialUtility.SetShaderNonModifiableDefaults(
                    shader,
                    configuredTextures.Where(x => !x.modifiable).Select(x => x.name).ToArray(),
                    configuredTextures.Where(x => !x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray());
            }

            UnityEngine.Object mainObject = shader;
#if VFX_GRAPH_10_0_0_OR_NEWER
            ShaderGraphVfxAsset vfxAsset = null;
            if (graph.hasVFXTarget)
            {
                vfxAsset = GenerateVfxShaderGraphAsset(graph);
                if (mainObject == null)
                {
                    mainObject = vfxAsset;
                }
                else
                {
                    //Correct main object if we have a shader and ShaderGraphVfxAsset : save as sub asset
                    vfxAsset.name = Path.GetFileNameWithoutExtension(path);
                    ctx.AddObjectToAsset("VFXShaderGraph", vfxAsset);
                }
            }
#endif

            Texture2D texture = Resources.Load <Texture2D>("Icons/sg_graph_icon");
            ctx.AddObjectToAsset("MainAsset", mainObject, texture);
            ctx.SetMainObject(mainObject);

            foreach (var target in graph.activeTargets)
            {
                if (target is IHasMetadata iHasMetadata)
                {
                    var metadata = iHasMetadata.GetMetadataObject();
                    if (metadata == null)
                    {
                        continue;
                    }

                    metadata.hideFlags = HideFlags.HideInHierarchy;
                    ctx.AddObjectToAsset($"{iHasMetadata.identifier}:Metadata", metadata);
                }
            }

            var sgMetadata = ScriptableObject.CreateInstance <ShaderGraphMetadata>();
            sgMetadata.hideFlags         = HideFlags.HideInHierarchy;
            sgMetadata.assetDependencies = new List <UnityEngine.Object>();

            foreach (var asset in assetCollection.assets)
            {
                if (asset.Value.HasFlag(AssetCollection.Flags.IncludeInExportPackage))
                {
                    // this sucks that we have to fully load these assets just to set the reference,
                    // which then gets serialized as the GUID that we already have here.  :P

                    var dependencyPath = AssetDatabase.GUIDToAssetPath(asset.Key);
                    if (!string.IsNullOrEmpty(dependencyPath))
                    {
                        sgMetadata.assetDependencies.Add(
                            AssetDatabase.LoadAssetAtPath(dependencyPath, typeof(UnityEngine.Object)));
                    }
                }
            }

            List <MinimalCategoryData.GraphInputData> inputInspectorDataList = new List <MinimalCategoryData.GraphInputData>();
            foreach (AbstractShaderProperty property in graph.properties)
            {
                // Don't write out data for non-exposed blackboard items
                if (!property.isExposed)
                {
                    continue;
                }

                // VTs are treated differently
                if (property is VirtualTextureShaderProperty virtualTextureShaderProperty)
                {
                    inputInspectorDataList.Add(MinimalCategoryData.ProcessVirtualTextureProperty(virtualTextureShaderProperty));
                }
                else
                {
                    inputInspectorDataList.Add(new MinimalCategoryData.GraphInputData()
                    {
                        referenceName = property.referenceName, propertyType = property.propertyType, isKeyword = false
                    });
                }
            }
            foreach (ShaderKeyword keyword in graph.keywords)
            {
                // Don't write out data for non-exposed blackboard items
                if (!keyword.isExposed)
                {
                    continue;
                }

                var sanitizedReferenceName = keyword.referenceName;
                if (keyword.keywordType == KeywordType.Boolean && keyword.referenceName.Contains("_ON"))
                {
                    sanitizedReferenceName = sanitizedReferenceName.Replace("_ON", String.Empty);
                }

                inputInspectorDataList.Add(new MinimalCategoryData.GraphInputData()
                {
                    referenceName = sanitizedReferenceName, keywordType = keyword.keywordType, isKeyword = true
                });
            }

            sgMetadata.categoryDatas = new List <MinimalCategoryData>();
            foreach (CategoryData categoryData in graph.categories)
            {
                // Don't write out empty categories
                if (categoryData.childCount == 0)
                {
                    continue;
                }

                MinimalCategoryData mcd = new MinimalCategoryData()
                {
                    categoryName  = categoryData.name,
                    propertyDatas = new List <MinimalCategoryData.GraphInputData>()
                };
                foreach (var input in categoryData.Children)
                {
                    MinimalCategoryData.GraphInputData propData;
                    // Only write out data for exposed blackboard items
                    if (input.isExposed == false)
                    {
                        continue;
                    }

                    // VTs are treated differently
                    if (input is VirtualTextureShaderProperty virtualTextureShaderProperty)
                    {
                        propData = MinimalCategoryData.ProcessVirtualTextureProperty(virtualTextureShaderProperty);
                        inputInspectorDataList.RemoveAll(inputData => inputData.referenceName == propData.referenceName);
                        mcd.propertyDatas.Add(propData);
                        continue;
                    }
                    else if (input is ShaderKeyword keyword)
                    {
                        var sanitizedReferenceName = keyword.referenceName;
                        if (keyword.keywordType == KeywordType.Boolean && keyword.referenceName.Contains("_ON"))
                        {
                            sanitizedReferenceName = sanitizedReferenceName.Replace("_ON", String.Empty);
                        }

                        propData = new MinimalCategoryData.GraphInputData()
                        {
                            referenceName = sanitizedReferenceName, keywordType = keyword.keywordType, isKeyword = true
                        };
                    }
                    else
                    {
                        var prop = input as AbstractShaderProperty;
                        propData = new MinimalCategoryData.GraphInputData()
                        {
                            referenceName = input.referenceName, propertyType = prop.propertyType, isKeyword = false
                        };
                    }

                    mcd.propertyDatas.Add(propData);
                    inputInspectorDataList.Remove(propData);
                }
                sgMetadata.categoryDatas.Add(mcd);
            }

            // Any uncategorized elements get tossed into an un-named category at the top as a fallback
            if (inputInspectorDataList.Count > 0)
            {
                sgMetadata.categoryDatas.Insert(0, new MinimalCategoryData()
                {
                    categoryName = "", propertyDatas = inputInspectorDataList
                });
            }

            ctx.AddObjectToAsset("SGInternal:Metadata", sgMetadata);

            // declare dependencies
            foreach (var asset in assetCollection.assets)
            {
                if (asset.Value.HasFlag(AssetCollection.Flags.SourceDependency))
                {
                    ctx.DependsOnSourceAsset(asset.Key);

                    // I'm not sure if this warning below is actually used or not, keeping it to be safe
                    var assetPath = AssetDatabase.GUIDToAssetPath(asset.Key);

                    // Ensure that dependency path is relative to project
                    if (!string.IsNullOrEmpty(assetPath) && !assetPath.StartsWith("Packages/") && !assetPath.StartsWith("Assets/"))
                    {
                        Debug.LogWarning($"Invalid dependency path: {assetPath}", mainObject);
                    }
                }

                // NOTE: dependencies declared by GatherDependenciesFromSourceFile are automatically registered as artifact dependencies
                // HOWEVER: that path ONLY grabs dependencies via MinimalGraphData, and will fail to register dependencies
                // on GUIDs that don't exist in the project.  For both of those reasons, we re-declare the dependencies here.
                if (asset.Value.HasFlag(AssetCollection.Flags.ArtifactDependency))
                {
                    ctx.DependsOnArtifact(asset.Key);
                }
            }
        }