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.Navigation;

namespace XFEEDToolBox.Core.Galaxy;

public sealed record GalaxyAccountBookmark(string Uid,long SystemAddress,string SystemName,string Name,bool Squadron,bool Favourite)
{
    public uint Icon { get;init; }
}
public sealed record GalaxyColonisationClaim(long SystemAddress,ulong CommanderId,byte Status,bool Active);
public sealed record GalaxySocialLocation(long SystemAddress,string Kind,int Status,string StatusName,bool? LocationCurrent);
public sealed record GalaxyNativePowerOption(int Index,int UiPowerId,int InternalPowerId,string Name,float RawRed,float RawGreen,float RawBlue)
{
    public long? HeadquartersSystemAddress { get;init; }
}
public sealed record GalaxyNativePowerOptionsSnapshot(bool Available,IReadOnlyList<GalaxyNativePowerOption> Options)
{
    public bool OptionsComplete=>Available;
}
public sealed record GalaxySocialSnapshot(bool Available,bool FriendsReady,bool WingsReady,IReadOnlyList<GalaxySocialLocation> Locations)
{
    public bool Complete=>false;
}
public sealed record GalaxyColonisationSnapshot(bool Available,IReadOnlyList<GalaxyColonisationClaim> Claims)
{
    public bool Complete=>false;
}
public sealed record GalaxyAccountSnapshot(bool Available,IReadOnlyList<GalaxyAccountBookmark> Bookmarks,string Source)
{
    // The original manager snapshot currently supplies positive observations;
    // its empty vector cannot certify absence or full account coverage.
    public bool Complete=>false;
}

