Exemplo n.º 1
0
        // Recursive until new SBP APIs land in 2020.1
        internal static Hash128[] GetDependenciesInternal(Hash128 artifactHash)
        {
            try
            {
                AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out string[] paths);
                var metaPath = paths.First(o => o.EndsWith(k_DependenciesExtension));
                if (metaPath == null)
                {
                    return(Array.Empty <Hash128>());
                }

                BlobAssetReference <BuildMetaData> buildMetaData;
                if (!BlobAssetReference <BuildMetaData> .TryRead(metaPath, k_CurrentFileFormatVersion, out buildMetaData))
                {
                    return(new Hash128[0]);
                }

                Hash128[] guids = buildMetaData.Value.Dependencies.ToArray();
                buildMetaData.Dispose();
                return(guids);
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogError($"Exception thrown getting dependencies for '{artifactHash}'.\n{e.Message}");
            }
            return(new Hash128[0]);
        }
        static unsafe TypeDependencyCache()
        {
            //TODO: Find a better way to enforce Version 2 compatibility
            bool v2Enabled = (bool)typeof(AssetDatabase).GetMethod("IsV2Enabled", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, null);

            if (!v2Enabled)
            {
                throw new System.InvalidOperationException("com.unity.entities requires Asset Pipeline Version 2. Please enable Version 2 in Project Settings / Editor / Asset Pipeline / Mode");
            }

            // Custom dependencies are transmitted to the import worker so dont spent time on registering them
            if (AssetDatabaseCompatibility.IsAssetImportWorkerProcess())
            {
                return;
            }

            using (kRegisterComponentTypes.Auto())
                RegisterComponentTypes();

            using (kRegisterConversionSystemVersions.Auto())
                RegisterConversionSystems();

            int fileFormatVersion = SerializeUtility.CurrentFileFormatVersion;

            UnityEngine.Hash128 fileFormatHash = default;
            HashUnsafeUtilities.ComputeHash128(&fileFormatVersion, sizeof(int), &fileFormatHash);
            AssetDatabaseCompatibility.RegisterCustomDependency("EntityBinaryFileFormatVersion", fileFormatHash);

            int sceneFileFormatVersion = SceneMetaDataSerializeUtility.CurrentFileFormatVersion;

            UnityEngine.Hash128 sceneFileFormatHash = default;
            HashUnsafeUtilities.ComputeHash128(&sceneFileFormatVersion, sizeof(int), &sceneFileFormatHash);
            AssetDatabaseCompatibility.RegisterCustomDependency("SceneMetaDataFileFormatVersion", sceneFileFormatHash);
        }
