using System.Collections.ObjectModel; using System.Text.Json; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; using XFEEDToolBox.Core.Execution; using XFEEDToolBox.Core.Data; using XFEEDToolBox.Core.Localization; using XFEEDToolBox.Core.Models; using XFEEDToolBox.Core.Navigation; using XFEEDToolBox.Core.Planning; namespace XFEEDToolBox.ViewModels; public sealed class TradeRouteCandidateViewModel(RoutePlan plan,int rank,IReadOnlyList? matchedGoals=null,bool syntheticFixture=false,DateTimeOffset? verifiedAt=null):ObservableObject { public RoutePlan Plan{get;}=plan; private readonly IReadOnlyList communityGoals=matchedGoals??[]; private readonly DateTimeOffset communityGoalReadAt=verifiedAt??DateTimeOffset.UtcNow; internal IReadOnlyList MatchedCommunityGoals=>communityGoals; private bool communityGoalActive=matchedGoals?.Any(goal=>goal.Active&&goal.Expires>DateTimeOffset.UtcNow)==true; private bool selected; public bool IsSelected { get=>selected; set{if(SetProperty(ref selected,value)){OnPropertyChanged(nameof(CardBorder));OnPropertyChanged(nameof(SelectedVisibility));}} } public Brush CardBorder=>new SolidColorBrush(IsCommunityGoal ?IsSelected?Windows.UI.Color.FromArgb(255,195,166,255):Windows.UI.Color.FromArgb(255,102,80,144) :IsSelected?Windows.UI.Color.FromArgb(255,255,174,72):Windows.UI.Color.FromArgb(255,37,52,72)); public bool IsCommunityGoal=>communityGoalActive; public Brush RouteAccentBrush=>new SolidColorBrush(IsCommunityGoal?Windows.UI.Color.FromArgb(255,195,166,255):Windows.UI.Color.FromArgb(255,255,174,72)); public Brush CommunityGoalBadgeBackground=>new SolidColorBrush(Windows.UI.Color.FromArgb(40,166,120,245)); public Visibility CommunityGoalVisibility=>IsCommunityGoal?Visibility.Visible:Visibility.Collapsed; public string CommunityGoalLabel=>syntheticFixture?"CG 活动交付 · 合成夹具":"含 CG 活动交付货物"; public string CommunityGoalDescription=>string.Join(Environment.NewLine,communityGoals.Select(goal=>$"{goal.Title} · {goal.StationName} · 截止 {goal.Expires.ToLocalTime():MM-dd HH:mm}")) +(syntheticFixture?"\n离线合成界面夹具,不是真实活动、资金、行情或交易。":$"\n原目录核验于 {communityGoalReadAt.ToLocalTime():HH:mm:ss};货单包含目标活动接收的商品。额外CG奖励未计入预计收益,执行前仍须重新核验。"); internal void RefreshCommunityGoalValidity(DateTimeOffset now) { var active=now>=communityGoalReadAt&&now-communityGoalReadAt<=TimeSpan.FromMinutes(2)&&communityGoals.Any(goal=>goal.Active&&goal.Expires>now); if(active==communityGoalActive)return;communityGoalActive=active; foreach(var name in new[]{nameof(IsCommunityGoal),nameof(CardBorder),nameof(RouteAccentBrush),nameof(CommunityGoalVisibility)})OnPropertyChanged(name); } public Visibility SelectedVisibility=>IsSelected?Visibility.Visible:Visibility.Collapsed; public string Rank=>$"{rank:00}"; public string Recommendation=>syntheticFixture?"合成夹具":rank==1?"推荐":"备选"; public string Origin=>Plan.Legs[0].From.Name; public string Destination=>Plan.Legs[0].To.Name; public string OriginDetail=>Plan.Legs[0].From.SystemName; public string DestinationDetail=>Plan.Legs[0].To.SystemName; public string RouteKind=>Plan.IsLoop?(Plan.Legs.Count>2?$"{Plan.Legs.Count} 段环线":"往返环线"):$"{Plan.Legs.Count} 段航线"; public string RouteSummary=>string.Join(" → ",new[]{Plan.Legs[0].From.Name}.Concat(Plan.Legs.Select(leg=>leg.To.Name))); public string Hourly=>Plan.CreditsPerHour>=1_000_000?$"{Plan.CreditsPerHour/1_000_000:F1}M":$"{Plan.CreditsPerHour:N0}"; public string HourlyExact=>$"{Plan.CreditsPerHour:N0} Cr/h"; public string Risk=>Plan.RiskTier==TradeRiskTier.Unknown?"风险信息不足":Plan.RiskDisplay+"风险"; public Brush RiskBrush=>new SolidColorBrush(Plan.RiskTier switch { TradeRiskTier.Low=>Windows.UI.Color.FromArgb(255,84,222,200), TradeRiskTier.Moderate=>Windows.UI.Color.FromArgb(255,255,174,72), TradeRiskTier.High or TradeRiskTier.VeryHigh=>Windows.UI.Color.FromArgb(255,255,134,121), _=>Windows.UI.Color.FromArgb(255,145,163,185) }); public string Profit=>$"{Plan.NetProfit:N0} Cr"; public string Duration=>$"{Plan.Minutes:F1} 分钟"; public string Distance=>$"{Plan.DeadheadDistanceLy+Plan.Legs.Sum(leg=>leg.DistanceLy):F1} ly"; public string Jumps=>$"{Plan.DeadheadJumps+Plan.Legs.Sum(leg=>leg.EstimatedJumps)} 跳"; public string Cargo=>string.Join(Environment.NewLine,Plan.Legs.Select((leg,index)=> $"{CargoLabel(index)} {(leg.Orders.Count==0?"空载转场":leg.Orders[0].Summary)}{(leg.Orders.Count>1?$" · 另 {leg.Orders.Count-1} 种商品":"")}")); public string CargoDetails=>string.Join(Environment.NewLine,Plan.Legs.Select((leg,index)=> $"{CargoLabel(index)} · {leg.From.Name} → {leg.To.Name}:{leg.CargoSummary}")); private string CargoLabel(int index)=>Plan.Legs.Count==1?"货物":Plan.IsLoop&&Plan.Legs.Count==2?(index==0?"去程":"返程"):$"第 {index+1} 段"; public string Approach=>Plan.DeadheadMinutes>0?$"含前往起点 {Plan.DeadheadDistanceLy:F1} ly / {Plan.DeadheadJumps} 跳":"包含各站停靠与航行时间"; } public partial class ToolboxViewModel { private bool updatingInvestment,investmentFollowsBalance=true,tradeInputsInitialized,selectingTradeCandidate,manualTradeConfigured; private DispatcherQueueTimer? tradeExecutionTimer; private DateTimeOffset? tradeExecutionStartedAt; private bool plannedRoundCounted; private sealed record TradeRunMetrics(string SessionId,int BaselineRounds); [ObservableProperty,NotifyPropertyChangedFor(nameof(TradeAdvancedVisibility),nameof(TradeEditLabel))] public partial bool TradeAdvancedEditing{get;set;} [ObservableProperty] public partial double TradeInvestment{get;set;} [ObservableProperty] public partial string TradePlanningStatus{get;set;}="输入投入资金,比较可行路线。"; [ObservableProperty] public partial string TradeEmptyTitle{get;set;}="规划下一趟航程"; [ObservableProperty] public partial string TradeEmptyDescription{get;set;}="飞船、货舱与余额会自动读取,点击规划路线即可比较方案。"; [ObservableProperty] public partial string TradeCommunityGoalStatus{get;set;}="CG 标记需核实有效活动、目标站和接收商品;额外奖励不计入预计收益。"; internal object? TradeCommunityGoalReadForProbe{get;private set;} private DateTimeOffset? tradeCommunityGoalVerifiedAt; internal TradePlanningDiagnostics? TradePlanningDiagnosticForProbe{get;private set;} [ObservableProperty] public partial int CompletedTradeRounds{get;set;} [ObservableProperty] public partial string TradeConfirmedProfit{get;set;}="0 Cr"; [ObservableProperty] public partial string TradeElapsed{get;set;}="00:00:00"; [ObservableProperty] public partial TradeRouteCandidateViewModel? SelectedTradeCandidate{get;set;} public ObservableCollection TradeCandidates{get;}=[]; public Visibility TradeAdvancedVisibility=>TradeAdvancedEditing?Visibility.Visible:Visibility.Collapsed; public string TradeEditLabel=>TradeAdvancedEditing?"收起高级搜索选项":"高级搜索选项"; public Visibility TradeEmptyVisibility=>TradeCandidates.Count==0?Visibility.Visible:Visibility.Collapsed; public Visibility TradePlanVisibility=>Plan?.Legs.Count>0?Visibility.Visible:Visibility.Collapsed; public bool TradeSelectionEnabled=>!RunActive&&!IsBusy; public string TradeShipName=>CurrentPlayer.Ships.FirstOrDefault(ship=>ship.ShipId==CurrentPlayer.CurrentShipId)?.DisplayName ??(string.IsNullOrWhiteSpace(CurrentPlayer.Ship)?"等待飞船数据":ChineseNames.Ship(CurrentPlayer.Ship)); public string TradeCargoSummary=>CurrentPlayer.CargoCapacity>0?$"可用货舱 {CurrentPlayer.FreeCargo:N0} / {CurrentPlayer.CargoCapacity:N0} t":"等待货舱数据"; public string TradeJumpSummary=>CurrentPlayer.MaxJumpRange is >0?$"估算满载跳距 {CurrentPlayer.MaxJumpRange.Value*.8:F1} ly":"等待跳距数据"; public string TradeOriginSummary=>string.IsNullOrWhiteSpace(CurrentPlayer.SystemName)?"等待当前位置":"从 "+CurrentPlayer.SystemName+" 出发 · 自动比较范围内货源"; private double EffectiveTradeReserve=>double.IsFinite(Reserve)?Math.Max(0,Reserve):(double)CurrentPlayer.Rebuy; public string TradeFundsSummary=>CurrentPlayer.Credits is {} credits ?$"可投入 {Math.Max(0,credits-(decimal)EffectiveTradeReserve):N0} Cr · 已留出 {EffectiveTradeReserve:N0} Cr 运营与保险资金" :"等待读取当前余额,投入金额将自动填入。"; public string TradeInvestmentMode=>investmentFollowsBalance?"全部可用资金":"自定义投入"; public string TradeSelectedRouteSummary=>RunActive&&automaticTradeStop is not null&&automaticTradeParameters is{} automatic ?$"{(automatic.Mode==XFEEDToolBox.Core.Execution.AutomaticTradeMode.CommunityGoal?"CG 重复跑商":"重复跑商")} · 交付站 {automatic.Destination.DisplayName}" :SelectedTradeCandidate?.RouteSummary ??(manualTradeConfigured&&SelectedStart is not null&&AutomaticDestination is not null?SelectedStart.Record.Name+" → "+AutomaticDestination.Record.Name:"选择方案后即可开始执行"); public bool TradeHasExistingCargo=>SelectedTradeCandidate is {} candidate&&(candidate.Plan.Request.OccupiedCargo>0||CurrentPlayer.CargoCount>0); public bool TradeExecutesFullPlan=>SelectedTradeCandidate is {} candidate&&(candidate.Plan.IsCargoAlternative||!candidate.Plan.IsLoop||candidate.Plan.Legs.Count!=2 ||candidate.Plan.Request.OccupiedCargo>0||candidate.Plan.Legs[0].Orders.Count==0 ||candidate.Plan.Legs.SelectMany(leg=>new[]{leg.From.MarketId,leg.To.MarketId}).Distinct().Count()>2); public string TradeExecutionActionLabel=>SelectedTradeCandidate is null?"开始执行":TradeExecutesFullPlan?"执行此路线":"开始循环"; public string TradeExecutionPolicy=>TradeHasExistingCargo?"已保留现有货物用于规划;自动执行前请先处理现有货物。":SelectedTradeCandidate is null?(manualTradeConfigured?"按手动站点与跑商方式执行,收益只统计已确认成交。":"收益按实际成交与费用回执累计。") :TradeExecutesFullPlan?"完整路线执行一遍后停止;需先停靠起点。":"按所选两站循环执行,采购前重新核对行情;可随时取消。"; [RelayCommand] private void ToggleTradeAdvanced()=>TradeAdvancedEditing=!TradeAdvancedEditing; [RelayCommand] private void UseAllTradeFunds() { investmentFollowsBalance=true;SetTradeInvestment(Math.Max(0,Cash-EffectiveTradeReserve)); OnPropertyChanged(nameof(TradeInvestmentMode));InvalidateTradeCandidates(); } private void SetTradeInvestment(double value) {updatingInvestment=true;try{TradeInvestment=value;}finally{updatingInvestment=false;}} partial void OnTradeInvestmentChanged(double value) {if(!updatingInvestment){investmentFollowsBalance=!double.IsFinite(value);OnPropertyChanged(nameof(TradeInvestmentMode));InvalidateTradeCandidates();}} partial void OnReserveChanged(double value) { if(investmentFollowsBalance)SetTradeInvestment(Math.Max(0,Cash-EffectiveTradeReserve)); OnPropertyChanged(nameof(TradeFundsSummary)); InvalidateTradeCandidates(); } partial void OnCashChanged(double value) {if(investmentFollowsBalance)SetTradeInvestment(Math.Max(0,value-EffectiveTradeReserve));InvalidateTradeCandidates();} partial void OnTradeAdvancedEditingChanged(bool value) {if(value&&SelectedStart is not null&&AutomaticDestination is not null)manualTradeConfigured=true;RefreshTradePlanCommands();} private void NoteManualTradeConfiguration() {if(TradeAdvancedEditing&&!selectingTradeCandidate)manualTradeConfigured=true;} partial void OnSelectedTradeCandidateChanged(TradeRouteCandidateViewModel? value) { foreach(var candidate in TradeCandidates)candidate.IsSelected=ReferenceEquals(candidate,value); if(value is null)return; selectingTradeCandidate=true; try { var plan=value.Plan; var rows=Stations.Select(station=>station.Record).Concat(plan.Legs.SelectMany(leg=>new[]{leg.From,leg.To})).DistinctBy(station=>station.MarketId).ToArray(); Stations.Apply(rows); Plan=plan;SelectedLeg=plan.Legs.FirstOrDefault(); SelectedStart=Stations.First(station=>station.MarketId==plan.Legs[0].From.MarketId); AutomaticDestination=Stations.First(station=>station.MarketId==plan.Legs[0].To.MarketId); var cgGoals=plan.Request.CommunityGoalSupplyOnly?value.MatchedCommunityGoals.Where(goal=>goal.MarketId==plan.Legs[0].To.MarketId).ToArray():[]; AutomaticModeIndex=cgGoals.Length>0?1:0;AutomaticReturnTrade=cgGoals.Length==0&&plan.IsLoop; if(cgGoals.Length>0)AutomaticCommodities=string.Join(", ",cgGoals.SelectMany(goal=>goal.AcceptedCommodities).Select(goods=>CommodityCatalog.Key(goods)) .Where(goods=>plan.Request.CommunityGoalCommodityFilter is not{Length:>0}||plan.Request.CommunityGoalCommodityFilter.Contains(goods,StringComparer.Ordinal)).Distinct(StringComparer.Ordinal)); PlanProfit=$"{plan.NetProfit:N0} Cr";PlanHourly=$"{plan.CreditsPerHour:N0} Cr/h";PlanDuration=$"{plan.Minutes:F1} 分钟"; PlanInfo=$"{plan.Legs.Count} 段{(plan.IsLoop?"环线":"航线")} · {plan.StationsConsidered} 个候选站点"; PlanWarnings=string.Join(Environment.NewLine,plan.Warnings); NotifyTradePlanningSummary();RefreshTradePlanCommands(); } finally{selectingTradeCandidate=false;} } private void SetTradeCandidates(IReadOnlyList plans,TradePlanningDiagnostics? diagnostics=null,IReadOnlyList? goals=null,bool syntheticFixture=false) { var now=DateTimeOffset.UtcNow; if(TradePlanningModeIndex==1) { var valid=plans.Where(plan=>plan.Request.CommunityGoalSupplyOnly&&CommunityGoalSupplyScope.MatchesRoute(goals??[],plan,now) &&(syntheticFixture||tradeCommunityGoalVerifiedAt is {} at&&now>=at&&now-at<=TimeSpan.FromMinutes(2))).ToArray(); if(plans.Count>0&&valid.Length==0&&diagnostics is not null) diagnostics=diagnostics with{Code="cg-directory-changed",Message="CG 活动目录已过期或发生变化,请重新规划;未沿用普通路线或此前活动结果。"}; plans=valid; } TradePlanningDiagnosticForProbe=diagnostics; if(diagnostics is null){TradeCommunityGoalReadForProbe=null;tradeCommunityGoalVerifiedAt=null;TradeCommunityGoalStatus="CG 标记需核实有效活动、目标站和接收商品;额外奖励不计入预计收益。";} SelectedTradeCandidate=null;TradeCandidates.Clear(); foreach(var plan in plans.Take(3))TradeCandidates.Add(new(plan,TradeCandidates.Count+1,CommunityGoalCatalogue.MatchRoute(goals??[],plan,DateTimeOffset.UtcNow),syntheticFixture,tradeCommunityGoalVerifiedAt)); SelectedTradeCandidate=TradeCandidates.FirstOrDefault(); if(TradeCandidates.Count==0){Plan=null;SelectedLeg=null;PlanInfo="尚无可确认的盈利路线。";TradeEmptyTitle="尚无可确认的盈利路线"; TradeEmptyDescription=diagnostics?.Message??"请先核对所选范围内的行情与飞船参数,再重新规划。";PlanInfo=TradeEmptyDescription;} TradePlanningStatus=TradeCandidates.Count>0?$"{TradeCandidates.Count} 个方案 · 按预计净利润 / 小时排序"+(diagnostics is not null?$" · {diagnostics.FreshStations} 个新鲜行情站点":"") :diagnostics?.Message??"尚无可确认的盈利路线。"; if(TradeCandidates.Count>0&&diagnostics is not null) {if(diagnostics.InputTruncated)TradePlanningStatus+=" · 站点输入受限";if(diagnostics.SearchPruned)TradePlanningStatus+=" · 有界路线搜索";} OnPropertyChanged(nameof(TradeEmptyVisibility));OnPropertyChanged(nameof(TradePlanVisibility)); } private void SetTradePlanningIssue(string title,string message) {SetTradeCandidates([]);TradeEmptyTitle=title;TradeEmptyDescription=message;TradePlanningStatus=PlanInfo=message;} private void InvalidateTradeCandidates() { if(selectingTradeCandidate||RunActive)return; Interlocked.Increment(ref tradePlanningInputVersion); if(TradeCandidates.Count==0)return; SetTradeCandidates([]);TradePlanningStatus="参数已更改,请重新规划路线。"; TradeEmptyTitle="重新规划路线";TradeEmptyDescription="投入、范围或约束已更改,点击规划路线重新比较。"; } private void RefreshTradePlanningPlayer(PlayerState player,bool force=false) { RefreshTradePlanningIdentity(player); RefreshTradeShipPad(); Cash=player.Credits is {} credits?(double)credits:0; if(force||!tradeInputsInitialized)Reserve=(double)player.Rebuy;else if(Reserve<(double)player.Rebuy)Reserve=(double)player.Rebuy; Hold=player.CargoCapacity;JumpRange=player.MaxJumpRange??0; if(force){investmentFollowsBalance=true;SetTradeInvestment(Math.Max(0,Cash-EffectiveTradeReserve));} if((force||!TradeAdvancedEditing&&Plan is null&&!RunActive)&&player.MarketId is {} market) SelectedStart=Stations.FirstOrDefault(station=>station.MarketId==market); tradeInputsInitialized=true;NotifyTradePlanningSummary();RefreshTradePlanCommands(); } private void NotifyTradePlanningSummary() { foreach(var candidate in TradeCandidates)candidate.RefreshCommunityGoalValidity(DateTimeOffset.UtcNow); if(TradePlanningModeIndex==1&&!IsBusy&&!RunActive&&TradeCandidates.Any(candidate=>!candidate.IsCommunityGoal)) SetTradePlanningIssue("CG 目录需要刷新","活动有效期或目录核验时间已到,请重新规划 CG 供货路线;未保留普通推荐。"); foreach(var name in new[]{nameof(TradeShipName),nameof(TradeCargoSummary),nameof(TradeJumpSummary),nameof(TradeOriginSummary),nameof(TradeFundsSummary),nameof(TradeInvestmentMode),nameof(TradeSelectedRouteSummary),nameof(TradePlanVisibility),nameof(TradeHasExistingCargo),nameof(TradeExecutionActionLabel),nameof(TradeExecutionPolicy)})OnPropertyChanged(name); } private async Task> ReadTradeCommunityGoalsForPlanningAsync(bool demo,CancellationToken token) { tradeCommunityGoalVerifiedAt=null; TradeCommunityGoalReadForProbe=new{at=DateTimeOffset.UtcNow,attempted=false,readOnly=true,joinSent=false,gameInputsSent=0,selectionChangesSent=0}; var player=CurrentPlayer; if(demo||!player.InGame||!player.Docked||player.InDanger||player.MarketId is not >0||player.CurrentShipId is null||player.LoadGameAt is null ||string.IsNullOrWhiteSpace(player.CommanderId)||runtime.FlightDriver is not NativeFlightControlDriver driver) {TradeCommunityGoalStatus=TradePlanningModeIndex==1?"请在停靠且原生接口就绪后核对 CG 目录;当前不能推荐 CG 供货路线,未回退普通跑商。":"CG 活动目录尚未核验;已知市场利润仍可比较,额外奖励未计入。";return [];} using var deadline=CancellationTokenSource.CreateLinkedTokenSource(token);deadline.CancelAfter(TimeSpan.FromSeconds(3)); bool SameContext()=>CurrentPlayer.InGame&&CurrentPlayer.Docked&&!CurrentPlayer.InDanger&&CurrentPlayer.CommanderId==player.CommanderId&&CurrentPlayer.CurrentShipId==player.CurrentShipId &&CurrentPlayer.LoadGameAt==player.LoadGameAt&&CurrentPlayer.MarketId==player.MarketId&&runtime.FlightDriver is NativeFlightControlDriver current&¤t.ProcessId==driver.ProcessId; try { var read=await new NativeCommunityGoalClient(new NativeCommerceChannel(driver.ProcessId),player.MarketId.Value).ReadAsync(false,deadline.Token); token.ThrowIfCancellationRequested(); if(!SameContext()) {TradeCommunityGoalStatus="会话或停靠地点已改变,未沿用此前CG目录。";TradeCommunityGoalReadForProbe=new{at=DateTimeOffset.UtcNow,attempted=true,readOnly=true,contextMatched=false,joinSent=false,gameInputsSent=0,selectionChangesSent=0};return [];} TradeCommunityGoalReadForProbe=new{at=DateTimeOffset.UtcNow,attempted=true,readOnly=true,contextMatched=true,processId=driver.ProcessId, read.Generation,read.Proof,goalCount=read.Goals.Count,mutationsSent=0,joinSent=false,gameInputsSent=0,selectionChangesSent=0}; TradeCommunityGoalStatus="CG 标记依据本次原游戏目录匹配;额外活动奖励未计入预计收益。"; tradeCommunityGoalVerifiedAt=DateTimeOffset.UtcNow; runtime.Log("CG 路线",$"只读目录核验:generation {read.Generation},{read.Goals.Count} 个活动记录;0报名、0交易、0游戏输入。"); return read.Goals; } catch(OperationCanceledException)when(token.IsCancellationRequested){throw;} catch(Exception error) { TradeCommunityGoalStatus=TradePlanningModeIndex==1?"CG 活动目录暂不可用,当前不能推荐 CG 供货路线;未回退普通跑商。":"CG 活动目录暂不可用,未标记活动路线;额外奖励未计入。"; TradeCommunityGoalReadForProbe=new{at=DateTimeOffset.UtcNow,attempted=true,readOnly=true,verified=false,issue=error.GetType().Name,joinSent=false,gameInputsSent=0,selectionChangesSent=0}; runtime.Log("CG 路线",error.ToString());return []; } } private void RefreshTradeExecutionTimer(bool active) { OnPropertyChanged(nameof(TradeSelectionEnabled)); if(active) { tradeExecutionStartedAt??=DateTimeOffset.UtcNow; if(tradeExecutionTimer is null) { tradeExecutionTimer=dispatcher.CreateTimer();tradeExecutionTimer.Interval=TimeSpan.FromSeconds(1); tradeExecutionTimer.Tick+=(_,_)=>RefreshTradeElapsed(); } tradeExecutionTimer.Start(); } else{RefreshTradeElapsed();tradeExecutionTimer?.Stop();} } private void RefreshTradeElapsed() { if(tradeExecutionStartedAt is not {} started)return; var elapsed=DateTimeOffset.UtcNow-started;if(elapsed(File.ReadAllText(path),ToolboxSettings.JsonOptions) is {} existing&&existing.SessionId==session.Id) return existing.BaselineRounds; var value=new TradeRunMetrics(session.Id,completedRounds);var temporary=path+".tmp"; File.WriteAllText(temporary,JsonSerializer.Serialize(value,ToolboxSettings.JsonOptions));File.Move(temporary,path,true);return value.BaselineRounds; } }