/// <summary>Reads only the plugin's already observed, owner-bound managed account snapshot.</summary>
public sealed partial class NativeGalaxyAccountCatalog(int processId)
{
    private readonly NavigationPipeClient pipe=new(processId);
    public async Task<GalaxyNativePowerOptionsSnapshot> ReadPowerOptionsAsync(CancellationToken token=default)
    {
        var page=await pipe.CallAsync(new{op="galaxy.powers",limit=16},token);
        if(!page.GetProperty("available").GetBoolean())return new(false,[]);
        var generation=page.GetProperty("generation").GetUInt64();var total=page.GetProperty("total").GetInt32();var entity=page.GetProperty("entityId").GetString();
        if(generation==0||total is <0 or >128||string.IsNullOrEmpty(entity))throw new InvalidDataException("原游戏势力选项快照无效。");
        var options=new List<GalaxyNativePowerOption>();var ids=new HashSet<int>();var offset=0;
        while(true)
        {
            token.ThrowIfCancellationRequested();
            if(!page.GetProperty("available").GetBoolean()||!page.GetProperty("optionsComplete").GetBoolean()||page.GetProperty("generation").GetUInt64()!=generation||page.GetProperty("entityId").GetString()!=entity||page.GetProperty("total").GetInt32()!=total)
                throw new InvalidDataException("原游戏势力选项快照已变化,请重试。");
            var rows=page.GetProperty("items");if(rows.ValueKind!=JsonValueKind.Array||rows.GetArrayLength()>16||offset+rows.GetArrayLength()>total)throw new InvalidDataException("原游戏势力选项分页无效。");
            foreach(var row in rows.EnumerateArray())
            {
                var index=row.GetProperty("index").GetInt32();var ui=row.GetProperty("uiPowerId").GetInt32();var id=row.GetProperty("internalPowerId").GetInt32();var name=row.GetProperty("name").GetString()??"";
                var red=row.GetProperty("rawRed").GetSingle();var green=row.GetProperty("rawGreen").GetSingle();var blue=row.GetProperty("rawBlue").GetSingle();
                if(index!=options.Count||ui!=index+1||id is <0 or >=128||!ids.Add(id)||string.IsNullOrWhiteSpace(name)||name.Length>512||!float.IsFinite(red)||!float.IsFinite(green)||!float.IsFinite(blue))throw new InvalidDataException("原游戏势力选项数据无效。");
                long? headquarters=null;
                if(row.TryGetProperty("headquartersSystemAddress",out var headquartersValue)&&headquartersValue.ValueKind!=JsonValueKind.Null)
                {
                    if(!long.TryParse(headquartersValue.GetString(),NumberStyles.None,CultureInfo.InvariantCulture,out var address)||address<=0||address>=1L<<55)
                        throw new InvalidDataException("原游戏势力总部地址无效。");
                    headquarters=address;
                }
                options.Add(new(index,ui,id,name,red,green,blue){HeadquartersSystemAddress=headquarters});
            }
            offset+=rows.GetArrayLength();if(offset==total)break;if(rows.GetArrayLength()==0)throw new InvalidDataException("原游戏势力选项分页未继续。");
            page=await pipe.CallAsync(new{op="galaxy.powers",generation,offset,limit=16},token);
        }
        return new(true,options);
    }
    public async Task<GalaxySocialSnapshot> ReadSocialAsync(CancellationToken token=default)
    {
        var page=await pipe.CallAsync(new{op="galaxy.social",limit=96},token);
        if(!page.GetProperty("available").GetBoolean())return new(false,false,false,[]);
        var generation=page.GetProperty("generation").GetUInt64();var total=page.GetProperty("total").GetInt32();var entity=page.GetProperty("entityId").GetString();
        var friendsReady=page.GetProperty("friendsReady").GetBoolean();var wingsReady=page.GetProperty("wingsReady").GetBoolean();
        if(generation==0||total is <0 or >20000||string.IsNullOrEmpty(entity)||!friendsReady&&!wingsReady)throw new InvalidDataException("原游戏社交位置快照无效。");
        var locations=new List<GalaxySocialLocation>();var offset=0;
        while(true)
        {
            token.ThrowIfCancellationRequested();
            if(!page.GetProperty("available").GetBoolean()||page.GetProperty("generation").GetUInt64()!=generation||page.GetProperty("entityId").GetString()!=entity||page.GetProperty("total").GetInt32()!=total||
               page.GetProperty("friendsReady").GetBoolean()!=friendsReady||page.GetProperty("wingsReady").GetBoolean()!=wingsReady)throw new InvalidDataException("原游戏社交位置快照已变化,请重试。");
            var rows=page.GetProperty("items");if(rows.ValueKind!=JsonValueKind.Array||rows.GetArrayLength()>96||offset+rows.GetArrayLength()>total)throw new InvalidDataException("原游戏社交位置分页无效。");
            foreach(var row in rows.EnumerateArray())
            {
                var kind=row.GetProperty("kind").GetString();var status=row.GetProperty("status").GetInt32();var name=row.GetProperty("statusName").GetString()??"";
                if(!long.TryParse(row.GetProperty("systemAddress").GetString(),NumberStyles.None,CultureInfo.InvariantCulture,out var id)||id<=0||id>=1L<<55||
                   kind is not("friend" or "wing")||kind=="friend"&&!friendsReady||kind=="wing"&&!wingsReady||kind=="friend"&&status is <0 or >13||name.Length>128)throw new InvalidDataException("原游戏社交位置记录无效。");
                var current=row.GetProperty("locationCurrent");bool? active=current.ValueKind==JsonValueKind.Null?null:current.ValueKind is JsonValueKind.True or JsonValueKind.False?current.GetBoolean():throw new InvalidDataException("原游戏社交位置时效状态无效。");
                locations.Add(new(id,kind!,status,name,active));
            }
            offset+=rows.GetArrayLength();if(offset==total)break;if(rows.GetArrayLength()==0)throw new InvalidDataException("原游戏社交位置分页未继续。");
            page=await pipe.CallAsync(new{op="galaxy.social",generation,offset,limit=96},token);
        }
        return new(true,friendsReady,wingsReady,locations.Distinct().ToArray());
    }
    public async Task<GalaxyColonisationSnapshot> ReadColonisationAsync(CancellationToken token=default)
    {
        var page=await pipe.CallAsync(new{op="galaxy.colonisation",limit=96},token);
        if(!page.GetProperty("available").GetBoolean())return new(false,[]);
        var generation=page.GetProperty("generation").GetUInt64();var total=page.GetProperty("total").GetInt32();var entity=page.GetProperty("entityId").GetString();
        if(generation==0||total is <0 or >16384||string.IsNullOrEmpty(entity))throw new InvalidDataException("原游戏殖民快照无效。");
        var claims=new List<GalaxyColonisationClaim>();var addresses=new HashSet<long>();var offset=0;
        while(true)
        {
            token.ThrowIfCancellationRequested();
            if(!page.GetProperty("available").GetBoolean()||page.GetProperty("generation").GetUInt64()!=generation||page.GetProperty("entityId").GetString()!=entity||page.GetProperty("total").GetInt32()!=total)throw new InvalidDataException("原游戏殖民快照已变化,请重试。");
            var rows=page.GetProperty("items");if(rows.ValueKind!=JsonValueKind.Array||rows.GetArrayLength()>96||offset+rows.GetArrayLength()>total)throw new InvalidDataException("原游戏殖民分页无效。");
            foreach(var row in rows.EnumerateArray())
            {
                if(!long.TryParse(row.GetProperty("systemAddress").GetString(),NumberStyles.None,CultureInfo.InvariantCulture,out var id)||id<=0||id>=1L<<55||!addresses.Add(id)||
                   !ulong.TryParse(row.GetProperty("commanderId").GetString(),NumberStyles.None,CultureInfo.InvariantCulture,out var commander))throw new InvalidDataException("原游戏殖民记录标识无效。");
                var status=row.GetProperty("status").GetByte();var active=row.GetProperty("active").GetBoolean();
                if(status>3||active!=(status is 1 or 2 or 3))throw new InvalidDataException("原游戏殖民状态无效。");
                claims.Add(new(id,commander,status,active));
            }
            offset+=rows.GetArrayLength();if(offset==total)break;if(rows.GetArrayLength()==0)throw new InvalidDataException("原游戏殖民分页未继续。");
            page=await pipe.CallAsync(new{op="galaxy.colonisation",generation,offset,limit=96},token);
        }
        return new(true,claims);
    }
    public async Task<GalaxyAccountSnapshot> ReadAsync(CancellationToken token=default)
    {
        var first=await pipe.CallAsync(new{op="galaxy.account",limit=16},token);
        if(!first.GetProperty("available").GetBoolean())return new(false,[],"original-bookmark-manager");
        var generation=first.GetProperty("generation").GetUInt64();var total=first.GetProperty("total").GetInt32();
        var entity=first.GetProperty("entityId").GetString();
        if(total is <0 or >4096||generation==0||string.IsNullOrEmpty(entity))throw new InvalidDataException("原游戏账户星图快照无效。");
        var bookmarks=new List<GalaxyAccountBookmark>();var identities=new HashSet<string>(StringComparer.Ordinal);var offset=0;var page=first;
        while(true)
        {
            token.ThrowIfCancellationRequested();
            if(!page.GetProperty("available").GetBoolean()||page.GetProperty("generation").GetUInt64()!=generation||page.GetProperty("entityId").GetString()!=entity||page.GetProperty("total").GetInt32()!=total)
                throw new InvalidDataException("原游戏账户星图快照已变化,请重试。");
            var rows=page.GetProperty("items");if(rows.ValueKind!=JsonValueKind.Array||rows.GetArrayLength()>16||offset+rows.GetArrayLength()>total)throw new InvalidDataException("原游戏账户星图分页无效。");
            foreach(var row in rows.EnumerateArray())
            {
                var address=row.GetProperty("systemAddress").GetString();var uid=row.GetProperty("uid").GetString()??"";var source=row.GetProperty("sourceKind").GetInt32();
                var systemName=row.GetProperty("systemName").GetString()??"";var name=row.GetProperty("name").GetString()??"";
                if(!long.TryParse(address,NumberStyles.None,CultureInfo.InvariantCulture,out var id)||id<=0||id>=1L<<55||!ulong.TryParse(uid,out _)||source is not(1 or 2)||name.Length>512||systemName.Length>512||!identities.Add(source+":"+uid))throw new InvalidDataException("原游戏账户书签数据无效。");
                var icon=row.TryGetProperty("icon",out var iconValue)&&iconValue.TryGetUInt32(out var number)?number:0;
                bookmarks.Add(new(uid,id,systemName,name,source==2,row.GetProperty("favourite").GetBoolean()){Icon=icon});
            }
            offset+=rows.GetArrayLength();if(offset==total)break;if(rows.GetArrayLength()==0)throw new InvalidDataException("原游戏账户星图分页未继续。");
            page=await pipe.CallAsync(new{op="galaxy.account",generation,offset,limit=16},token);
        }
        return new(true,bookmarks,"original-bookmark-manager");
    }
}