using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.Core.Config; using BetterGenshinImpact.GameTask.AutoPathing.Model; using BetterGenshinImpact.GameTask.Common; using BetterGenshinImpact.GameTask.LogParse; using BetterGenshinImpact.Helpers; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; namespace BetterGenshinImpact.GameTask.FarmingPlan; /// /// 锄地统计记录器 /// public static class FarmingStatsRecorder { public static readonly string LogDirectory = Global.Absolute(@"log\FarmingPlan"); public static bool debugMode = false; //输出测试用 public static void debugInfo(string msg) { if (debugMode) { TaskControl.Logger.LogDebug(msg); } } public static bool IsDailyFarmingLimitReached(FarmingSession farmingSession, out string message) { if (!farmingSession.AllowFarmingCount || farmingSession.PrimaryTarget == "disable") { message = ""; return false; } var dailyFarmingData = ReadDailyFarmingData(); var config = TaskContext.Instance().Config.OtherConfig.FarmingPlanConfig; var mysdCfg = config.MiyousheDataConfig; bool mysEnable = mysdCfg.Enabled; var cap = dailyFarmingData.getFinalCap(); var ft = dailyFarmingData.getFinalTotalMobCount(); var dailyEliteCap = cap.DailyEliteCap; var dailyMobCap = cap.DailyMobCap; var totalEliteMobCount = ft.TotalEliteMobCount; var totalNormalMobCount = ft.TotalNormalMobCount; bool isEliteOverLimit = totalEliteMobCount >= dailyEliteCap; bool isNormalOverLimit = totalNormalMobCount >= dailyMobCap; var messages = new List(); if (isEliteOverLimit) messages.Add($"精英超上限:{totalEliteMobCount}/{dailyEliteCap}"); if (isNormalOverLimit) messages.Add($"小怪超上限:{totalNormalMobCount}/{dailyMobCap}"); //尝试更新米游社的条件,超过最后札记两个小时,并且超过上次尝试更新20分钟 debugInfo($"尝试更新米游社:{DateTime.Now} > {dailyFarmingData.TravelsDiaryDetailManagerUpdateTime.AddHours(2)}&&{DateTime.Now}> {dailyFarmingData.LastMiyousheUpdateTime.AddMinutes(20)}"); if (mysEnable &&DateTime.Now > dailyFarmingData.TravelsDiaryDetailManagerUpdateTime.AddHours(2) && DateTime.Now > dailyFarmingData.LastMiyousheUpdateTime.AddMinutes(20)) { Task.Run(() => TryUpdateTravelsData()); } // 两者都超限时直接返回 if (isEliteOverLimit && isNormalOverLimit) { message = string.Join(",", messages); return true; } if ( farmingSession.NormalMobCount == 0 && farmingSession.EliteMobCount ==0) { messages.Add("精英和小怪计数都为0,请确认配置"); message = string.Join(",", messages); return true; } if ((farmingSession.EliteMobCount == 0 && farmingSession.PrimaryTarget == "elite") ||(farmingSession.NormalMobCount == 0 && farmingSession.PrimaryTarget == "normal")) { messages.Add("主目标计数为0,请确认配置"); message = string.Join(",", messages); return true; } bool result = false; if (farmingSession.PrimaryTarget == "elite" && isEliteOverLimit) { result = true; if (farmingSession.NormalMobCount > 0) messages.Add("脚本主目标为精英"); } else if (farmingSession.PrimaryTarget == "normal" && isNormalOverLimit) { result = true; if (farmingSession.EliteMobCount > 0) messages.Add("脚本主目标为小怪"); } if (!result) { //精英到上限,本次小怪数量为0,跳过。小怪到上限,本次精英数量为0,跳过。 result = (isEliteOverLimit && farmingSession.NormalMobCount == 0) || (isNormalOverLimit && farmingSession.EliteMobCount == 0); } message = string.Join(",", messages); return result; } /// /// 记录锄地统计数据 /// /// 本次锄地会话数据 /// 本次锄地路径信息 public static void RecordFarmingSession(FarmingSession session, FarmingRouteInfo route) { try { DateTime now = DateTime.Now; DailyFarmingData dailyData = ReadDailyFarmingData(); // 如果需要计数,则更新统计数据 if (session.AllowFarmingCount) { dailyData.TotalNormalMobCount += session.NormalMobCount; dailyData.TotalEliteMobCount += session.EliteMobCount; } // 添加新的锄地记录 dailyData.Records.Add(CreateFarmingRecord(session, route, now)); var ft = dailyData.getFinalTotalMobCount(); var cap = dailyData.getFinalCap(); // 保存更新后的数据 SaveDailyData(dailyData.FilePath, dailyData); TaskControl.Logger.LogInformation( $"锄地进度:[小怪:{ft.TotalNormalMobCount}/{cap.DailyMobCap}" + $",精英:{ft.TotalEliteMobCount}/{cap.DailyEliteCap}]"+(dailyData.EnableMiyousheStats()?"(合并米游社数据)":"")); } catch (Exception e) { TaskControl.Logger.LogError($"锄地进度记录失败:{e.Message}"); } } //生成需要读取的札记月份 private static readonly SemaphoreSlim _updateLock = new SemaphoreSlim(1, 1); private static bool _isUpdating = false; public async static Task TryUpdateTravelsData() { // 快速检查:如果正在更新则立即退出 if (_isUpdating) return; try { _isUpdating = true; // await _updateLock.WaitAsync(); // 获取独占锁 debugInfo("开始更新米游社札记"); string cookie = TaskContext.Instance().Config.OtherConfig.MiyousheConfig.Cookie; DailyFarmingData? dailyFarmingData = null; if (TaskContext.Instance().Config.OtherConfig.FarmingPlanConfig.MiyousheDataConfig.Enabled && cookie != string.Empty) { try { GameInfo gameInfo = await TravelsDiaryDetailManager.UpdateTravelsDiaryDetailManager(cookie,true); List actionItems = TravelsDiaryDetailManager.loadNowDayActionItems(gameInfo); //当天的数据 MoraStatistics ms = new MoraStatistics(); ms.ActionItems.AddRange(actionItems); dailyFarmingData = ReadDailyFarmingData(); if (actionItems.Count > 0) { dailyFarmingData.MiyousheTotalEliteMobCount = ms.EliteGameStatistics; dailyFarmingData.MiyousheTotalNormalMobCount = ms.SmallMonsterStatistics; dailyFarmingData.TravelsDiaryDetailManagerUpdateTime = DateTime.Parse(actionItems.Last().Time); debugInfo($"札记当天数据:[精英:{dailyFarmingData.MiyousheTotalEliteMobCount},小怪:{dailyFarmingData.MiyousheTotalNormalMobCount},{dailyFarmingData.TravelsDiaryDetailManagerUpdateTime}]"); } else { TaskControl.Logger.LogError($"米游社旅行札记未有数据!"); } } catch (Exception e) { TaskControl.Logger.LogError($"米游社数据更新失败,请检查cookie是否过期:{e.Message}"); } } if (dailyFarmingData == null) { dailyFarmingData = ReadDailyFarmingData(); } dailyFarmingData.LastMiyousheUpdateTime = DateTime.Now; SaveDailyData(dailyFarmingData.FilePath, dailyFarmingData); } finally { //_updateLock.Release(); _isUpdating = false; } } public static DailyFarmingData ReadDailyFarmingData() { // 确定统计日期(以凌晨4点为分界) DateTimeOffset now = ServerTimeHelper.GetServerTimeNow(); DateTimeOffset statsDate = CalculateStatsDate(now); string dateString = statsDate.ToString("yyyyMMdd"); // 确保目录存在 Directory.CreateDirectory(LogDirectory); string filePath = Path.Combine(LogDirectory, $"{dateString}.json"); // 读取现有数据或创建新数据 DailyFarmingData dailyData = LoadDailyData(filePath); return dailyData; } /// /// 计算统计日期(凌晨4点为分界) /// private static DateTime CalculateStatsDate(DateTimeOffset currentTime) { // 如果当前时间在4点之前,则算作前一天 return currentTime.Hour < 4 ? currentTime.Date.AddDays(-1) : currentTime.Date; } /// /// 创建新的锄地记录 /// private static FarmingRecord CreateFarmingRecord(FarmingSession session, FarmingRouteInfo route, DateTime timestamp) { return new FarmingRecord { GroupName = route.GroupName, ProjectName = route.ProjectName, FolderName = route.FolderName, NormalMobCount = session.AllowFarmingCount ? session.NormalMobCount : 0, EliteMobCount = session.AllowFarmingCount ? session.EliteMobCount : 0, Timestamp = timestamp }; } /// /// 加载每日数据 /// private static DailyFarmingData LoadDailyData(string filePath) { if (!File.Exists(filePath)) { return new DailyFarmingData() { FilePath = filePath }; } try { string json = File.ReadAllText(filePath); DailyFarmingData dailyFarmingData = JsonConvert.DeserializeObject(json, GetJsonSettings()) ?? new DailyFarmingData(); dailyFarmingData.FilePath = filePath; return dailyFarmingData; } catch (JsonException) { // 文件损坏时创建新数据 return new DailyFarmingData() { FilePath = filePath }; } } /// /// 保存每日数据 /// private static void SaveDailyData(string filePath, DailyFarmingData data) { string json = JsonConvert.SerializeObject(data, GetJsonSettings()); File.WriteAllText(filePath, json); } /// /// 获取JSON序列化设置 /// private static JsonSerializerSettings GetJsonSettings() { return new JsonSerializerSettings { // 使用下划线命名法 ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() }, Formatting = Formatting.Indented, DateFormatHandling = DateFormatHandling.IsoDateFormat }; } }