public static void PrepareDeployment(InvocationParams config, string filePath, string filterPath, out IFileDeployment outDeployment) { outDeployment = null; // Prepare for what there is to come: var inputFile = new FileInfo(filePath); if (!inputFile.Exists) { throw new FileNotFoundException($"File '{filePath}' does not exist"); } // There are two special filter paths: "assets" and "shaders". // Files under both filter paths are copied to the output directory, but // only those under "shaders" are possibly compiled to SPIR-V (in case // of building against Vulkan) or their GLSL code might be modified (in // case of building against OpenGL) // // All in all, we have the following special cases: // #1: If it is a shader file and we're building for Vulkan => compile to SPIR-V // #2: If it is a shader file and we're building for OpenGL => modify GLSL // #3: If it is an .obj 3D Model file => get its materials file var isExternalDependency = CgbUtils.NormalizePath(inputFile.FullName).Contains(CgbUtils.NormalizePath(config.CgbExternalPath)); var isAsset = RegexIsInAssets.IsMatch(filterPath); var isShader = RegexIsInShaders.IsMatch(filterPath); if (!isAsset && !isShader && !isExternalDependency) { Trace.TraceInformation($"Skipping '{filePath}' since it is neither in 'assets/' nor in 'shaders/' nor is it an external dependency."); return; } // Ensure we have no coding errors for the following cases: Diag.Debug.Assert(isAsset != isShader || isExternalDependency); // Construct the deployment and DO IT... JUST DO IT IFileDeployment deploy = null; Action <IFileDeployment> additionalInitAction = null; if (isShader) { if (config.TargetApi == BuildTargetApi.Vulkan) { // It's a shader and we're building for Vulkan => Special case #1 deploy = new VkShaderDeployment(); } else { Diag.Debug.Assert(config.TargetApi == BuildTargetApi.OpenGL); // It's a shader and we're building for OpenGL => Special case #2 deploy = new GlShaderDeployment(); } } else // is an asset { // Is it a model? try { using (AssimpContext importer = new AssimpContext()) { var model = importer.ImportFile(inputFile.FullName); var allTextures = new HashSet <string>(); foreach (var m in model.Materials) { if (m.HasTextureAmbient) { allTextures.Add(m.TextureAmbient.FilePath); } if (m.HasTextureDiffuse) { allTextures.Add(m.TextureDiffuse.FilePath); } if (m.HasTextureDisplacement) { allTextures.Add(m.TextureDisplacement.FilePath); } if (m.HasTextureEmissive) { allTextures.Add(m.TextureEmissive.FilePath); } if (m.HasTextureHeight) { allTextures.Add(m.TextureHeight.FilePath); } if (m.HasTextureLightMap) { allTextures.Add(m.TextureLightMap.FilePath); } if (m.HasTextureNormal) { allTextures.Add(m.TextureNormal.FilePath); } if (m.HasTextureOpacity) { allTextures.Add(m.TextureOpacity.FilePath); } if (m.HasTextureReflection) { allTextures.Add(m.TextureReflection.FilePath); } if (m.HasTextureSpecular) { allTextures.Add(m.TextureSpecular.FilePath); } } if (inputFile.FullName.Trim().EndsWith(".obj", true, System.Globalization.CultureInfo.InvariantCulture)) { deploy = new ObjModelDeployment(); } else { deploy = new ModelDeployment(); } additionalInitAction = (theDeployment) => { ((ModelDeployment)theDeployment).SetTextures(allTextures); }; } } catch (AssimpException aex) { Trace.TraceWarning(aex.Message); // Maybe it is no model?! } if (null == deploy) { deploy = new CopyFileDeployment(); } } deploy.SetInputParameters( config, filterPath, inputFile, Path.Combine(config.OutputPath, filterPath, inputFile.Name)); additionalInitAction?.Invoke(deploy); // We're done here => return the deployment-instance to the caller outDeployment = deploy; }
/// <summary> /// Handles ONE file deployment /// </summary> /// <param name="config">The build's config parameters</param> /// <param name="filePath">Path to the input file</param> /// <param name="filterPath">Associated filter path of the file</param> /// <param name="modDeployments">List of deployments; this will be modified, i.e. a deployment will be added to this list in the success-case</param> /// <param name="modFileDeployments">List of FILE deployments; this will be modified. A deployment can affect multiple files, which are all added to this list in the success-case.</param> /// <param name="modWindowsToShowFor">List of single file deployments which an emergency-window has to be opened for; this will be modified.</param> public void HandleFileToDeploy( InvocationParams config, string filePath, string filterPath, IList<IFileDeployment> modDeployments, IList<FileDeploymentData> modFileDeployments, IList<FileDeploymentData> modWindowsToShowFor, bool doNotOverwriteExisting = false) { IFileDeployment savedForUseInException = null; try { lock (_namedPipeSync) { _applicationStatus = $"Deploying files from '{new FileInfo(config.VcxprojPath).Name}' (currently working on '{new FileInfo(filePath).Name}')..."; } savedForUseInException = null; CgbUtils.PrepareDeployment( config, filePath, filterPath, out var deployment); // It can be null, if it is not an asset/shader that should be deployed if (null == deployment) { return; } savedForUseInException = deployment; // Do it! if (doNotOverwriteExisting) { // ...unless we shouldn't do it! if (File.Exists(deployment.DesignatedOutputPath)) { Trace.TraceInformation($"Not deploying file to '{deployment.DesignatedOutputPath}' because it already exists (and don't overwrite flag is set)."); return; } } // Before deploying, check for conflicts and try to resolve them (which actually is only implemented for Models) bool repeatChecks; var deploymentBase = (DeploymentBase)deployment; var deploymentModel = deployment as ModelDeployment; var deploymentsToIssueWarningsFor = new HashSet<DeploymentBase>(); do { repeatChecks = false; foreach (var otherDeployment in modDeployments) { var otherDeploymentBase = (DeploymentBase)otherDeployment; if (deploymentBase.HasConflictWith(otherDeploymentBase)) { if (null != deploymentModel && otherDeployment is ModelDeployment otherDeploymentModel) { deploymentModel.ResolveConflictByMovingThisToSubfolder(); repeatChecks = true; break; } else { deploymentsToIssueWarningsFor.Add(otherDeploymentBase); } } } } while (repeatChecks); // Do we have to show any warnings? if (deploymentsToIssueWarningsFor.Count > 0) { foreach (var otherDeploymentBase in deploymentsToIssueWarningsFor) { AddToMessagesList(Message.Create(MessageType.Warning, $"File '{deploymentBase.InputFilePath}' has an unresolvable conflict with file '{otherDeploymentBase.InputFilePath}'.", null, deploymentBase.InputFilePath) /* TODO: ADD INSTANCE HERE */); } ShowMessagesList(); } // And, before deploying, try to optimize! foreach (var otherDeployment in modDeployments) { System.Diagnostics.Debug.Assert(deployment != otherDeployment); var otherDeploymentBase = (DeploymentBase)otherDeployment; if (null != deploymentModel && otherDeployment is ModelDeployment otherDeploymentModel) { deploymentModel.KickOutAllTexturesWhichAreAvailableInOther(otherDeploymentModel); } } deployment.Deploy(); foreach (var deployedFile in deployment.FilesDeployed) { // For the current files list: modFileDeployments.Add(deployedFile); var deploymentHasErrors = deployedFile.Messages.ContainsMessagesOfType(MessageType.Error); var deploymentHasWarnings = deployedFile.Messages.ContainsMessagesOfType(MessageType.Warning); // Show errors/warnings in window immediately IF this behavior has been opted-in via our settings if (deploymentHasWarnings || deploymentHasErrors) { if ((CgbPostBuildHelper.Properties.Settings.Default.ShowWindowForVkShaderDeployment && deployment is Deployers.VkShaderDeployment) || (CgbPostBuildHelper.Properties.Settings.Default.ShowWindowForGlShaderDeployment && deployment is Deployers.GlShaderDeployment) || (CgbPostBuildHelper.Properties.Settings.Default.ShowWindowForModelDeployment && deployment is Deployers.ModelDeployment)) { modWindowsToShowFor.Add(deployedFile); } } } modDeployments.Add(deployment); } catch (UnauthorizedAccessException uaex) { if (uaex.Message.IndexOf(".dll", StringComparison.InvariantCultureIgnoreCase) >= 0 && null != savedForUseInException && 0 != savedForUseInException.FilesDeployed.Count && CgbPostBuildHelper.Properties.Settings.Default.HideAccessDeniedErrorsForDlls) { savedForUseInException.FilesDeployed.Last().Messages.Add(Message.Create(MessageType.Information, uaex.Message, null)); foreach (var deployedFile in savedForUseInException.FilesDeployed) { modFileDeployments.Add(deployedFile); } modDeployments.Add(savedForUseInException); } else { AddToMessagesList(Message.Create(MessageType.Error, uaex.Message, null), config); // TODO: Window with more info? ShowMessagesList(); } } catch (Exception ex) { AddToMessagesList(Message.Create(MessageType.Error, ex.Message, null), config); // TODO: Window with more info? ShowMessagesList(); } }