Exemplo n.º 3
0
        public static void Check(string path)
        {
            var guid = AssetDatabaseCompatibility.PathToGUID(path);

            Assert.IsFalse(guid.Empty());

            var configGUID = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(guid, default, true, out var requireRefresh);
Exemplo n.º 4
0
        internal static Hash128 GetHash(string guid, BuildTarget target, ImportMode importMode)
        {
            LiveLinkBuildPipeline.RemapBuildInAssetGuid(ref guid);
            AssetBundleTypeCache.RegisterMonoScripts();

            // TODO: GetArtifactHash needs to take BuildTarget so we can get Artifacts for other than the ActiveBuildTarget
            return(AssetDatabaseCompatibility.GetArtifactHash(guid, typeof(LiveLinkBuildImporter), importMode));
        }
        static unsafe void RegisterConversionSystems()
        {
            var systems        = DefaultWorldInitialization.GetAllSystems(WorldSystemFilterFlags.GameObjectConversion | WorldSystemFilterFlags.EntitySceneOptimizations);
            var behaviours     = TypeCache.GetTypesDerivedFrom <IConvertGameObjectToEntity>();
            var nameAndVersion = new NameAndVersion[systems.Count + behaviours.Count];

            int count = 0;

            // System versions
            for (int i = 0; i != systems.Count; i++)
            {
                var fullName = systems[i].FullName;
                if (fullName == null)
                {
                    continue;
                }

                nameAndVersion[count++].Init(systems[i], fullName);
            }

            // IConvertGameObjectToEntity versions
            for (int i = 0; i != behaviours.Count; i++)
            {
                var fullName = behaviours[i].FullName;
                if (fullName == null)
                {
                    continue;
                }

                nameAndVersion[count++].Init(behaviours[i], fullName);
            }

            Array.Sort(nameAndVersion, 0, count);

            UnityEngine.Hash128 hash = default;
            for (int i = 0; i != count; i++)
            {
                var fullName = nameAndVersion[i].FullName;
                fixed(char *str = fullName)
                {
                    HashUnsafeUtilities.ComputeHash128(str, (ulong)(sizeof(char) * fullName.Length), &hash);
                }

                var userName = nameAndVersion[i].UserName;
                if (userName != null)
                {
                    fixed(char *str = userName)
                    {
                        HashUnsafeUtilities.ComputeHash128(str, (ulong)(sizeof(char) * userName.Length), &hash);
                    }
                }

                int version = nameAndVersion[i].Version;
                HashUnsafeUtilities.ComputeHash128(&version, sizeof(int), &hash);
            }

            AssetDatabaseCompatibility.RegisterCustomDependency(SystemsVersion, hash);
        }
        static void RegisterComponentTypes()
        {
            TypeManager.Initialize();

            AssetDatabaseCompatibility.UnregisterCustomDependencyPrefixFilter("DOTSType/");
            int typeCount = TypeManager.GetTypeCount();

            for (int i = 1; i < typeCount; ++i)
            {
                ref readonly var typeInfo = ref TypeManager.GetTypeInfo(i);
        public void SectionMetadata()
        {
            using (var world = TestWorldSetup.CreateEntityWorld("World", false))
            {
                var resolveParams = new SceneSystem.LoadParameters
                {
                    Flags = SceneLoadFlags.BlockOnImport | SceneLoadFlags.DisableAutoLoad
                };
                var sceneSystem = world.GetOrCreateSystem <SceneSystem>();
                var sceneEntity = sceneSystem.LoadSceneAsync(SceneGUID, resolveParams);
                world.Update();
                var manager         = world.EntityManager;
                var sectionEntities = manager.GetBuffer <ResolvedSectionEntity>(sceneEntity);

                Assert.AreEqual(3, sectionEntities.Length);
                Assert.IsTrue(manager.HasComponent <TestMetadata>(sectionEntities[0].SectionEntity));
                Assert.IsFalse(manager.HasComponent <TestMetadata>(sectionEntities[1].SectionEntity));
                Assert.IsTrue(manager.HasComponent <TestMetadata>(sectionEntities[2].SectionEntity));

                Assert.IsTrue(manager.HasComponent <TestMetadataTag>(sectionEntities[0].SectionEntity));
                Assert.IsFalse(manager.HasComponent <TestMetadataTag>(sectionEntities[1].SectionEntity));
                Assert.IsTrue(manager.HasComponent <TestMetadataTag>(sectionEntities[2].SectionEntity));

                // These components should not be added, instead an error is logged that meta info components can't contain entities or blob assets
                var filteredTypes = new[]
                {
                    typeof(TestMetadataWithEntity), typeof(TestMetadataWithBlobAsset), typeof(EcsTestSharedComp), typeof(EcsIntElement), typeof(EcsState1),
#if !UNITY_DISABLE_MANAGED_COMPONENTS
                    typeof(EcsTestManagedComponent)
#endif
                };

                foreach (var type in filteredTypes)
                {
                    var componentType = ComponentType.FromTypeIndex(TypeManager.GetTypeIndex(type));
                    Assert.IsFalse(manager.HasComponent(sectionEntities[0].SectionEntity, componentType));
                }

                Assert.AreEqual(0, manager.GetComponentData <TestMetadata>(sectionEntities[0].SectionEntity).SectionIndex);
                Assert.AreEqual(13, manager.GetComponentData <TestMetadata>(sectionEntities[0].SectionEntity).Value);
                Assert.AreEqual(42, manager.GetComponentData <TestMetadata>(sectionEntities[2].SectionEntity).SectionIndex);
                Assert.AreEqual(100, manager.GetComponentData <TestMetadata>(sectionEntities[2].SectionEntity).Value);

                var hash = EntityScenesPaths.GetSubSceneArtifactHash(SceneGUID, sceneSystem.BuildConfigurationGUID, true, ImportMode.Synchronous);
                Assert.IsTrue(hash.IsValid);
                AssetDatabaseCompatibility.GetArtifactPaths(hash, out var paths);
                var logPath = EntityScenesPaths.GetLoadPathFromArtifactPaths(paths, EntityScenesPaths.PathType.EntitiesConversionLog);
                Assert.NotNull(logPath);
                var log = System.IO.File.ReadAllText(logPath);
                Assert.IsTrue(log.Contains("The component type must contains only blittable/basic data types"));
                Assert.IsFalse(log.Contains("entities in the scene 'TestSubSceneWithSectionMetadata' had no SceneSection and as a result were not serialized at all."));
            }
        }
Exemplo n.º 8
0
        // This function is responsible for providing all the subscenes to the build.
        //
        // The way these files get generated is that we have a SceneWithBuildConfiguration file, (which is a bit of a hack to work around the inability for scriptable importers to take arguments, so
        // instead we create a different file that points to the scene we want to import, and points to the buildconfiguration we want to import it for).   The SubsceneImporter will import this file,
        // and it will make 3 (relevant) kind of files:
        // - headerfile
        // - entitybinaryformat file (the actual entities payloads)
        // - a SerializedFile that has an array of UnityEngine.Object PPtrs that are used by this entity file.
        //
        // The first two we deal with very simply: they just need to be copied into the build, and we're done.
        // the third one, we will feed as input to the Scriptable build pipeline (which is actually about creating assetbundles), and create an assetbundle that
        // has all those objects in it that the 3rd file referred to.  We do this with a batch api, first we loop through all subscenes, and register with this batch
        // api which assetbundles we'd like to see produced, and then at the end, we say "okay make them please".  this assetbundle creation api has a caching system
        // that is separate from the assetpipeline caching system, so if all goes well, the call to produce these assetbundles will return very fast and did nothing.
        //
        // The reason for the strange looking api, where a two callbacks get passed in is to make integration of the new incremental buildpipeline easier, as this code
        // needs to be compatible both with the current buildpipeline in the dots-repo, as well as with the incremental buildpipeline.  When that is merged, we can simplify this.

        public static void PrepareAdditionalFiles(string buildConfigurationGuid, Func <Type, IBuildComponent> getRequiredComponent, Action <string, string> RegisterFileCopy, string outputStreamingAssetsDirectory, string buildWorkingDirectory)
        {
            T GetRequiredComponent <T>() => (T)getRequiredComponent(typeof(T));

            var profile = GetRequiredComponent <ClassicBuildProfile>();

            if (profile.Target == BuildTarget.NoTarget)
            {
                throw new InvalidOperationException($"Invalid build target '{profile.Target.ToString()}'.");
            }

            if (profile.Target != EditorUserBuildSettings.activeBuildTarget)
            {
                throw new InvalidOperationException($"ActiveBuildTarget must be switched before the {nameof(SubSceneBuildCode)} runs.");
            }

            var content       = new BundleBuildContent(new AssetBundleBuild[0]);
            var sceneList     = GetRequiredComponent <SceneList>();
            var bundleNames   = new List <string>();
            var subSceneGuids = sceneList.GetScenePathsForBuild().SelectMany(scenePath => SceneMetaDataImporter.GetSubSceneGuids(AssetDatabase.AssetPathToGUID(scenePath))).Distinct().ToList();

            foreach (var subSceneGuid in subSceneGuids)
            {
                var hash128Guid = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(subSceneGuid, new Hash128(buildConfigurationGuid));

                var hash = AssetDatabaseCompatibility.GetArtifactHash(hash128Guid.ToString(), typeof(SubSceneImporter), ImportMode.Synchronous);
                AssetDatabaseCompatibility.GetArtifactPaths(hash, out var artifactPaths);

                foreach (var artifactPath in artifactPaths)
                {
                    var ext = Path.GetExtension(artifactPath).Replace(".", "");
                    if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesHeader))
                    {
                        var destinationFile = outputStreamingAssetsDirectory + "/" + EntityScenesPaths.RelativePathInStreamingAssetsFolderFor(subSceneGuid, EntityScenesPaths.PathType.EntitiesHeader, -1);
                        RegisterFileCopy(artifactPath, destinationFile);
                    }

                    if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesBinary))
                    {
                        var destinationFile = outputStreamingAssetsDirectory + "/" + EntityScenesPaths.RelativePathInStreamingAssetsFolderFor(subSceneGuid, EntityScenesPaths.PathType.EntitiesBinary, EntityScenesPaths.GetSectionIndexFromPath(artifactPath));
                        RegisterFileCopy(artifactPath, destinationFile);
                    }

                    if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesUnityObjectReferences))
                    {
                        content.CustomAssets.Add(new CustomContent
                        {
                            Asset     = hash128Guid,
                            Processor = (guid, processor) =>
                            {
                                var sectionIndex = EntityScenesPaths.GetSectionIndexFromPath(artifactPath);
                                processor.GetObjectIdentifiersAndTypesForSerializedFile(artifactPath, out ObjectIdentifier[] objectIds, out Type[] types);
Exemplo n.º 9
0
 internal static string GetBundlePathInternal(Hash128 artifactHash, GUID guid)
 {
     try
     {
         AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out string[] paths);
         return(paths.First(o => o.EndsWith(k_BundleExtension)));
     }
     catch (Exception e)
     {
         UnityEngine.Debug.LogError($"Exception thrown getting bundle path for '{guid}'.\n{e.Message}");
     }
     return("");
 }
Exemplo n.º 10
0
        bool CheckConversionLog(SubScene subScene)
        {
            var pendingWork = false;

            foreach (var world in World.All)
            {
                var sceneSystem = world.GetExistingSystem <SceneSystem>();
                if (sceneSystem is null)
                {
                    continue;
                }

                if (!m_ConversionLogLoaded.TryGetValue(sceneSystem.BuildConfigurationGUID, out var loaded))
                {
                    m_ConversionLogLoaded.Add(sceneSystem.BuildConfigurationGUID, false);
                }
                else if (loaded)
                {
                    continue;
                }

                var hash = EntityScenesPaths.GetSubSceneArtifactHash(subScene.SceneGUID, sceneSystem.BuildConfigurationGUID, ImportMode.Asynchronous);
                if (!hash.IsValid)
                {
                    pendingWork = true;
                    continue;
                }

                m_ConversionLogLoaded[sceneSystem.BuildConfigurationGUID] = true;

                AssetDatabaseCompatibility.GetArtifactPaths(hash, out var paths);
                var logPath = EntityScenesPaths.GetLoadPathFromArtifactPaths(paths, EntityScenesPaths.PathType.EntitiesConversionLog);
                if (logPath == null)
                {
                    continue;
                }

                var log = File.ReadAllText(logPath);
                if (log.Trim().Length != 0)
                {
                    if (m_ConversionLog.Length != 0)
                    {
                        m_ConversionLog += "\n\n";
                    }
                    m_ConversionLog += log;
                }
            }

            return(pendingWork);
        }
        static void RegisterComponentTypes()
        {
            TypeManager.Initialize();

            AssetDatabaseCompatibility.UnregisterCustomDependencyPrefixFilter("DOTSType/");
            int typeCount = TypeManager.GetTypeCount();

            for (int i = 1; i < typeCount; ++i)
            {
                var typeInfo = TypeManager.GetTypeInfo(i);
                var hash     = typeInfo.StableTypeHash;
                AssetDatabaseCompatibility.RegisterCustomDependency(TypeString(typeInfo.Type),
                                                                    new UnityEngine.Hash128(hash, hash));
            }
        }
Exemplo n.º 12
0
    public static Hash128[] GetSubSceneGuids(string guid)
    {
        var hash = AssetDatabaseCompatibility.GetArtifactHash(guid, typeof(SceneMetaDataImporter), ImportMode.Synchronous);

        AssetDatabaseCompatibility.GetArtifactPaths(hash, out string[] paths);

        var metaPath = paths.First(o => o.EndsWith("scenemeta"));

        BlobAssetReference <SceneMetaData> sceneMetaDataRef;

        if (!BlobAssetReference <SceneMetaData> .TryRead(metaPath, SceneMetaDataImporter.CurrentFileFormatVersion, out sceneMetaDataRef))
        {
            return(new Hash128[0]);
        }

        Hash128[] guids = sceneMetaDataRef.Value.SubScenes.ToArray();
        sceneMetaDataRef.Dispose();
        return(guids);
    }
        static void AddEntityBinaryFiles(Hash128 buildConfigurationGuid, string[] scenePathsForBuild, EntitySectionBundlesInBuild sectionBundlesInBuild)
        {
            var subSceneGuids = scenePathsForBuild.SelectMany(scenePath => EditorEntityScenes.GetSubScenes(AssetDatabaseCompatibility.PathToGUID(scenePath))).Distinct().ToList();

            var requiresRefresh       = false;
            var sceneBuildConfigGuids = new NativeArray <GUID>(subSceneGuids.Count, Allocator.TempJob);

            for (int i = 0; i != sceneBuildConfigGuids.Length; i++)
            {
                sceneBuildConfigGuids[i] = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(subSceneGuids[i], buildConfigurationGuid, false, out var thisRequiresRefresh);
                requiresRefresh         |= thisRequiresRefresh;

                sectionBundlesInBuild.Add(subSceneGuids[i], sceneBuildConfigGuids[i], typeof(SubSceneImporter));
            }
            if (requiresRefresh)
            {
                AssetDatabase.Refresh();
            }

            AssetDatabaseCompatibility.ProduceArtifactsAsync(sceneBuildConfigGuids, typeof(SubSceneImporter));
            sceneBuildConfigGuids.Dispose();
        }
Exemplo n.º 14
0
        public static void RegisterMonoScripts()
        {
            if (AssetDatabaseCompatibility.IsAssetImportWorkerProcess() || s_Initialized)
            {
                return;
            }
            s_Initialized = true;

            AssetDatabaseCompatibility.UnregisterCustomDependencyPrefixFilter("UnityEngineType/");

            var behaviours = TypeCache.GetTypesDerivedFrom <UnityEngine.MonoBehaviour>();
            var scripts    = TypeCache.GetTypesDerivedFrom <UnityEngine.ScriptableObject>();

            for (int i = 0; i != behaviours.Count; i++)
            {
                var type = behaviours[i];
                if (type.IsGenericType)
                {
                    continue;
                }
                var hash = TypeHash.CalculateStableTypeHash(type);
                AssetDatabaseCompatibility.RegisterCustomDependency(TypeString(type),
                                                                    new UnityEngine.Hash128(hash, hash));
            }

            for (int i = 0; i != scripts.Count; i++)
            {
                var type = scripts[i];
                if (type.IsGenericType)
                {
                    continue;
                }
                var hash = TypeHash.CalculateStableTypeHash(type);
                AssetDatabaseCompatibility.RegisterCustomDependency(TypeString(type),
                                                                    new UnityEngine.Hash128(hash, hash));
            }
        }
        public NativeArray <Hash128> GetInitialScenes(int playerId, Allocator allocator)
        {
            var sceneList = _BuildConfiguration.GetComponent <SceneList>();
            var nonEmbeddedStartupScenes = new List <string>();

            foreach (var path in sceneList.GetScenePathsToLoad())
            {
                if (SceneImporterData.CanLiveLinkScene(path))
                {
                    nonEmbeddedStartupScenes.Add(path);
                }
            }

            if (nonEmbeddedStartupScenes.Count > 0)
            {
                var sceneIds = new NativeArray <Hash128>(nonEmbeddedStartupScenes.Count, allocator);
                for (int i = 0; i < nonEmbeddedStartupScenes.Count; i++)
                {
                    sceneIds[i] = AssetDatabaseCompatibility.PathToGUID(nonEmbeddedStartupScenes[i]);
                }
                return(sceneIds);
            }
            return(new NativeArray <Hash128>(0, allocator));
        }
        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}");
            }
        }
