using CommunityToolkit.Mvvm.Input; using Microsoft.UI.Xaml.Automation.Peers; using Microsoft.UI.Xaml.Automation.Provider; using XFEEDToolBox.Controls; using XFEEDToolBox.Core.Models; using XFEEDToolBox.Core.Navigation; using XFEEDToolBox.Views; using XFEEDToolBox.Services; namespace XFEEDToolBox; public partial class App { private static async Task RunInterfaceOnlyProbeAsync(string path) { var directory=Path.GetDirectoryName(Path.GetFullPath(path))!;Directory.CreateDirectory(directory);object? result=null;string? failure=null; if(Environment.GetCommandLineArgs().Contains("--preview-layout-only")) { try{result=await RunPreviewLayoutProbeAsync(directory);}catch(Exception error){failure=error.ToString();} await File.WriteAllTextAsync(path,System.Text.Json.JsonSerializer.Serialize(new{result,failure,uiError=ViewModel.ErrorMessage,gameFlightCommandsInvoked=false},new System.Text.Json.JsonSerializerOptions{WriteIndented=true}));MainWindow.Close();return; } try { MainWindow.AppWindow.Move(new(-30000,-30000));MainWindow.AppWindow.Resize(new(1900,1160));MainWindow.AppWindow.Show(false); var modes=Environment.GetCommandLineArgs(); if(modes.Contains("--engineering-grade-only"))result=await RunEngineeringGradeProbeAsync(directory); else if(modes.Contains("--system-atlas-only"))result=await RunSystemAtlasProbeAsync(directory); else if(modes.Contains("--system-map-composition-only"))result=await RunSystemCompositionProbeAsync(directory); else if(modes.Contains("--market-only"))result=await RunMarketPageProbeAsync(directory); else if(modes.Contains("--market-cache-settings-only"))result=await RunMarketCacheSettingsProbeAsync(directory); else if(modes.Contains("--activity-only"))result=await RunActivityLogProbeAsync(directory); else if(modes.Contains("--system-map-only"))result=await RunLocalSystemMapProbeAsync(directory); else if(modes.Contains("--trade-planner-only"))result=await RunTradePlannerProbeAsync(directory); else if(modes.Contains("--probe-hologram-detail"))result=await RunHologramDetailProbeAsync(directory); else if(modes.Contains("--refit-appearance-only"))result=await RunRefitAppearanceProbeAsync(directory); else if(modes.Contains("--checklist-only"))result=await RunFloatingChecklistProbeAsync(directory); else if(modes.Contains("--places-only"))result=await RunPlacesProbeAsync(directory); else if(modes.Contains("--probe-navigation-overlap"))result=await RunGalaxyUi0416ProbeAsync(directory); else if(modes.Contains("--probe-galaxy-nebula"))result=await RunGalaxyNebulaProbeAsync(directory); else result=await RunInterfaceRefinementProbeAsync(directory); } catch(Exception error){failure=error.ToString();} await File.WriteAllTextAsync(path,System.Text.Json.JsonSerializer.Serialize(new{result,failure,uiError=ViewModel.ErrorMessage,gameFlightCommandsInvoked=false,gameRestartInvoked=false},new System.Text.Json.JsonSerializerOptions{WriteIndented=true}));MainWindow.Close(); } private static async Task RunFloatingChecklistProbeAsync(string directory) { static void Require(bool value,string message){if(!value)throw new InvalidOperationException(message);} var original=ViewModel.UpgradeNeeds.Select(row=>row.Record).ToArray(); try { ViewModel.UpgradeNeeds.Apply([new("modifiedembeddedfirmware","Modified Embedded Firmware",35,0),new("nickel","Nickel",16,68),new("vanadium","Vanadium",5,15)]); Require(ViewModel.UpgradeMissingMaterialCount==1,"The badge must count one missing material type, not 35 units or three total types."); using var popup=new FloatingUpgradeList(WinRT.Interop.WindowNative.GetWindowHandle(MainWindow),0,0,hidden:true); popup.MoveTo(-30000,-30000);popup.Show();await Task.Delay(150); Require(popup.IsToolPopup&&popup.Panel.IsLoaded,"Checklist must remain a captionless native tool popup."); Require(Descendants(popup.Surface).OfType().Count(grip=>Microsoft.UI.Xaml.Automation.AutomationProperties.GetName(grip)=="拖动调整清单大小")==8,"All four edges and four corners need resize handles."); var initial=popup.Bounds; popup.TogglePin();Require(popup.IsPinned&&popup.NativeTopmost,"Pin must set native topmost."); popup.ResizeBy(FloatingUpgradeList.ResizeEdge.Right|FloatingUpgradeList.ResizeEdge.Bottom,150,120);await Task.Delay(80); var enlarged=popup.Bounds; Require(enlarged.X==initial.X&&enlarged.Y==initial.Y&&enlarged.Width==initial.Width+150&&enlarged.Height==initial.Height+120,"Right/bottom resize failed."); var scale=popup.Surface.XamlRoot.RasterizationScale; Require(Math.Abs(popup.Surface.ActualWidth*scale-enlarged.Width)<2&&Math.Abs(popup.Surface.ActualHeight*scale-enlarged.Height)<2,"XAML content did not follow the native window size."); foreach(var edges in new[]{FloatingUpgradeList.ResizeEdge.Left,FloatingUpgradeList.ResizeEdge.Right,FloatingUpgradeList.ResizeEdge.Top,FloatingUpgradeList.ResizeEdge.Bottom,FloatingUpgradeList.ResizeEdge.Left|FloatingUpgradeList.ResizeEdge.Top,FloatingUpgradeList.ResizeEdge.Right|FloatingUpgradeList.ResizeEdge.Top,FloatingUpgradeList.ResizeEdge.Left|FloatingUpgradeList.ResizeEdge.Bottom,FloatingUpgradeList.ResizeEdge.Right|FloatingUpgradeList.ResizeEdge.Bottom}) { var before=popup.Bounds;popup.ResizeBy(edges,edges.HasFlag(FloatingUpgradeList.ResizeEdge.Left)?-16:16,edges.HasFlag(FloatingUpgradeList.ResizeEdge.Top)?-12:12);await Task.Delay(25);var after=popup.Bounds; Require(after.Width==before.Width+((edges&(FloatingUpgradeList.ResizeEdge.Left|FloatingUpgradeList.ResizeEdge.Right))!=0?16:0)&&after.Height==before.Height+((edges&(FloatingUpgradeList.ResizeEdge.Top|FloatingUpgradeList.ResizeEdge.Bottom))!=0?12:0),"Resize failed for "+edges); Require(edges.HasFlag(FloatingUpgradeList.ResizeEdge.Left)?after.X+after.Width==before.X+before.Width:after.X==before.X,"Opposite horizontal edge moved for "+edges); Require(edges.HasFlag(FloatingUpgradeList.ResizeEdge.Top)?after.Y+after.Height==before.Y+before.Height:after.Y==before.Y,"Opposite vertical edge moved for "+edges); } await CaptureRefinementElementAsync(popup.Surface,Path.Combine(directory,"checklist-enlarged.png")); popup.ResizeBy(FloatingUpgradeList.ResizeEdge.Right|FloatingUpgradeList.ResizeEdge.Bottom,-100000,-100000);await Task.Delay(100); var minimum=popup.Bounds;scale=popup.Surface.XamlRoot.RasterizationScale; Require(Math.Abs(minimum.Width/scale-FloatingUpgradeList.MinimumWidth)<2&&Math.Abs(minimum.Height/scale-FloatingUpgradeList.MinimumHeight)<2,"Minimum readable size was not enforced."); var scroller=(ScrollViewer)popup.Panel.FindName("UpgradePreviewScroller");Require(scroller.ActualHeight>30,"Minimum-size checklist has no material viewport."); var bottom=new Windows.Foundation.Point(0,popup.Panel.ActualHeight);var windowBottom=popup.Panel.TransformToVisual(popup.Surface).TransformPoint(bottom); Require(windowBottom.Y<=popup.Surface.ActualHeight,"Details button overflowed the resized window."); Require(popup.IsPinned&&popup.NativeTopmost&&popup.IsToolPopup,"Resizing must retain topmost and popup styling."); await CaptureRefinementElementAsync(popup.Surface,Path.Combine(directory,"checklist-minimum.png")); popup.TogglePin();Require(!popup.IsPinned&&!popup.NativeTopmost,"Unpin must still work after resize."); ViewModel.UpgradeNeeds.Apply([new("nickel","Nickel",16,68)]);Require(ViewModel.UpgradeMissingMaterialCount==0&&!ViewModel.HasUpgradeMaterialShortages,"Complete materials must hide the badge."); return new{missingTypesBadge=1,allEightResizeDirections=true,minimumSizeEnforced=true,contentResizes=true,pinningRetained=true,captionlessPopupRetained=true,initial=new{initial.Width,initial.Height},enlarged=new{enlarged.Width,enlarged.Height},minimum=new{minimum.Width,minimum.Height},gameCommandsInvoked=false}; } finally{ViewModel.UpgradeNeeds.Apply(original);} } private static async Task RunInterfaceRefinementProbeAsync(string directory) { static void Require(bool value,string message){if(!value)throw new InvalidOperationException(message);} static void Invoke(Button button)=>((IInvokeProvider)new ButtonAutomationPeer(button).GetPattern(PatternInterface.Invoke)).Invoke(); async Task Open(Type type){AppShellPage.Current!.Navigate(type);await Task.Delay(180);return AppShellPage.Current.CurrentPage!;} var home=(MainPage)await Open(typeof(MainPage)); Require(!Descendants(home).OfType().Any(t=>t.Text=="本机档案已读取"),"Removed dashboard badge is still visible."); var dashboard=(StackPanel)home.FindName("DashboardContent"); Require(dashboard.Children.Last() is Border{Child:ShipStatusPanel},"Ship properties must be the final, full-width dashboard card."); Require(!Descendants(home).OfType().Any(t=>t.Text=="数据接入"),"Removed data-access card remains visible."); await Task.Delay(500); var shipProperties=(ShipStatusPanel)home.FindName("HomeShipStatus"); Require(((SelectorBar)shipProperties.FindName("StatusTabs")).Items.Count==4,"Ship specifications and power tab is missing."); shipProperties.StartBringIntoView(new BringIntoViewOptions{AnimationDesired=false});await Task.Delay(150); await CaptureRefinementElementAsync(shipProperties,Path.Combine(directory,"ship-properties.png")); var host=(StackPanel)home.FindName("DashboardContent");var fixture=new StackPanel{Spacing=12};host.Children.Insert(0,fixture); var idle=new StackPanel();idle.Children.Add(new TextBlock{Text="异步操作检查"}); var button=new Button{Content=idle};fixture.Children.Add(button);var cancelled=0; var action=new AsyncRelayCommand(async token=>{try{await Task.Delay(Timeout.Infinite,token);}catch(OperationCanceledException){cancelled++;}}); AsyncAction.SetCommand(button,action);await Task.Delay(50);Invoke(button);await Task.Delay(50); Require(action.IsRunning&&button.Content as string=="取消"&&button.IsEnabled,"Running action must remain cancellable on the original button."); await CaptureRefinementElementAsync(button,Path.Combine(directory,"cancel-button.png"));Invoke(button);await action.ExecutionTask!.WaitAsync(TimeSpan.FromSeconds(3));await Task.Delay(40); Require(cancelled==1&&!action.IsRunning&&ReferenceEquals(button.Content,idle),"Cancellation did not restore original content."); var finish=new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);var bar=new AppBarButton{Label="载入附近星系",Icon=new SymbolIcon(Symbol.Download)};fixture.Children.Add(bar); var explicitAction=new AsyncRelayCommand(()=>finish.Task);AsyncAction.SetCommand(bar,explicitAction);AsyncAction.SetCancelCommand(bar,new RelayCommand(()=>finish.TrySetResult()));await Task.Delay(30);Invoke(bar);await Task.Delay(30); Require(bar.Label=="取消"&&bar.IsEnabled,"Command bar must offer cancellation on its original button."); Invoke(bar);await explicitAction.ExecutionTask!.WaitAsync(TimeSpan.FromSeconds(3));await Task.Delay(30);Require(bar.Label=="载入附近星系","Command bar label did not restore."); var deferred=new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);var deferredAction=new AsyncRelayCommand(()=>deferred.Task); AsyncAction.SetCommand(button,deferredAction);Invoke(button);await Task.Delay(30);fixture.Children.Remove(button);deferred.SetResult();await deferredAction.ExecutionTask!; fixture.Children.Add(button);await Task.Delay(40);Require(ReferenceEquals(button.Content,idle),"Unloaded action retained its cancel state on return."); fixture.Children.Clear();var gallery=new StackPanel{Orientation=Orientation.Horizontal,Spacing=16};fixture.Children.Add(gallery);var opened=0;var failures=new List(); void AddIcon(UserControl control,string label) { var image=(Image)control.Content;image.ImageOpened+=(_,_)=>opened++;image.ImageFailed+=(_,error)=>failures.Add(label+": "+error.ErrorMessage); var panel=new StackPanel{Spacing=8,Width=64};panel.Children.Add(control);panel.Children.Add(new TextBlock{Text=label});gallery.Children.Add(panel); } foreach(var category in new[]{"Raw","Manufactured","Encoded"})AddIcon(new MaterialIcon{Category=category},category); for(var grade=1;grade<=5;grade++)AddIcon(new MaterialGradeIcon{Grade=grade},$"G{grade}"); var deadline=DateTimeOffset.UtcNow.AddSeconds(4);while(opened<8&&failures.Count==0&&DateTimeOffset.UtcNow{planned++;map.Planning=true;};map.BeginPointer(centreAfter,false);await Task.Delay(270); Require(map.ShowsHold&&map.HoldProgress is >10 and <90,"Long press must animate progress around the selected star."); await CaptureRefinementElementAsync(map,Path.Combine(directory,"map-hold-progress.png"));await Task.Delay(430);map.EndPointer(centreAfter); Require(planned==1&&map.ShowsPlanning,"Long press must submit once and display planning until confirmation.");await Task.Delay(80);map.Planning=false; Require(!map.ShowsPlanning&&!map.ShowsHold,"Confirmed planning must clear the pending ring.");map.ClearSelection();Require(map.Selection is null,"Selection must be cancellable."); map.Systems=BenchmarkSystems(25000);map.Centre=new(0,0,0);map.RenderNowForProbe();var sceneBuilds=map.SceneRebuilds;var vectorNodes=map.VectorNodesCreated;var cpu=new double[90]; for(var i=0;is.Module?.Engineering?.Quality is not null);ViewModel.RefitSlot=slot;ViewModel.RefitGrade=5; var slots=(GridView)editor.FindName("SlotList");slots.ScrollIntoView(slot);await Task.Delay(100); var container=slots.ContainerFromItem(slot);var property=ViewModel.RefitProperties.Single(p=>p.OriginalName=="Integrity");var blueprint=ViewModel.RefitBlueprint;var effect=ViewModel.RefitEffect?.Key; var p=ViewModel.CurrentPlayer;var old=slot.Module!;var changed=old with{Health=.123,AmmoInClip=9,AmmoInHopper=234,Engineering=old.Engineering! with{Quality=.81}}; var snapshot=p with{Ships=p.Ships.Select(s=>s.ShipId==ViewModel.RefitDocument!.ShipId?s with{Modules=s.Modules.Select(m=>m.Slot==slot.Slot?changed:m).ToArray()}:s).ToArray()}; ViewModel.RefreshRefitProbePlayer(snapshot);await Task.Delay(100); var ring=(ProgressRing)editor.FindName("CurrentEngineeringProgress"); Require(ViewModel.RefitDocument!.Slots.First(s=>s.Slot==slot.Slot).Target?.Grade==5&&!Descendants(editor).OfType