XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Globalization;
using System.Text.Json;
using XFEEDToolBox.Core.Localization;
using XFEEDToolBox.Core.Models;

namespace XFEEDToolBox.Core.Galaxy;

public enum GatheringCategory { Manufactured, Raw, Encoded }
public sealed record GatheringMaterial(string Name)
{
    public string DisplayName=>ChineseNames.Translate(Name) is var n&&n!="未收录名称"?n:Name;
    public string OriginalName=>DisplayName==Name?"":Name;
}
public sealed record ManufacturedGatheringRule(string Material,string[] Allegiances,string[] States)
{
    public string Description=>string.Join(" / ",Allegiances)+" · "+string.Join(" / ",States);
}
public sealed record RawGatheringSite(string Name,string SystemName,Coordinates Position,long SystemAddress,string Body,
    double Latitude,double Longitude,double FinishLatitude,double FinishLongitude,string[] Materials)
{
    public GalacticPlace Place(Coordinates origin)=>new(Name,SystemName,Position,SystemAddress,origin.DistanceTo(Position),
        FormattableString.Invariant($"{Body} · 起点 {Latitude:F2}°, {Longitude:F2}° · 终点 {FinishLatitude:F2}°, {FinishLongitude:F2}°"),"用户提供的脑树采集点 · 地表坐标见原图",Source:"脑树采集点目录");
}

