// Attempts to load the settings used in the last build to see if the output settings have changed // Returns true if the settings have changed (need to redo the packing process) // This checks for things like if the output directory or packing settings have changed // Also check if the compression changed but might not be caught by the content items, which can // happen when switching around intermediate and output roots in a specific way private bool CheckOutputChanged() { var packPath = PackingProcess.GetPackPath(Project.Paths.OutputRoot); if (!File.Exists(packPath)) { return(true); } try { using (var reader = new BinaryReader(File.Open(packPath, FileMode.Open, FileAccess.Read, FileShare.None))) { byte flags = reader.ReadBytes(6)[5]; // 6-byte header, last byte is build flags bool rel = (flags & 0x01) > 0; bool compress = (flags & 0x02) > 0; uint packSize = reader.ReadUInt32(); return((Engine.IsRelease != rel) || (compress != Engine.Compress) || (Project.Properties.PackSize != packSize)); } } catch { return(true); } }
// The pipeline control function for build tasks that runs on the separate build thread public void Build(bool rebuild) { Busy = true; ShouldStop = false; _isCleaning = false; Stopwatch timer = Stopwatch.StartNew(); bool success = false; try { Engine.Logger.BuildStart(rebuild, Engine.IsRelease); // Reset the item enumerator to the beginning _itemEnumerator = Project.Items.GetEnumerator(); _itemIndex = 0; // Ensure that the intermediate, output, and temp directories exist if (!Directory.Exists(Project.Paths.IntermediateRoot)) { Directory.CreateDirectory(Project.Paths.IntermediateRoot); } if (!Directory.Exists(Project.Paths.OutputRoot)) { Directory.CreateDirectory(Project.Paths.OutputRoot); } if (Directory.Exists(TempFilePath)) { Directory.Delete(TempFilePath, true); } Directory.CreateDirectory(TempFilePath); // Launch the build tasks foreach (var task in _tasks) { task.Start(rebuild); } // Wait for the tasks to complete foreach (var task in _tasks) { task.Join(); } // Clean up the temp files Directory.Delete(TempFilePath, true); // Check for exit request before moving on if (ShouldStop) { return; } // Clean up, lots of temp items probably hanging around at this point GC.Collect(); // Fail out if any items failed if (_tasks.Any(task => task.Results.FailCount > 0)) { Engine.Logger.EngineError("One or more items failed to build, skipping content output step."); return; } // Check if the output settings have changed bool outChanged = CheckOutputChanged(); // Test if we can skip output, otherwise report if (_tasks.All(task => task.Results.PassCount == task.Results.SkipCount)) { if (!outChanged) { Engine.Logger.EngineInfo($"Skipping content output step, no items were rebuilt.", true); success = true; return; } else { Engine.Logger.EngineInfo($"No items were rebuilt, but the output settings have changed.", true); } } Engine.Logger.BuildContinue(timer.Elapsed); // Create the output process and build the metadata var outProc = new PackingProcess(this, _tasks); if (!outProc.BuildContentPack()) { return; } // One last exit check before starting the output process if (ShouldStop) { return; } // Perform the final output steps (will check for cancellation) success = outProc.ProcessOutput(outChanged); } finally { Busy = false; Engine.Logger.BuildEnd(success, timer.Elapsed, ShouldStop); } }