using System; using System.Diagnostics.CodeAnalysis; using System.IO; namespace ADOFAIRenderer.API; /// /// Represents the result and metadata of a completed or canceled render session. /// /// /// Passed to the completion callback registered with . Immutable. /// [SuppressMessage("ReSharper", "UnusedType.Global")] [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public class RenderResult { /// /// Indicates whether the rendering session completed successfully. /// public bool Success { get; } /// /// The output path of the rendered video file: the path given to as passed /// (relative if it was relative), or the path of the time-stamped file in the output directory chosen in the mod /// settings (by default <game root>/Render). /// Empty string if rendering failed or was cancelled (the unfinished file is deleted). /// public string OutputPath { get; } /// /// Total number of video frames sent to the encoder. /// public long TotalFrames { get; } /// /// The calculated video duration in seconds: divided by the effective video frame rate /// (min of the configured VideoFPS and RenderFPS); 0 when the frame rate is not positive. /// public double VideoDuration { get; } /// /// Total wall-clock time spent rendering, from the end of the countdown (start of capture) to the end of the render. /// public TimeSpan RenderDuration { get; } /// /// File size of the output video in bytes (0 if failed or file does not exist). /// public long FileSizeBytes { get; } /// /// Error message or reason if rendering failed or was canceled; null on success. /// A cancelled render has "Rendering was cancelled by user."; a failed render has "Rendering failed: " followed by /// the reason. Use to test the outcome; the texts are meant for display. /// public string? ErrorMessage { get; } /// /// Initializes a new instance of the class. /// /// Whether the render session completed successfully. /// The absolute output path of the rendered video file. /// Total number of video frames sent to the encoder. /// Calculated video duration in seconds. /// Total wall-clock time spent rendering. /// File size of the output video in bytes. /// Error message or reason if failed or canceled; otherwise, null. public RenderResult( bool success, string outputPath, long totalFrames, double videoDuration, TimeSpan renderDuration, long fileSizeBytes = 0, string? errorMessage = null) { Success = success; OutputPath = outputPath; TotalFrames = totalFrames; VideoDuration = videoDuration; RenderDuration = renderDuration; FileSizeBytes = fileSizeBytes; ErrorMessage = errorMessage; } /// /// Creates a successful instance from the specified render metrics. /// /// The path to the rendered video file. /// Total number of video frames sent to the encoder. /// The effective frames per second used to compute video duration. /// Total wall-clock time spent rendering. /// A new representing a successful render session. /// The file size is read from disk; it is 0 when the file does not exist or cannot be read. internal static RenderResult CreateSuccess(string outputPath, long totalFrames, double fps, TimeSpan renderDuration) { var fileSizeBytes = 0L; if (!string.IsNullOrEmpty(outputPath) && File.Exists(outputPath)) { try { fileSizeBytes = new FileInfo(outputPath).Length; } catch { /* ignored */ } } var videoDuration = fps > 0 ? totalFrames / fps : 0.0; return new RenderResult(true, outputPath, totalFrames, videoDuration, renderDuration, fileSizeBytes); } /// /// Creates a failed or cancelled instance. /// /// Error message or reason for failure/cancellation. /// Total number of video frames sent to the encoder prior to termination. /// The effective frames per second used to compute video duration. /// Total wall-clock time spent rendering prior to termination. /// A new representing a failed or canceled render session. /// OutputPath is empty and FileSizeBytes is 0. A null message is replaced by a generic one. internal static RenderResult CreateFailure(string? errorMessage, long totalFrames, double fps, TimeSpan renderDuration) { var videoDuration = fps > 0 ? totalFrames / fps : 0.0; return new RenderResult(false, string.Empty, totalFrames, videoDuration, renderDuration, 0, errorMessage ?? "Rendering failed or was cancelled."); } /// /// Returns a string summarizing the render result metrics or failure reason. /// /// A string representation of the . public override string ToString() { return Success ? $"[RenderResult: Success, Output={OutputPath}, Frames={TotalFrames}, VideoDuration={VideoDuration:F2}s, Time={RenderDuration.TotalSeconds:F1}s, Size={FileSizeBytes / 1024.0 / 1024.0:F2}MB]" : $"[RenderResult: Failed/Cancelled, Error={ErrorMessage ?? "Unknown"}]"; } }