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;

namespace XFEEDToolBox.Core.Galaxy;

public sealed record GalaxyCurrentTradeFlow(long FromSystemAddress,long ToSystemAddress,ushort CommodityToken,string? CommodityName,
    float NpcAmount,float PlayerAmount,ulong Timestamp);
public sealed record GalaxyCurrentTradeFlowsSnapshot(bool Available,ulong OriginalClock,ulong LifetimeSeconds,ulong RefreshSeconds,
    uint Revision,IReadOnlyList<GalaxyCurrentTradeFlow> Flows,int UnresolvedCount)
{
    public bool Complete=>false;
    public const string Source="original-current-trade-flow-cache";
}

public sealed partial class NativeGalaxyAccountCatalog
{
    public async Task<GalaxyCurrentTradeFlowsSnapshot> ReadCurrentTradeFlowsAsync(CancellationToken token=default)
    {
        var page=await pipe.CallAsync(new{op="galaxy.tradeflows",limit=16},token);
        if(!page.GetProperty("available").GetBoolean())return new(false,0,0,0,0,[],0);
        var generation=page.GetProperty("generation").GetUInt64();var total=page.GetProperty("total").GetInt32();
        var entity=page.GetProperty("entityId").GetString();var clock=TradeFlowU64(page.GetProperty("originalClock"));
        var lifetime=page.GetProperty("lifetimeSeconds").GetUInt64();var refresh=page.GetProperty("refreshSeconds").GetUInt64();
        var revision=page.GetProperty("revision").GetUInt32();var unresolved=page.GetProperty("unresolvedCount").GetInt32();
        if(generation==0||total is <0 or >65536||string.IsNullOrEmpty(entity)||entity.Length>128||clock==0||lifetime==0||unresolved<0||unresolved>total)
            throw new InvalidDataException("原当前贸易流快照标识无效。");
        var result=new List<GalaxyCurrentTradeFlow>();var keys=new HashSet<(long,long,ushort)>();var offset=0;
        while(true)
        {
            token.ThrowIfCancellationRequested();
            var pageClock=TradeFlowU64(page.GetProperty("originalClock"));
            if(!page.GetProperty("available").GetBoolean()||page.GetProperty("generation").GetUInt64()!=generation||page.GetProperty("total").GetInt32()!=total||
               page.GetProperty("entityId").GetString()!=entity||page.GetProperty("complete").GetBoolean()||page.GetProperty("source").GetString()!=GalaxyCurrentTradeFlowsSnapshot.Source||
               pageClock<clock||page.GetProperty("lifetimeSeconds").GetUInt64()!=lifetime||page.GetProperty("refreshSeconds").GetUInt64()!=refresh||
               page.GetProperty("revision").GetUInt32()!=revision||page.GetProperty("unresolvedCount").GetInt32()!=unresolved||
               page.TryGetProperty("offset",out var echoedOffset)&&echoedOffset.GetInt32()!=offset)
                throw new InvalidDataException("原当前贸易流读取期间来源发生变化。");
            clock=pageClock;
            var items=page.GetProperty("items");
            if(items.ValueKind!=JsonValueKind.Array||items.GetArrayLength()>16||offset+items.GetArrayLength()>total)
                throw new InvalidDataException("原当前贸易流分页无效。");
            foreach(var item in items.EnumerateArray())
            {
                var from=TradeFlowAddress(item.GetProperty("fromSystemAddress"));var to=TradeFlowAddress(item.GetProperty("toSystemAddress"));
                var commodity=item.GetProperty("commodityToken").GetUInt16();var nameValue=item.GetProperty("commodityName");
                var name=nameValue.ValueKind==JsonValueKind.Null?null:nameValue.GetString();
                var npc=item.GetProperty("npcAmount").GetSingle();var player=item.GetProperty("playerAmount").GetSingle();var timestamp=TradeFlowU64(item.GetProperty("timestamp"));
                if(from==to||commodity==0||!keys.Add((from,to,commodity))||name is not null&&(string.IsNullOrWhiteSpace(name)||name.Length>256||name.Any(char.IsControl))||
                   !float.IsFinite(npc)||npc is <0 or >1||!float.IsFinite(player)||timestamp>clock)
                    throw new InvalidDataException("原当前贸易流条目无效。");
                result.Add(new(from,to,commodity,name,npc,player,timestamp));
            }
            offset+=items.GetArrayLength();var next=page.GetProperty("nextOffset");
            if(next.ValueKind==JsonValueKind.Null)
            {
                var cutoff=unchecked(clock-lifetime);
                if(offset!=total||result.Count(row=>row.CommodityName is null)!=unresolved||result.Any(row=>row.Timestamp<cutoff||row.Timestamp>clock))
                    throw new InvalidDataException("原当前贸易流快照缺失记录。");
                break;
            }
            if(items.GetArrayLength()==0||next.GetInt32()!=offset||offset>=total)
                throw new InvalidDataException("原当前贸易流分页顺序无效。");
            page=await pipe.CallAsync(new{op="galaxy.tradeflows",limit=16,offset,generation},token);
        }
        return new(true,clock,lifetime,refresh,revision,result,unresolved);
    }
    private static ulong TradeFlowU64(JsonElement value)
    {
        if(value.ValueKind!=JsonValueKind.String||!ulong.TryParse(value.GetString(),NumberStyles.None,CultureInfo.InvariantCulture,out var result))
            throw new InvalidDataException("原当前贸易流64位字段无效。");
        return result;
    }
    private static long TradeFlowAddress(JsonElement value)
    {
        var result=TradeFlowU64(value);
        if(result==0||result>=1UL<<55)throw new InvalidDataException("原当前贸易流地址无效。");
        return (long)result;
    }
}