Exemplo n.º 17
0
        // This function is responsible for providing all the subscenes to the build.
        //
        // The way these files get generated is that we have a SceneWithBuildConfiguration file, (which is a bit of a hack to work around the inability for scriptable importers to take arguments, so
        // instead we create a different file that points to the scene we want to import, and points to the buildconfiguration we want to import it for).   The SubsceneImporter will import this file,
        // and it will make 3 (relevant) kind of files:
        // - headerfile
        // - entitybinaryformat file (the actual entities payloads)
        // - a SerializedFile that has an array of UnityEngine.Object PPtrs that are used by this entity file.
        //
        // The first two we deal with very simply: they just need to be copied into the build, and we're done.
        // the third one, we will feed as input to the Scriptable build pipeline (which is actually about creating assetbundles), and create an assetbundle that
        // has all those objects in it that the 3rd file referred to.  We do this with a batch api, first we loop through all subscenes, and register with this batch
        // api which assetbundles we'd like to see produced, and then at the end, we say "okay make them please".  this assetbundle creation api has a caching system
        // that is separate from the assetpipeline caching system, so if all goes well, the call to produce these assetbundles will return very fast and did nothing.
        //
        // The reason for the strange looking api, where a two callbacks get passed in is to make integration of the new incremental buildpipeline easier, as this code
        // needs to be compatible both with the current buildpipeline in the dots-repo, as well as with the incremental buildpipeline.  When that is merged, we can simplify this.
        public static void PrepareAdditionalFiles(string buildConfigurationGuid, string[] scenePathsForBuild, BuildTarget target, Action <string, string> RegisterFileCopy, string outputStreamingAssetsDirectory, string buildWorkingDirectory)
        {
            if (target == BuildTarget.NoTarget)
            {
                throw new InvalidOperationException($"Invalid build target '{target.ToString()}'.");
            }

            if (target != EditorUserBuildSettings.activeBuildTarget)
            {
                throw new InvalidOperationException($"ActiveBuildTarget must be switched before the {nameof(SubSceneBuildCode)} runs.");
            }

            var content             = new BundleBuildContent(new AssetBundleBuild[0]);
            var bundleNames         = new HashSet <string>();
            var subSceneGuids       = scenePathsForBuild.SelectMany(scenePath => SceneMetaDataImporter.GetSubSceneGuids(AssetDatabase.AssetPathToGUID(scenePath))).Distinct().ToList();
            var subScenePaths       = new Dictionary <Hash128, string>();
            var dependencyInputData = new Dictionary <SceneSection, SectionDependencyInfo>();
            var refExt    = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesUnityObjectReferences);
            var headerExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesHeader);
            var binaryExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesBinary);

            var group      = BuildPipeline.GetBuildTargetGroup(target);
            var parameters = new BundleBuildParameters(target, @group, buildWorkingDirectory)
            {
                BundleCompression = BuildCompression.LZ4Runtime
            };

            var requiresRefresh       = false;
            var sceneBuildConfigGuids = new NativeArray <GUID>(subSceneGuids.Count, Allocator.TempJob);

            for (int i = 0; i != sceneBuildConfigGuids.Length; i++)
            {
                sceneBuildConfigGuids[i] = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(subSceneGuids[i], new Hash128(buildConfigurationGuid), out var thisRequiresRefresh);
                requiresRefresh         |= thisRequiresRefresh;
            }
            if (requiresRefresh)
            {
                AssetDatabase.Refresh();
            }

            var artifactHashes = new NativeArray <UnityEngine.Hash128>(subSceneGuids.Count, Allocator.TempJob);

            AssetDatabaseCompatibility.ProduceArtifactsRefreshIfNecessary(sceneBuildConfigGuids, typeof(SubSceneImporter), artifactHashes);

            for (int i = 0; i != sceneBuildConfigGuids.Length; i++)
            {
                var sceneGuid            = subSceneGuids[i];
                var sceneBuildConfigGuid = sceneBuildConfigGuids[i];
                var artifactHash         = artifactHashes[i];

                bool foundEntityHeader = false;
                AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out var artifactPaths);
                foreach (var artifactPath in artifactPaths)
                {
                    //@TODO: This looks like a workaround. Whats going on here?
                    var ext = Path.GetExtension(artifactPath).Replace(".", "");
                    if (ext == headerExt)
                    {
                        foundEntityHeader = true;

                        if (!string.IsNullOrEmpty(artifactPaths.FirstOrDefault(a => a.EndsWith(refExt))))
                        {
                            subScenePaths[sceneGuid] = artifactPath;
                        }
                        else
                        {
                            //if there are no reference bundles, then deduplication can be skipped
                            var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesHeader, -1);
                            DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile);
                        }
                    }
                    else if (ext == binaryExt)
                    {
                        var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesBinary, EntityScenesPaths.GetSectionIndexFromPath(artifactPath));
                        DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile);
                    }

                    if (ext == refExt)
                    {
                        content.CustomAssets.Add(new CustomContent
                        {
                            Asset     = sceneBuildConfigGuid,
                            Processor = (guid, processor) =>
                            {
                                var sectionIndex = EntityScenesPaths.GetSectionIndexFromPath(artifactPath);
                                processor.GetObjectIdentifiersAndTypesForSerializedFile(artifactPath, out ObjectIdentifier[] objectIds, out Type[] types);
Exemplo n.º 18
0
 static bool GetMetaDataArtifactPath(Hash128 artifactHash, out string metaDataPath)
 {
     metaDataPath = default;
     if (!AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out string[] paths))
        // This function is responsible for providing all the subscenes to the build.
        //
        // The way these files get generated is that we have a SceneWithBuildConfiguration file, (which is a bit of a hack to work around the inability for scriptable importers to take arguments, so
        // instead we create a different file that points to the scene we want to import, and points to the buildconfiguration we want to import it for).   The SubsceneImporter will import this file,
        // and it will make 3 (relevant) kind of files:
        // - headerfile
        // - entitybinaryformat file (the actual entities payloads)
        // - a SerializedFile that has an array of UnityEngine.Object PPtrs that are used by this entity file.
        //
        // The first two we deal with very simply: they just need to be copied into the build, and we're done.
        // the third one, we will feed as input to the Scriptable build pipeline (which is actually about creating assetbundles), and create an assetbundle that
        // has all those objects in it that the 3rd file referred to.  We do this with a batch api, first we loop through all subscenes, and register with this batch
        // api which assetbundles we'd like to see produced, and then at the end, we say "okay make them please".  this assetbundle creation api has a caching system
        // that is separate from the assetpipeline caching system, so if all goes well, the call to produce these assetbundles will return very fast and did nothing.
        //
        // The reason for the strange looking api, where a two callbacks get passed in is to make integration of the new incremental buildpipeline easier, as this code
        // needs to be compatible both with the current buildpipeline in the dots-repo, as well as with the incremental buildpipeline.  When that is merged, we can simplify this.
        public static void PrepareAdditionalFiles(GUID[] sceneGuids, ArtifactKey[] entitySceneArtifacts, BuildTarget target, Action <string, string> RegisterFileCopy, string outputStreamingAssetsDirectory, string buildWorkingDirectory)
        {
            if (target == BuildTarget.NoTarget)
            {
                throw new InvalidOperationException($"Invalid build target '{target.ToString()}'.");
            }

            if (target != EditorUserBuildSettings.activeBuildTarget)
            {
                throw new InvalidOperationException($"ActiveBuildTarget must be switched before the {nameof(SubSceneBuildCode)} runs.");
            }

            Assert.AreEqual(sceneGuids.Length, entitySceneArtifacts.Length);

            var content             = new BundleBuildContent(new AssetBundleBuild[0]);
            var bundleNames         = new HashSet <string>();
            var subScenePaths       = new Dictionary <Hash128, string>();
            var dependencyInputData = new Dictionary <SceneSection, SectionDependencyInfo>();

            var    refExt    = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesUnityObjectReferences);
            var    headerExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesHeader);
            var    binaryExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesBinary);
            string conversionLogExtension = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesConversionLog);

            var group      = BuildPipeline.GetBuildTargetGroup(target);
            var parameters = new BundleBuildParameters(target, @group, buildWorkingDirectory)
            {
                BundleCompression = BuildCompression.LZ4Runtime
            };

            var artifactHashes = new UnityEngine.Hash128[entitySceneArtifacts.Length];

            AssetDatabaseCompatibility.ProduceArtifactsRefreshIfNecessary(entitySceneArtifacts, artifactHashes);

            for (int i = 0; i != entitySceneArtifacts.Length; i++)
            {
                var sceneGuid            = sceneGuids[i];
                var sceneBuildConfigGuid = entitySceneArtifacts[i].guid;
                var artifactHash         = artifactHashes[i];

                bool foundEntityHeader = false;

                if (!artifactHash.isValid)
                {
                    throw new Exception($"Building EntityScene artifact failed: '{AssetDatabaseCompatibility.GuidToPath(sceneGuid)}' ({sceneGuid}). There were exceptions during the entity scene imports.");
                }

                AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out var artifactPaths);

                foreach (var artifactPath in artifactPaths)
                {
                    //UnityEngine.Debug.Log($"guid: {sceneGuid} artifact: '{artifactPath}'");

                    //@TODO: This looks like a workaround. Whats going on here?
                    var ext = Path.GetExtension(artifactPath).Replace(".", "");

                    if (ext == conversionLogExtension)
                    {
                        var res = ConversionLogUtils.PrintConversionLogToUnityConsole(artifactPath);

                        if (res.HasException)
                        {
                            throw new Exception("Building entity scenes failed. There were exceptions during the entity scene imports.");
                        }
                    }
                    else if (ext == headerExt)
                    {
                        foundEntityHeader = true;

                        if (!string.IsNullOrEmpty(artifactPaths.FirstOrDefault(a => a.EndsWith(refExt))))
                        {
                            subScenePaths[sceneGuid] = artifactPath;
                        }
                        else
                        {
                            //if there are no reference bundles, then deduplication can be skipped
                            var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesHeader, -1);
                            DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile);
                        }
                    }
                    else if (ext == binaryExt)
                    {
                        var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesBinary, EntityScenesPaths.GetSectionIndexFromPath(artifactPath));
                        DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile);
                    }
                    else if (ext == refExt)
                    {
                        content.CustomAssets.Add(new CustomContent
                        {
                            Asset     = sceneBuildConfigGuid,
                            Processor = (guid, processor) =>
                            {
                                var sectionIndex = EntityScenesPaths.GetSectionIndexFromPath(artifactPath);
                                processor.GetObjectIdentifiersAndTypesForSerializedFile(artifactPath, out ObjectIdentifier[] objectIds, out Type[] types);
        public void Update(List <LiveLinkChangeSet> changeSets, NativeList <Hash128> loadScenes, NativeList <Hash128> unloadScenes, LiveLinkMode mode)
        {
            if (_LoadedScenes.Count == 0 && _SceneGUIDToLiveLink.Count == 0 && _RemovedScenes.Length == 0)
            {
                return;
            }

            // If build configuration changed, we need to trigger a full conversion
            if (_BuildConfigurationGUID != default)
            {
                var buildConfigurationDependencyHash = AssetDatabaseCompatibility.GetAssetDependencyHash(_BuildConfigurationGUID);
                if (_BuildConfigurationArtifactHash != buildConfigurationDependencyHash)
                {
                    _BuildConfigurationArtifactHash = buildConfigurationDependencyHash;
                    RequestCleanConversion();
                }
            }

            if (_PreviousGlobalDirtyID != GlobalDirtyID)
            {
                RequestCleanConversion();
                _PreviousGlobalDirtyID = GlobalDirtyID;
            }

            // By default all scenes need to have m_GameObjectSceneCullingMask, otherwise they won't show up in game view
            _GUIDToEditScene.Clear();
            for (int i = 0; i != EditorSceneManager.sceneCount; i++)
            {
                var scene     = EditorSceneManager.GetSceneAt(i);
                var sceneGUID = AssetDatabaseCompatibility.PathToGUID(scene.path);

                if (_LoadedScenes.Contains(sceneGUID))
                {
                    if (scene.isLoaded && sceneGUID != default(GUID))
                    {
                        _GUIDToEditScene.Add(sceneGUID, scene);
                    }
                }
            }

            foreach (var scene in _SceneGUIDToLiveLink)
            {
                if (!_GUIDToEditScene.ContainsKey(scene.Key))
                {
                    unloadScenes.Add(scene.Key);
                }
            }

            // Process scenes that are no longer loaded
            foreach (var scene in unloadScenes)
            {
                var liveLink = _SceneGUIDToLiveLink[scene];
                liveLink.Dispose();
                _SceneGUIDToLiveLink.Remove(scene);
                _SentLoadScenes.Remove(scene);
            }
            foreach (var scene in _RemovedScenes)
            {
                if (_SceneGUIDToLiveLink.TryGetValue(scene, out var liveLink))
                {
                    liveLink.Dispose();
                    _SceneGUIDToLiveLink.Remove(scene);
                }

                unloadScenes.Add(scene);
                _SentLoadScenes.Remove(scene);
            }
            _RemovedScenes.Clear();

            _SentLoadScenes.RemoveWhere(scene => !_LoadedScenes.Contains(scene));

            // Process all scenes that the player needs
            var conversionMode = LiveConversionSettings.Mode;

            foreach (var sceneGuid in _LoadedScenes)
            {
                var isLoaded = _GUIDToEditScene.TryGetValue(sceneGuid, out var scene);

                // We are editing with live link. Ensure it is active & up to date
                if (isLoaded)
                {
                    var liveLink = GetLiveLink(sceneGuid);

                    if (liveLink == null || liveLink.DidRequestUpdate())
                    {
                        AddLiveLinkChangeSet(ref liveLink, sceneGuid, changeSets, mode);
                    }
#if !UNITY_2020_2_OR_NEWER
                    else if (liveLink.LiveLinkDirtyID != GetSceneDirtyID(scene))
                    {
                        AddLiveLinkChangeSet(ref liveLink, sceneGuid, changeSets, mode);
                    }
#endif

#if UNITY_2020_2_OR_NEWER
                    if (conversionMode == LiveConversionSettings.ConversionMode.IncrementalConversionWithDebug)
                    {
                        if (liveLink != null && liveLink.DidRequestDebugConversion())
                        {
                            if (IsHotControlActive())
                            {
                                EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
                            }
                            else
                            {
                                liveLink.DebugIncrementalConversion();
                            }
                        }
                    }
#endif
                }
                else
                {
                    if (_SentLoadScenes.Add(sceneGuid))
                    {
                        loadScenes.Add(sceneGuid);
                    }
                }
            }
        }
Exemplo n.º 21
0
        public override BuildResult Run(BuildContext context)
        {
            var manifest               = context.BuildManifest;
            var rootAssembly           = context.GetComponentOrDefault <DotsRuntimeRootAssembly>();
            var buildScenes            = context.GetComponentOrDefault <SceneList>();
            var targetName             = rootAssembly.MakeBeeTargetName(context.BuildConfigurationName);
            var scenePaths             = buildScenes.GetScenePathsForBuild();
            var buildConfigurationGuid = context.BuildConfigurationAssetGUID;
            var dataDirectory          = WorldExport.GetOrCreateDataDirectoryFrom(rootAssembly.StagingDirectory.Combine(targetName));
            var logsDirectory          = WorldExport.GetOrCreateLogDirectoryFrom(targetName);

            var sceneGuids = scenePaths.SelectMany(scenePath =>
            {
                var guids = EditorEntityScenes.GetSubScenes(AssetDatabaseCompatibility.PathToGUID(scenePath)).ToList();
                guids.Add(AssetDatabaseCompatibility.PathToGUID(scenePath));
                return(guids);
            }).Distinct().ToList();

            //Save all unsaved scenes of the project first
            foreach (var guid in sceneGuids)
            {
                string scenePath = AssetDatabase.GUIDToAssetPath(guid.ToString());
                var    scene     = SceneManager.GetSceneByPath(scenePath);
                EditorSceneManager.SaveScene(scene);
            }

            var requiresRefresh       = false;
            var sceneBuildConfigGuids = new NativeArray <GUID>(sceneGuids.Count, Allocator.TempJob);

            for (int i = 0; i != sceneBuildConfigGuids.Length; i++)
            {
                sceneBuildConfigGuids[i] = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(sceneGuids[i], new Hash128(buildConfigurationGuid), false, out var thisRequiresRefresh);
                requiresRefresh         |= thisRequiresRefresh;
            }
            if (requiresRefresh)
            {
                AssetDatabase.Refresh();
            }

            var artifactHashes = new NativeArray <UnityEngine.Hash128>(sceneGuids.Count, Allocator.TempJob);

            AssetDatabaseCompatibility.ProduceArtifactsRefreshIfNecessary(sceneBuildConfigGuids, typeof(SubSceneImporter), artifactHashes);

            bool succeeded = true;

            for (int i = 0; i != sceneBuildConfigGuids.Length; i++)
            {
                var sceneGuid    = sceneGuids[i];
                var artifactHash = artifactHashes[i];

                AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out var artifactPaths);

                List <FileInfo> exportedFiles     = new List <FileInfo>();
                bool            foundEntityHeader = false;
                foreach (var artifactPath in artifactPaths)
                {
                    var ext = Path.GetExtension(artifactPath).ToLower().Replace(".", "");
                    if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesHeader))
                    {
                        foundEntityHeader = true;
                        var destinationFile = dataDirectory.FullName + Path.DirectorySeparatorChar + EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesHeader, -1);
                        new NPath(artifactPath).MakeAbsolute().Copy(new NPath(destinationFile).MakeAbsolute().EnsureParentDirectoryExists());
                        exportedFiles.Add(new FileInfo(destinationFile));
                    }
                    else if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesBinary))
                    {
                        var destinationFile = dataDirectory.FullName + Path.DirectorySeparatorChar + EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesBinary, EntityScenesPaths.GetSectionIndexFromPath(artifactPath));
                        new NPath(artifactPath).MakeAbsolute().Copy(new NPath(destinationFile).MakeAbsolute().EnsureParentDirectoryExists());
                        exportedFiles.Add(new FileInfo(destinationFile));
                    }
                    else if (ext == EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesConversionLog))
                    {
                        var destinationFile = logsDirectory.FullName + Path.DirectorySeparatorChar + $"{sceneGuid}.{EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesConversionLog)}";
                        new NPath(artifactPath).MakeAbsolute().Copy(new NPath(destinationFile).MakeAbsolute().EnsureParentDirectoryExists());
                        var result = PrintConversionLogToUnityConsole(artifactPath);
                        if (result.HasError || result.HasException)
                        {
                            UnityEngine.Debug.LogError("Failed to export scene: " + Path.GetFileName(AssetDatabase.GUIDToAssetPath(sceneGuid.ToString())));
                            succeeded = false;
                        }
                    }
                    else if (new Hash128(ext).IsValid) //Asset files are exported as {artifactHash}.{assetguid}
                    {
                        var destinationFile = dataDirectory.FullName + Path.DirectorySeparatorChar + ext;
                        new NPath(artifactPath).MakeAbsolute().Copy(new NPath(destinationFile).MakeAbsolute().EnsureParentDirectoryExists());
                        exportedFiles.Add(new FileInfo(destinationFile));
                    }
                }

                if (!foundEntityHeader)
                {
                    Debug.LogError($"Failed to build EntityScene for '{AssetDatabaseCompatibility.GuidToPath(sceneGuid)}'.");
                    succeeded = false;
                }

                //UpdateManifest
                manifest.Add(new Guid(sceneGuid.ToString()), AssetDatabase.GUIDToAssetPath(sceneGuid.ToString()), exportedFiles);
            }

            var catalogPath = Path.Combine(dataDirectory.ToString(), SceneSystem.k_SceneInfoFileName);

            WriteCatalogFile(catalogPath, buildScenes);
            manifest.AddAdditionalFilesToDeploy(new FileInfo(catalogPath.ToString()));

            sceneBuildConfigGuids.Dispose();
            artifactHashes.Dispose();

            if (succeeded)
            {
                return(context.Success());
            }
            return(context.Failure($"Failed to export scenes"));
        }