/// <summary>Collection locations and HGE conditions supplied by the user. Does not create or execute a flight route.</summary>
public sealed class MaterialGathering(HttpClient http)
{
    public static IReadOnlyList<ManufacturedGatheringRule> Manufactured {get;}=[
        new("Core Dynamics Composites",["Federation"],["Election","None"]),
        new("Military Grade Alloys",["Independent","Alliance"],["War","Civil War"]),
        new("Military Supercapacitors",["Independent","Alliance"],["War","Civil War"]),
        new("Improvised Components",["Independent","Alliance"],["Civil Unrest"]),
        new("Imperial Shielding",["Empire"],["Election","None"]),
        new("Pharmaceutical Isolators",["Independent","Alliance"],["Outbreak"]),
        new("Proto Heat Radiators",["Independent","Alliance"],["Boom","None"]),
        new("Proto Radiolic Alloys",["Independent","Alliance"],["Boom","None"])];
    public static IReadOnlyList<RawGatheringSite> RawSites {get;}=[
        new("Selenium Smudge","HR 3230",new(394.15625,19.25,-152.375),182359951707,"3 a a",52.64,-165.74,52.71,-165.93,["Selenium","Manganese","Zirconium"]),
        new("Triple T Ridge","Wregoe SB-Z b41-2",new(415.375,19.40625,-145.1875),5074638218601,"A 1 a",-50.94,165.18,-51.02,164.65,["Technetium","Tin","Tungsten","Chromium","Manganese","Zinc"]),
        new("Antimony Snow Man","HIP 34958",new(369.1875,-109.28125,-68.625),491597564259,"AB 1 a",-15.73,35.43,-15.61,35.49,["Antimony","Niobium","Tungsten","Chromium","Germanium","Vanadium"]),
        new("Ruthenium Double Dot","HIP 34958",new(369.1875,-109.28125,-68.625),491597564259,"AB 1 d a",6.70,-47.07,6.62,-47.42,["Ruthenium","Tin","Mercury","Chromium","Germanium","Zinc"]),
        new("Tellurium Valley","Synuefe FS-X b48-1",new(364.09375,-89.84375,-13.71875),2874809263521,"A 1 a",39.99,72.39,40.16,72.27,["Tellurium","Cadmium","Tungsten","Chromium","Germanium","Zirconium"]),
        new("Polonium Tire Tread","Synuefe BY-F d12-39",new(381.3125,-71.4375,-7.25),1350591039851,"A 2",35.60,45.99,35.76,46.79,["Polonium","Molybdenum","Mercury","Chromium","Zinc","Vanadium"]),
        new("Yttrium Pepsi Crater","Synuefe AN-H d11-101",new(432.625,-129.28125,-90.15625),3480911579491,"AB 1 c",65.57,-46.12,65.60,-46.27,["Yttrium","Cadmium","Niobium","Chromium","Manganese"])];
    public static IReadOnlyList<GatheringMaterial> Choices(GatheringCategory category)=>(category switch
    {
        GatheringCategory.Manufactured=>Manufactured.Select(r=>r.Material),
        GatheringCategory.Raw=>RawSites.SelectMany(r=>r.Materials),
        _=>Enumerable.Empty<string>()
    }).Distinct(StringComparer.OrdinalIgnoreCase).Order(StringComparer.OrdinalIgnoreCase).Select(n=>new GatheringMaterial(n)).ToArray();
    public static IReadOnlyList<GalacticPlace> FixedPlaces(GatheringCategory category,string material,Coordinates origin)
    {
        if(!origin.IsValid)throw new ArgumentException("尚未读取当前位置。");
        if(category==GatheringCategory.Encoded)
            return [new("Jameson 坠毁点","HIP 12099",new(-101.90625,-95.46875,-165.59375),560216394075,
                origin.DistanceTo(new(-101.90625,-95.46875,-165.59375)),"1 B · 纬度 -54.3803° · 经度 -50.3575° · 扫描坠毁点数据信标",
                "Jameson Crash Site · 地表数据采集点",Source:"Jameson 坠毁点目录")];
        if(category!=GatheringCategory.Raw)throw new ArgumentException("该类别需要实时搜索。");
        return RawSites.Where(s=>s.Materials.Contains(material,StringComparer.OrdinalIgnoreCase)).Select(s=>s.Place(origin)).OrderBy(p=>p.Distance).ThenBy(p=>p.Name).ToArray();
    }
    public static ManufacturedGatheringRule Rule(string material)=>Manufactured.FirstOrDefault(r=>r.Material.Equals(material,StringComparison.OrdinalIgnoreCase))??throw new ArgumentException("请选择表内的 G5 人造材料。");
    public static object Request(string material,Coordinates origin)
    {
        if(!origin.IsValid)throw new ArgumentException("尚未读取当前位置。");
        var rule=Rule(material);
        return new{filters=new{allegiance=new{value=rule.Allegiances},minor_faction_presences=new[]{new{state=new{value=rule.States}}}},
            sort=new[]{new{distance=new{direction="asc"}}},size=20,page=0,reference_coords=new{x=origin.X,y=origin.Y,z=origin.Z}};
    }
    public async Task<IReadOnlyList<GalacticPlace>> SearchManufacturedAsync(string material,Coordinates origin,CancellationToken token=default)
    {
        using var json=await PlaceSearchHttp.ReadAsync(http,"https://spansh.co.uk/api/systems/search",Request(material,origin),token).ConfigureAwait(false);
        token.ThrowIfCancellationRequested();return ParseManufactured(json.RootElement,material,origin);
    }
    public static IReadOnlyList<GalacticPlace> ParseManufactured(JsonElement root,string material,Coordinates origin)
    {
        var rule=Rule(material);
        if(!root.TryGetProperty("results",out var rows)||rows.ValueKind!=JsonValueKind.Array)throw new InvalidDataException("材料搜索未返回有效结果。");
        var found=new List<GalacticPlace>();
        foreach(var row in rows.EnumerateArray().Take(100))
        {
            string S(string key)=>row.TryGetProperty(key,out var v)&&v.ValueKind==JsonValueKind.String?v.GetString()??"":"";
            var allegiance=S("allegiance");
            if(!rule.Allegiances.Contains(allegiance,StringComparer.OrdinalIgnoreCase)||S("name").Length==0)continue;
            string? state=null;string faction="";
            if(row.TryGetProperty("minor_faction_presences",out var factions)&&factions.ValueKind==JsonValueKind.Array)
            foreach(var presence in factions.EnumerateArray())
            {
                // Only the current faction state qualifies; pending/recovering states do not.
                if(!presence.TryGetProperty("state",out var current)||current.ValueKind!=JsonValueKind.String)continue;
                var value=current.GetString()!;if(!rule.States.Contains(value,StringComparer.OrdinalIgnoreCase))continue;
                state=value;faction=presence.TryGetProperty("name",out var n)&&n.ValueKind==JsonValueKind.String?n.GetString()??"":"";break;
            }
            if(state is null)continue;
            if(!row.TryGetProperty("x",out var x)||!x.TryGetDouble(out var xx)||!row.TryGetProperty("y",out var y)||!y.TryGetDouble(out var yy)||!row.TryGetProperty("z",out var z)||!z.TryGetDouble(out var zz))continue;
            var position=new Coordinates(xx,yy,zz);if(!position.IsValid)continue;
            long? id=row.TryGetProperty("id64",out var a)&&a.TryGetInt64(out var address)&&address>0?address:null;
            var updated=S("updated_at");var stamp=DateTimeOffset.TryParse(updated,CultureInfo.InvariantCulture,DateTimeStyles.AssumeUniversal,out var at)?$"势力记录于 {at.ToLocalTime():MM-dd HH:mm}":"势力更新时间未提供";
            found.Add(new(material+" · 高等级信号候选",S("name"),position,id,origin.DistanceTo(position),allegiance+" · "+faction+" · "+state,stamp+" · 到达后扫描 HGE,掉落以游戏为准",Source:"Spansh 材料候选星系"));
        }
        return found.DistinctBy(p=>p.SystemName,StringComparer.OrdinalIgnoreCase).OrderBy(p=>p.Distance).Take(1).ToArray();
    }
}