using System.Globalization; using System.Text.Json; namespace XFEEDToolBox.Core.Galaxy; public sealed record GalaxyFleetItem(int Id,uint ShipId,long SystemAddress); public sealed record GalaxyFleetSnapshot(bool Available,uint? CurrentShipId,IReadOnlyList Ships) { public bool Complete=>false; } public sealed record GalaxyFleetMapTarget(int Id,uint ShipId,long SystemAddress,string Label); public sealed partial class NativeGalaxyAccountCatalog { public async Task ReadFleetAsync(CancellationToken token=default) { var page=await pipe.CallAsync(new{op="galaxy.fleet",limit=96},token); if(!page.GetProperty("available").GetBoolean())return new(false,null,[]); var generation=page.GetProperty("generation").GetUInt64();var total=page.GetProperty("total").GetInt32();var entity=page.GetProperty("entityId").GetString(); uint? Current(JsonElement p) { var value=p.GetProperty("currentShipId");if(value.ValueKind==JsonValueKind.Null)return null; if(!value.TryGetUInt32(out var id)||id==uint.MaxValue)throw new InvalidDataException("原游戏当前飞船 ID 无效。");return id; } var current=Current(page); if(generation==0||total is <0 or >4096||string.IsNullOrEmpty(entity))throw new InvalidDataException("原游戏飞船快照标识无效。"); var ships=new List();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||Current(page)!=current) 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 id=row.GetProperty("id").GetInt32();var shipId=row.GetProperty("shipId").GetUInt32(); if(id!=ships.Count+1||shipId==uint.MaxValue||current==shipId||!long.TryParse(row.GetProperty("systemAddress").GetString(),NumberStyles.None,CultureInfo.InvariantCulture,out var address)||address<=0||address>=1L<<55) throw new InvalidDataException("原游戏飞船条目无效。"); // AS id is the original filtered one-based ordinal, never a // ship ID or a Galactic address. Preserve repeated systems. ships.Add(new(id,shipId,address)); } offset+=rows.GetArrayLength();if(offset==total)break;if(rows.GetArrayLength()==0)throw new InvalidDataException("原游戏飞船分页未继续。"); page=await pipe.CallAsync(new{op="galaxy.fleet",generation,offset,limit=96},token); } return new(true,current,ships); } }