/// <summary> /// Initializes a new instance of the <see cref="BuildDependencyInfo"/> structure. /// </summary> /// <param name="assetType">The type of asset targeted by this dependency info.</param> /// <param name="compilationContext">The compilation context in which to compile the target asset.</param> /// <param name="dependencyType">The type of dependency.</param> public BuildDependencyInfo(Type assetType, Type compilationContext, BuildDependencyType dependencyType) { if (!typeof(Asset).IsAssignableFrom(assetType)) { throw new ArgumentException($@"{nameof(assetType)} should inherit from Asset", nameof(assetType)); } if (!typeof(ICompilationContext).IsAssignableFrom(compilationContext)) { throw new ArgumentException($@"{nameof(compilationContext)} should inherit from ICompilationContext", nameof(compilationContext)); } AssetType = assetType; CompilationContext = compilationContext; DependencyType = dependencyType; }
public async Task Build(AssetItem asset, BuildDependencyType dependencyType = BuildDependencyType.Runtime) { if (isDisposed) { throw new ObjectDisposedException(nameof(GameStudioDatabase)); } var buildUnit = new EditorGameBuildUnit(asset, CompilerContext, AssetDependenciesCompiler); try { assetBuilderService.PushBuildUnit(buildUnit); await buildUnit.Wait(); } catch (Exception e) { Logger?.Error($"An error occurred while building the scene: {e.Message}", e); return; } // Merge build result into the database using ((await databaseLock.ReserveSyncLock()).Lock()) { if (isDisposed) { return; } if (buildUnit.Failed) { // Build failed => unregister object // 1. If it is first-time scene loading and one of sub-asset failed, it will be in this state, but we don't care // since database will be empty at that point (it won't have any effect) // 2. The second case (the one we actually care about) happens when reloading a recently rebuilt individual asset (i.e. material or texture), // this will actually remove it from database database.Remove(new ObjectUrl(UrlType.Content, asset.Location)); } foreach (var outputObject in buildUnit.OutputObjects) { database[outputObject.Key] = outputObject.Value; } } }
/// <summary> /// Indicates whether this <see cref="BuildAssetLink"/> has at all dependencies of the given flags. /// </summary> /// <param name="type">A bitset of <see cref="BuildDependencyType"/>.</param> /// <returns>True if it has all the given dependencies, false otherwise.</returns> public bool HasAll(BuildDependencyType type) { return((DependencyType & type) == type); }
/// <summary> /// Indicates whether this <see cref="BuildAssetLink"/> has at least one of the dependency of the given flags. /// </summary> /// <param name="type">A bitset of <see cref="BuildDependencyType"/>.</param> /// <returns>True if it has at least one of the given dependencies, false otherwise.</returns> public bool HasOne(BuildDependencyType type) { return((DependencyType & type) != 0); }
/// <summary> /// Initialize a new instance of the <see cref="BuildAssetLink"/> structure. /// </summary> /// <param name="source">The source asset of the dependency.</param> /// <param name="target">The target asset of the dependency.</param> /// <param name="dependencyType">The type of dependency.</param> public BuildAssetLink(BuildAssetNode source, BuildAssetNode target, BuildDependencyType dependencyType) { Source = source; Target = target; DependencyType = dependencyType; }
private void Prepare(AssetCompilerResult finalResult, AssetCompilerContext context, AssetItem assetItem, [NotNull] Type compilationContext, HashSet <BuildAssetNode> visitedItems, Dictionary <AssetId, BuildStep> compiledItems, BuildStep parentBuildStep = null, BuildDependencyType dependencyType = BuildDependencyType.Runtime) { if (compilationContext == null) { throw new ArgumentNullException(nameof(compilationContext)); } var assetNode = BuildDependencyManager.FindOrCreateNode(assetItem, compilationContext); compiledItems.TryGetValue(assetNode.AssetItem.Id, out var assetBuildSteps); // Prevent re-entrancy in the same node if (visitedItems.Add(assetNode)) { assetNode.Analyze(context); // Invoke the compiler to prepare the build step for this asset if the dependency needs to compile it (Runtime or CompileContent) if ((dependencyType & ~BuildDependencyType.CompileAsset) != 0 && assetBuildSteps == null) { var mainCompiler = BuildDependencyManager.AssetCompilerRegistry.GetCompiler(assetItem.Asset.GetType(), assetNode.CompilationContext); if (mainCompiler == null) { return; } var compilerResult = mainCompiler.Prepare(context, assetItem); if ((dependencyType & BuildDependencyType.Runtime) == BuildDependencyType.Runtime && compilerResult.HasErrors) //allow Runtime dependencies to fail { //totally skip this asset but do not propagate errors! return; } assetBuildSteps = compilerResult.BuildSteps; compiledItems.Add(assetNode.AssetItem.Id, assetBuildSteps); // Copy the log to the final result (note: this does not copy or forward the build steps) compilerResult.CopyTo(finalResult); if (compilerResult.HasErrors) { finalResult.Error($"Failed to prepare asset {assetItem.Location}"); return; } // Add the resulting build steps to the final finalResult.BuildSteps.Add(assetBuildSteps); AssetCompiled?.Invoke(this, new AssetCompiledArgs(assetItem, compilerResult)); } // Go through the dependencies of the node and prepare them as well foreach (var reference in assetNode.References) { var target = reference.Target; Prepare(finalResult, context, target.AssetItem, target.CompilationContext, visitedItems, compiledItems, assetBuildSteps, reference.DependencyType); if (finalResult.HasErrors) { return; } } // If we didn't prepare any build step for this asset let's exit here. if (assetBuildSteps == null) { return; } } // Link the created build steps to their parent step. if (parentBuildStep != null && assetBuildSteps != null && (dependencyType & BuildDependencyType.CompileContent) == BuildDependencyType.CompileContent) //only if content is required Content.Load { BuildStep.LinkBuildSteps(assetBuildSteps, parentBuildStep); } }