diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 18e7db34..330bb137 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -10,7 +10,7 @@ true Assets\Images\logo.ico BetterGI - 10.38.6 + 10.38.7 x64 embedded diff --git a/BetterGenshinImpact/Core/Recorder/GlobalKeyMouseRecord.cs b/BetterGenshinImpact/Core/Recorder/GlobalKeyMouseRecord.cs index fa911db3..26e6cf4b 100644 --- a/BetterGenshinImpact/Core/Recorder/GlobalKeyMouseRecord.cs +++ b/BetterGenshinImpact/Core/Recorder/GlobalKeyMouseRecord.cs @@ -14,6 +14,7 @@ using System.Threading.Tasks; using System.Windows.Forms; using BetterGenshinImpact.Core.Config; using BetterGenshinImpact.Core.Video; +using BetterGenshinImpact.Core.Video.obs; using NAudio.Wave; using SharpAvi; using Vanara.PInvoke; @@ -82,6 +83,7 @@ public class GlobalKeyMouseRecord : Singleton _videoRecorder = VideoRecorderFactory.Create(TaskContext.Instance().Config.CommonConfig.Recorder, fileName); _directInputMonitor = new DirectInputMonitor(); + var recorderTmp = new KeyMouseRecorderJsonLine(fileName); // TaskTriggerDispatcher.Instance().StopTimer(); @@ -98,10 +100,26 @@ public class GlobalKeyMouseRecord : Singleton } - var videoEnabled = _videoRecorder.Start(); - + var tmpTime = DateTime.Now; + + var sw = new Stopwatch(); + sw.Start(); + long current; + + _directInputMonitor.Start(); - _recorder = new KeyMouseRecorderJsonLine(fileName); + _logger.LogInformation("从开始到directInput启动累计耗时ms:{Text}", sw.ElapsedMilliseconds); + + var videoEnabled = _videoRecorder.Start(); + _logger.LogInformation("从开始到视频录制启动累计耗时(OBS是WS通知完成耗时,并非实际录制时间)ms:{Text}", sw.ElapsedMilliseconds); + + _recorder = recorderTmp.Start(); + _recorder.AppendStartInfo(); + _logger.LogInformation("从开始到键鼠录制启动累计耗时ms:{Text}", sw.ElapsedMilliseconds); + + sw.Stop(); + + ObsLogFileProcessor.FindStartTime(fileName, tmpTime); Status = KeyMouseRecorderStatus.Recording; @@ -115,13 +133,18 @@ public class GlobalKeyMouseRecord : Singleton throw new InvalidOperationException("未处于录制中状态,无法停止"); } + var sw = new Stopwatch(); + sw.Start(); // var macro = _recorder?.ToJsonMacro() ?? string.Empty; _recorder = null; _directInputMonitor?.Stop(); _directInputMonitor?.Dispose(); _directInputMonitor = null; + _logger.LogInformation("从结束触发到键鼠录制关闭累计耗时ms:{Text}", sw.ElapsedMilliseconds); _videoRecorder?.Stop(); + _logger.LogInformation("从结束触发到视频录制关闭累计耗时ms:{Text}", sw.ElapsedMilliseconds); + if (_timer.Enabled) { @@ -182,7 +205,6 @@ public class GlobalKeyMouseRecord : Singleton public void GlobalHookKeyUp(KeyEventArgsExt e) { - if (_keyDownState.TryGetValue(e.KeyCode, out bool state) && state) { // Debug.WriteLine($"KeyUp: {e.KeyCode}"); diff --git a/BetterGenshinImpact/Core/Recorder/KeyMouseRecorderJsonLine.cs b/BetterGenshinImpact/Core/Recorder/KeyMouseRecorderJsonLine.cs index f2d5889b..6b81c199 100644 --- a/BetterGenshinImpact/Core/Recorder/KeyMouseRecorderJsonLine.cs +++ b/BetterGenshinImpact/Core/Recorder/KeyMouseRecorderJsonLine.cs @@ -42,11 +42,12 @@ public class KeyMouseRecorderJsonLine DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; + string _path; + public KeyMouseRecorderJsonLine(string folderName) { - var path = Global.Absolute($@"User\KeyMouseScript\{folderName}\"); + _path = Global.Absolute($@"User\KeyMouseScript\{folderName}\"); - DateTime startTime = DateTime.Now; // var bootTime = EnvironmentUtil.LastBootUpTime(); // if (bootTime == null) // { @@ -65,14 +66,28 @@ public class KeyMouseRecorderJsonLine Width = rect.Width, Height = rect.Height, RecordDpi = TaskContext.Instance().DpiScale, - StartTime = $"{startTime:yyyy-MM-dd HH:mm:ss:ffff}", - StartTimeUnixTimestamp = (startTime.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalNanoseconds.ToString("F0"), - SysParams = RecordContext.Instance.SysParams + SysParams = RecordContext.Instance.SysParams }; - var infoJson = JsonSerializer.Serialize(Info, JsonOptions); - File.WriteAllText(Path.Combine(path, $"systemInfo.json"), infoJson); - _consumerTask = Task.Run(async () => await ConsumeEventsAsync(path)); + _consumerTask = Task.Run(async () => await ConsumeEventsAsync(_path)); + } + + public KeyMouseRecorderJsonLine Start() + { + StartTick = Kernel32.GetTickCount(); + return this; + } + + public void AppendStartInfo() + { + Task.Run(() => + { + DateTime startTime = DateTime.Now; + Info.StartTime = $"{startTime:yyyy-MM-dd HH:mm:ss:ffff}"; + Info.StartTimeUnixTimestamp = (startTime.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalNanoseconds.ToString("F0"); + var infoJson = JsonSerializer.Serialize(Info, JsonOptions); + File.WriteAllText(Path.Combine(_path, $"systemInfo.json"), infoJson); + }); } private async Task ConsumeEventsAsync(string path) diff --git a/BetterGenshinImpact/Core/Video/ObsRecorder.cs b/BetterGenshinImpact/Core/Video/ObsRecorder.cs index 433753cb..c1e7dbbb 100644 --- a/BetterGenshinImpact/Core/Video/ObsRecorder.cs +++ b/BetterGenshinImpact/Core/Video/ObsRecorder.cs @@ -106,7 +106,7 @@ public class ObsRecorder : IVideoRecorder { obs.StartRecord(); _lastRecordTime = DateTime.Now; - TaskControl.Logger.LogInformation("OBS: 开始录制,时间: {Time}", _lastRecordTime.ToString("yyyy-MM-dd HH:mm:ss:ffff")); + TaskControl.Logger.LogInformation("OBS: ws请求开始录制,时间: {Time}", _lastRecordTime.ToString("yyyy-MM-dd HH:mm:ss.ffff")); return true; } catch (ErrorResponseException ex) @@ -118,7 +118,7 @@ public class ObsRecorder : IVideoRecorder } else { - TaskControl.Logger.LogError($"OBS: 开始录制失败: {ex.Message}"); + TaskControl.Logger.LogError($"OBS: ws请求开始录制失败: {ex.Message}"); throw; } } @@ -187,7 +187,7 @@ public class ObsRecorder : IVideoRecorder TaskControl.Logger.LogError("OBS: 未找到录制结果文件"); } - File.WriteAllText(Path.Combine(folderPath, "videoStartTime.txt"), (_lastRecordTime.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalNanoseconds.ToString("F0")); + // File.WriteAllText(Path.Combine(folderPath, "videoStartTime.txt"), (_lastRecordTime.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalNanoseconds.ToString("F0")); } catch (Exception e) { diff --git a/BetterGenshinImpact/Core/Video/obs/ObsLogFileProcessor.cs b/BetterGenshinImpact/Core/Video/obs/ObsLogFileProcessor.cs new file mode 100644 index 00000000..a39baf07 --- /dev/null +++ b/BetterGenshinImpact/Core/Video/obs/ObsLogFileProcessor.cs @@ -0,0 +1,133 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.GameTask.Common; +using Microsoft.Extensions.Logging; + +namespace BetterGenshinImpact.Core.Video.obs; + +public class ObsLogFileProcessor +{ + private static readonly string ObsLogPath = Global.Absolute(@"video\bin\OBS-Studio-31.0.0-Windows\config\obs-studio\logs"); + + public static FileInfo? GetLogFilePath() + { + // 找到目录中最新的日志文件 + if (!Directory.Exists(ObsLogPath)) + { + TaskControl.Logger.LogError("OBS日志目录不存在"); + return null; + } + + var files = Directory.GetFiles(ObsLogPath, "*.txt"); + if (files.Length == 0) + { + TaskControl.Logger.LogError("OBS日志文件不存在"); + return null; + } + + FileInfo? latestFile = null; + foreach (var file in files) + { + var fileInfo = new FileInfo(file); + if (latestFile == null || fileInfo.LastWriteTime > latestFile.LastWriteTime) + { + latestFile = fileInfo; + } + } + + TaskControl.Logger.LogDebug("当前最新的OBS日志文件:{Path}", latestFile?.FullName); + return latestFile; + } + + public static async Task ProcessLog(DateTime? beforeStartTime) + { + var logFile = GetLogFilePath(); + if (logFile == null) + { + return null; + } + + // 以共享的方式读取日志文件 + string content; + try + { + await using var fileStream = new FileStream(logFile.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + using var reader = new StreamReader(fileStream); + content = await reader.ReadToEndAsync(); + } + catch (IOException e) + { + TaskControl.Logger.LogError("OBS日志文件读取失败:{Msg}", e.Message); + return null; + } + + // 从下网上找到最近一次 = Recording Start = 关键词的行 + var lines = content.Split('\n'); + string? lastLine = null; + for (var i = lines.Length - 1; i >= 0; i--) + { + if (lines[i].Contains("= Recording Start =")) + { + if (beforeStartTime != null) + { + var timeStr = lines[i].Substring(0, 12); + if (DateTime.TryParse(timeStr, out var time)) + { + if (time >= beforeStartTime) + { + lastLine = lines[i]; + return time; + } + } + } + else + { + lastLine = lines[i]; + break; + } + } + } + + if (lastLine == null) + { + TaskControl.Logger.LogDebug("未找到OBS日志中录制开始关键词"); + return null; + } + + // 内容应该是 16:19:40.665: ==== Recording Start =============================================== + var timeStr2 = lastLine.Substring(0, 12); + // 16:19:40.665 转换到datetime + if (DateTime.TryParse(timeStr2, out var time2)) + { + return time2; + } + + return null; + } + + public static void FindStartTime(string fileName, DateTime beforeStartTime) + { + Task.Run(async () => + { + for (int i = 0; i < 10; i++) + { + await Task.Delay(1000); + var time = await ProcessLog(beforeStartTime); + if (time != null) + { + var t = time.Value; + TaskControl.Logger.LogInformation("OBS实际录制开始时间(来自log):{Time}", t.ToString("yyyy-MM-dd HH:mm:s.ffff")); + var folderPath = Global.Absolute($@"User\KeyMouseScript\{fileName}\"); + await File.WriteAllTextAsync(Path.Combine(folderPath, "videoStartTime.txt"), (t.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalNanoseconds.ToString("F0")); + break; + } + else + { + TaskControl.Logger.LogDebug("未找到OBS实际录制开始时间,等待1s后重试"); + } + } + }); + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/Genshin/Settings2/GenshinGameSettings.cs b/BetterGenshinImpact/Genshin/Settings2/GenshinGameSettings.cs index 858113d5..e154d362 100644 --- a/BetterGenshinImpact/Genshin/Settings2/GenshinGameSettings.cs +++ b/BetterGenshinImpact/Genshin/Settings2/GenshinGameSettings.cs @@ -324,7 +324,7 @@ public class GenshinGameSettings } var str = Encoding.UTF8.GetString(rawBytes); - Debug.WriteLine(str); + // Debug.WriteLine(str); return str; } diff --git a/BetterGenshinImpact/Service/Singletons/StartEndSingleton.cs b/BetterGenshinImpact/Service/Singletons/StartEndSingleton.cs index e3e25f7d..01f80717 100644 --- a/BetterGenshinImpact/Service/Singletons/StartEndSingleton.cs +++ b/BetterGenshinImpact/Service/Singletons/StartEndSingleton.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.Core.Config; using BetterGenshinImpact.Core.Video; +using BetterGenshinImpact.Core.Video.obs; using BetterGenshinImpact.GameTask; using BetterGenshinImpact.GameTask.Common; using BetterGenshinImpact.Genshin.Settings; @@ -65,7 +66,7 @@ public class StartEndSingleton : Singleton // // 退出 // Environment.Exit(0); // } - TosClientHelper.Instance.Test(Global.Absolute(@$"User/config.json")); + // TosClientHelper.Instance.Test(Global.Absolute(@$"User/config.json")); }