using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Localization;
namespace XFEEDToolBox.ViewModels;
public sealed record GalacticPlaceChoice(string Name)
{
public string DisplayName=>ChineseNames.Translate(Name) is var n&&n!="未收录名称"?n:Name;
public string OriginalName=>DisplayName==Name?"":Name;
}
public partial class ToolboxViewModel
{
private readonly Dictionary<GalacticPlaceKind,IReadOnlyList<string>> placeChoices=[];
private GalacticPlaces? placesClient;
private GalacticPlaces PlacesClient=>placesClient??=new(galaxyHttp);
private int placeSearchVersion;
[ObservableProperty,NotifyPropertyChangedFor(nameof(PlacesNeedTrader)),NotifyPropertyChangedFor(nameof(PlacesNeedEngineer)),NotifyPropertyChangedFor(nameof(PlacesNeedItem)),NotifyPropertyChangedFor(nameof(PlacesNeedModule)),NotifyPropertyChangedFor(nameof(PlacesNeedGathering)),NotifyPropertyChangedFor(nameof(PlacesNeedGatheringMaterial)),NotifyPropertyChangedFor(nameof(PlacesAllowPadFilter))]
public partial int GalaxyPlaceKindIndex {get;set;}
public bool PlacesNeedTrader=>GalaxyPlaceKindIndex==0;
public bool PlacesNeedEngineer=>GalaxyPlaceKindIndex==2;
public bool PlacesNeedItem=>GalaxyPlaceKindIndex is >=3 and <=5;
public bool PlacesNeedModule=>GalaxyPlaceKindIndex==4;
public bool PlacesNeedGathering=>GalaxyPlaceKindIndex==6;
public bool PlacesNeedGatheringMaterial=>PlacesNeedGathering&&GalaxyGatheringCategoryIndex!=2;
public bool PlacesAllowPadFilter=>!PlacesNeedGathering&&GalaxyPlaceKindIndex!=2;
[ObservableProperty,NotifyPropertyChangedFor(nameof(PlacesNeedGatheringMaterial)),NotifyPropertyChangedFor(nameof(GalaxyGatheringChoices)),NotifyPropertyChangedFor(nameof(GalaxyGatheringHint))]
public partial int GalaxyGatheringCategoryIndex {get;set;}
[ObservableProperty,NotifyPropertyChangedFor(nameof(GalaxyGatheringHint))] public partial GatheringMaterial? GalaxyGatheringMaterial {get;set;}=MaterialGathering.Choices(GatheringCategory.Manufactured).FirstOrDefault();
public IReadOnlyList<GatheringMaterial> GalaxyGatheringChoices=>MaterialGathering.Choices((GatheringCategory)Math.Clamp(GalaxyGatheringCategoryIndex,0,2));
public string GalaxyGatheringHint=>GalaxyGatheringCategoryIndex switch
{
0=>"G5 人造材料 · "+(GalaxyGatheringMaterial is {} m?MaterialGathering.Rule(m.Name).Description: "请选择材料")+";按星系势力与派系当前状态筛选最近候选,抵达后扫描高等级信号。",
1=>"按所选材料筛选图中的脑树采集点,按当前位置距离排序;结果包含行星及起止地表坐标。",
_=>"Jameson 坠毁点 · HIP 12099 1 B · 扫描数据信标;可在数据贸易商兑换其他数据。"
};
partial void OnGalaxyGatheringCategoryIndexChanged(int value)
{
GalaxyGatheringMaterial=GalaxyGatheringChoices.FirstOrDefault();InvalidateGatheringResults();
}
partial void OnGalaxyGatheringMaterialChanged(GatheringMaterial? value)=>InvalidateGatheringResults();
private void InvalidateGatheringResults()
{
placeSearchVersion++;
if(SearchGalacticPlacesCommand.IsRunning)SearchGalacticPlacesCommand.Cancel();
GalaxyPlaces=[];GalaxyPlacesStatus="以当前位置查找材料采集点。";
}
[ObservableProperty] public partial int GalaxyTraderIndex {get;set;}
[ObservableProperty] public partial int GalaxyModuleClassIndex {get;set;}
[ObservableProperty] public partial string GalaxyModuleRating {get;set;}="全部";
[ObservableProperty] public partial bool GalaxyPlaceLargePad {get;set;}
[ObservableProperty] public partial string GalaxyPlaceQuery {get;set;}="";
[ObservableProperty] public partial bool GalaxyPlacesBusy {get;set;}
[ObservableProperty] public partial string GalaxyPlacesStatus {get;set;}="以当前位置查找;商品与装配库存以最新采集记录为准。";
[ObservableProperty] public partial IReadOnlyList<GalacticPlace> GalaxyPlaces {get;set;}=[];
[ObservableProperty] public partial EngineerLocation? GalaxyEngineer {get;set;}=EngineerDirectory.All.FirstOrDefault(e=>e.Name.StartsWith("Tod "));
public IReadOnlyList<EngineerLocation> GalaxyEngineers=>EngineerDirectory.All;
public IReadOnlyList<string> GalaxyModuleClasses {get;}=["全部","0","1","2","3","4","5","6","7","8"];
public IReadOnlyList<string> GalaxyModuleRatings {get;}=["全部","A","B","C","D","E","F","G","H","I"];
private void InvalidatePlaceResults()
{
placeSearchVersion++;if(SearchGalacticPlacesCommand.IsRunning)SearchGalacticPlacesCommand.Cancel();
GalaxyPlaces=[];GalaxyPlacesStatus="以当前位置查找;商品与装配库存以最新采集记录为准。";
}
partial void OnGalaxyPlaceKindIndexChanged(int value){InvalidatePlaceResults();GalaxyPlaceQuery="";if(value==6)GalaxyPlacesStatus="选择材料类别和材料后查找采集点。";}
partial void OnGalaxyTraderIndexChanged(int value)=>InvalidatePlaceResults();
partial void OnGalaxyModuleClassIndexChanged(int value)=>InvalidatePlaceResults();
partial void OnGalaxyModuleRatingChanged(string value)=>InvalidatePlaceResults();
partial void OnGalaxyPlaceLargePadChanged(bool value)=>InvalidatePlaceResults();
partial void OnGalaxyPlaceQueryChanged(string value)=>InvalidatePlaceResults();
partial void OnGalaxyEngineerChanged(EngineerLocation? value)=>InvalidatePlaceResults();
internal async Task<IReadOnlyList<GalacticPlaceChoice>> SuggestPlacesAsync(string query,CancellationToken token)
{
if(!PlacesNeedItem)return [];
var kind=(GalacticPlaceKind)GalaxyPlaceKindIndex;
if(!placeChoices.TryGetValue(kind,out var values))placeChoices[kind]=values=await PlacesClient.ChoicesAsync(kind,token);
token.ThrowIfCancellationRequested();query=query.Trim();
return values.Select(s=>new GalacticPlaceChoice(s)).Where(c=>c.Name.Contains(query,StringComparison.OrdinalIgnoreCase)||c.DisplayName.Contains(query,StringComparison.OrdinalIgnoreCase)).ToArray();
}
[RelayCommand] private async Task SearchGalacticPlacesAsync(CancellationToken cancellationToken=default)
{
using var stop=CancellationTokenSource.CreateLinkedTokenSource(lifetime.Token,cancellationToken);var token=stop.Token;var version=placeSearchVersion;GalaxyPlacesBusy=true;
try
{
var origin=CurrentPlayer.Position??throw new InvalidOperationException("尚未读取当前星系坐标。");
var kind=(GalacticPlaceKind)Math.Clamp(GalaxyPlaceKindIndex,0,6);
IReadOnlyList<GalacticPlace> results;
if(kind==GalacticPlaceKind.MaterialGathering)
{
var category=(GatheringCategory)Math.Clamp(GalaxyGatheringCategoryIndex,0,2);
var material=GalaxyGatheringMaterial?.Name??"";GalaxyPlacesStatus="正在查找最近材料采集点…";
results=category==GatheringCategory.Manufactured
?await new MaterialGathering(galaxyHttp).SearchManufacturedAsync(material,origin,token)
:MaterialGathering.FixedPlaces(category,material,origin);
}
else if(kind==GalacticPlaceKind.Engineer)
{
var engineer=GalaxyEngineer??throw new InvalidOperationException("请先选择工程师。");
results=[new(engineer.DisplayName,engineer.SystemName,engineer.Position,null,origin.DistanceTo(engineer.Position),engineer.BaseName+" · "+engineer.Body,"工程师驻地",engineer.Portrait)];
}
else
{
var value=kind==GalacticPlaceKind.MaterialTrader?new[]{"Raw","Manufactured","Encoded"}[Math.Clamp(GalaxyTraderIndex,0,2)]:GalaxyPlaceQuery;
GalaxyPlacesStatus="正在查找最近地点…";
results=await PlacesClient.SearchAsync(kind,value,origin,GalaxyModuleClassIndex==0?null:GalaxyModuleClassIndex-1,GalaxyModuleRating=="全部"?"":GalaxyModuleRating,GalaxyPlaceLargePad,token);
}
token.ThrowIfCancellationRequested();GalaxyPlaces=results;
foreach(var result in results)galaxyCache[result.SystemName]=result.System;
PublishGalaxy();
GalaxyPlacesStatus=results.Count>0?$"找到 {results.Count} 个地点 · 按距离排序"+(kind is GalacticPlaceKind.Engineer or GalacticPlaceKind.MaterialGathering?"":" · Spansh 采集数据"):
kind==GalacticPlaceKind.MaterialGathering?"未找到符合材料筛选条件的已上报星系。":"没有符合条件的已上报站点。";
if(results.FirstOrDefault() is {} first)ShowGalacticPlace(first);
}
catch(OperationCanceledException){if(version==placeSearchVersion)GalaxyPlacesStatus="地点查找已取消。";}
catch(Exception error){if(version==placeSearchVersion)GalaxyPlacesStatus="地点查找未完成:"+error.Message;}
finally{GalaxyPlacesBusy=false;}
}
internal void ShowGalacticPlace(GalacticPlace place)
{
galaxyCache[place.SystemName]=place.System;GalaxySelection=place.System;GalaxyCentre=place.Position;PublishGalaxy();
}
}
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Localization;
namespace XFEEDToolBox.ViewModels;
public sealed record GalacticPlaceChoice(string Name)
{
public string DisplayName=>ChineseNames.Translate(Name) is var n&&n!="未收录名称"?n:Name;
public string OriginalName=>DisplayName==Name?"":Name;
}
public partial class ToolboxViewModel
{
private readonly Dictionary<GalacticPlaceKind,IReadOnlyList<string>> placeChoices=[];
private GalacticPlaces? placesClient;
private GalacticPlaces PlacesClient=>placesClient??=new(galaxyHttp);
private int placeSearchVersion;
[ObservableProperty,NotifyPropertyChangedFor(nameof(PlacesNeedTrader)),NotifyPropertyChangedFor(nameof(PlacesNeedEngineer)),NotifyPropertyChangedFor(nameof(PlacesNeedItem)),NotifyPropertyChangedFor(nameof(PlacesNeedModule)),NotifyPropertyChangedFor(nameof(PlacesNeedGathering)),NotifyPropertyChangedFor(nameof(PlacesNeedGatheringMaterial)),NotifyPropertyChangedFor(nameof(PlacesAllowPadFilter))]
public partial int GalaxyPlaceKindIndex {get;set;}
public bool PlacesNeedTrader=>GalaxyPlaceKindIndex==0;
public bool PlacesNeedEngineer=>GalaxyPlaceKindIndex==2;
public bool PlacesNeedItem=>GalaxyPlaceKindIndex is >=3 and <=5;
public bool PlacesNeedModule=>GalaxyPlaceKindIndex==4;
public bool PlacesNeedGathering=>GalaxyPlaceKindIndex==6;
public bool PlacesNeedGatheringMaterial=>PlacesNeedGathering&&GalaxyGatheringCategoryIndex!=2;
public bool PlacesAllowPadFilter=>!PlacesNeedGathering&&GalaxyPlaceKindIndex!=2;
[ObservableProperty,NotifyPropertyChangedFor(nameof(PlacesNeedGatheringMaterial)),NotifyPropertyChangedFor(nameof(GalaxyGatheringChoices)),NotifyPropertyChangedFor(nameof(GalaxyGatheringHint))]
public partial int GalaxyGatheringCategoryIndex {get;set;}
[ObservableProperty,NotifyPropertyChangedFor(nameof(GalaxyGatheringHint))] public partial GatheringMaterial? GalaxyGatheringMaterial {get;set;}=MaterialGathering.Choices(GatheringCategory.Manufactured).FirstOrDefault();
public IReadOnlyList<GatheringMaterial> GalaxyGatheringChoices=>MaterialGathering.Choices((GatheringCategory)Math.Clamp(GalaxyGatheringCategoryIndex,0,2));
public string GalaxyGatheringHint=>GalaxyGatheringCategoryIndex switch
{
0=>"G5 人造材料 · "+(GalaxyGatheringMaterial is {} m?MaterialGathering.Rule(m.Name).Description: "请选择材料")+";按星系势力与派系当前状态筛选最近候选,抵达后扫描高等级信号。",
1=>"按所选材料筛选图中的脑树采集点,按当前位置距离排序;结果包含行星及起止地表坐标。",
_=>"Jameson 坠毁点 · HIP 12099 1 B · 扫描数据信标;可在数据贸易商兑换其他数据。"
};
partial void OnGalaxyGatheringCategoryIndexChanged(int value)
{
GalaxyGatheringMaterial=GalaxyGatheringChoices.FirstOrDefault();InvalidateGatheringResults();
}
partial void OnGalaxyGatheringMaterialChanged(GatheringMaterial? value)=>InvalidateGatheringResults();
private void InvalidateGatheringResults()
{
placeSearchVersion++;
if(SearchGalacticPlacesCommand.IsRunning)SearchGalacticPlacesCommand.Cancel();
GalaxyPlaces=[];GalaxyPlacesStatus="以当前位置查找材料采集点。";
}
[ObservableProperty] public partial int GalaxyTraderIndex {get;set;}
[ObservableProperty] public partial int GalaxyModuleClassIndex {get;set;}
[ObservableProperty] public partial string GalaxyModuleRating {get;set;}="全部";
[ObservableProperty] public partial bool GalaxyPlaceLargePad {get;set;}
[ObservableProperty] public partial string GalaxyPlaceQuery {get;set;}="";
[ObservableProperty] public partial bool GalaxyPlacesBusy {get;set;}
[ObservableProperty] public partial string GalaxyPlacesStatus {get;set;}="以当前位置查找;商品与装配库存以最新采集记录为准。";
[ObservableProperty] public partial IReadOnlyList<GalacticPlace> GalaxyPlaces {get;set;}=[];
[ObservableProperty] public partial EngineerLocation? GalaxyEngineer {get;set;}=EngineerDirectory.All.FirstOrDefault(e=>e.Name.StartsWith("Tod "));
public IReadOnlyList<EngineerLocation> GalaxyEngineers=>EngineerDirectory.All;
public IReadOnlyList<string> GalaxyModuleClasses {get;}=["全部","0","1","2","3","4","5","6","7","8"];
public IReadOnlyList<string> GalaxyModuleRatings {get;}=["全部","A","B","C","D","E","F","G","H","I"];
private void InvalidatePlaceResults()
{
placeSearchVersion++;if(SearchGalacticPlacesCommand.IsRunning)SearchGalacticPlacesCommand.Cancel();
GalaxyPlaces=[];GalaxyPlacesStatus="以当前位置查找;商品与装配库存以最新采集记录为准。";
}
partial void OnGalaxyPlaceKindIndexChanged(int value){InvalidatePlaceResults();GalaxyPlaceQuery="";if(value==6)GalaxyPlacesStatus="选择材料类别和材料后查找采集点。";}
partial void OnGalaxyTraderIndexChanged(int value)=>InvalidatePlaceResults();
partial void OnGalaxyModuleClassIndexChanged(int value)=>InvalidatePlaceResults();
partial void OnGalaxyModuleRatingChanged(string value)=>InvalidatePlaceResults();
partial void OnGalaxyPlaceLargePadChanged(bool value)=>InvalidatePlaceResults();
partial void OnGalaxyPlaceQueryChanged(string value)=>InvalidatePlaceResults();
partial void OnGalaxyEngineerChanged(EngineerLocation? value)=>InvalidatePlaceResults();
internal async Task<IReadOnlyList<GalacticPlaceChoice>> SuggestPlacesAsync(string query,CancellationToken token)
{
if(!PlacesNeedItem)return [];
var kind=(GalacticPlaceKind)GalaxyPlaceKindIndex;
if(!placeChoices.TryGetValue(kind,out var values))placeChoices[kind]=values=await PlacesClient.ChoicesAsync(kind,token);
token.ThrowIfCancellationRequested();query=query.Trim();
return values.Select(s=>new GalacticPlaceChoice(s)).Where(c=>c.Name.Contains(query,StringComparison.OrdinalIgnoreCase)||c.DisplayName.Contains(query,StringComparison.OrdinalIgnoreCase)).ToArray();
}
[RelayCommand] private async Task SearchGalacticPlacesAsync(CancellationToken cancellationToken=default)
{
using var stop=CancellationTokenSource.CreateLinkedTokenSource(lifetime.Token,cancellationToken);var token=stop.Token;var version=placeSearchVersion;GalaxyPlacesBusy=true;
try
{
var origin=CurrentPlayer.Position??throw new InvalidOperationException("尚未读取当前星系坐标。");
var kind=(GalacticPlaceKind)Math.Clamp(GalaxyPlaceKindIndex,0,6);
IReadOnlyList<GalacticPlace> results;
if(kind==GalacticPlaceKind.MaterialGathering)
{
var category=(GatheringCategory)Math.Clamp(GalaxyGatheringCategoryIndex,0,2);
var material=GalaxyGatheringMaterial?.Name??"";GalaxyPlacesStatus="正在查找最近材料采集点…";
results=category==GatheringCategory.Manufactured
?await new MaterialGathering(galaxyHttp).SearchManufacturedAsync(material,origin,token)
:MaterialGathering.FixedPlaces(category,material,origin);
}
else if(kind==GalacticPlaceKind.Engineer)
{
var engineer=GalaxyEngineer??throw new InvalidOperationException("请先选择工程师。");
results=[new(engineer.DisplayName,engineer.SystemName,engineer.Position,null,origin.DistanceTo(engineer.Position),engineer.BaseName+" · "+engineer.Body,"工程师驻地",engineer.Portrait)];
}
else
{
var value=kind==GalacticPlaceKind.MaterialTrader?new[]{"Raw","Manufactured","Encoded"}[Math.Clamp(GalaxyTraderIndex,0,2)]:GalaxyPlaceQuery;
GalaxyPlacesStatus="正在查找最近地点…";
results=await PlacesClient.SearchAsync(kind,value,origin,GalaxyModuleClassIndex==0?null:GalaxyModuleClassIndex-1,GalaxyModuleRating=="全部"?"":GalaxyModuleRating,GalaxyPlaceLargePad,token);
}
token.ThrowIfCancellationRequested();GalaxyPlaces=results;
foreach(var result in results)galaxyCache[result.SystemName]=result.System;
PublishGalaxy();
GalaxyPlacesStatus=results.Count>0?$"找到 {results.Count} 个地点 · 按距离排序"+(kind is GalacticPlaceKind.Engineer or GalacticPlaceKind.MaterialGathering?"":" · Spansh 采集数据"):
kind==GalacticPlaceKind.MaterialGathering?"未找到符合材料筛选条件的已上报星系。":"没有符合条件的已上报站点。";
if(results.FirstOrDefault() is {} first)ShowGalacticPlace(first);
}
catch(OperationCanceledException){if(version==placeSearchVersion)GalaxyPlacesStatus="地点查找已取消。";}
catch(Exception error){if(version==placeSearchVersion)GalaxyPlacesStatus="地点查找未完成:"+error.Message;}
finally{GalaxyPlacesBusy=false;}
}
internal void ShowGalacticPlace(GalacticPlace place)
{
galaxyCache[place.SystemName]=place.System;GalaxySelection=place.System;GalaxyCentre=place.Position;PublishGalaxy();
}
}