using System.Buffers.Binary;
namespace XFEEDToolBox.Core.Galaxy;
/// <summary>Complete original Stellar Forge density raster, in the game's Galactic coordinate frame.</summary>
public sealed record GalaxyDensityMap(int Width,int Height,double OriginX,double OriginZ,double ExtentX,double ExtentZ,byte[] Values,bool FloatValues=false)
{
public static GalaxyDensityMap Read(string path)
{
if(new FileInfo(path).Length is <48 or >66*1024*1024)throw new InvalidDataException("银河全景资源大小无效。");
return Parse(File.ReadAllBytes(path));
}
public static GalaxyDensityMap Parse(ReadOnlySpan<byte> data)
{
if(data.Length<48||!(data[..8].SequenceEqual("XFEGDM1\0"u8)||data[..8].SequenceEqual("XFEGDM2\0"u8)))throw new InvalidDataException("银河全景资源头无效。");
var floats=data[6]=='2';var stride=floats?4:2;
var width=BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8,4));var height=BinaryPrimitives.ReadInt32LittleEndian(data.Slice(12,4));
var ox=BinaryPrimitives.ReadDoubleLittleEndian(data.Slice(16,8));var oz=BinaryPrimitives.ReadDoubleLittleEndian(data.Slice(24,8));
var ex=BinaryPrimitives.ReadDoubleLittleEndian(data.Slice(32,8));var ez=BinaryPrimitives.ReadDoubleLittleEndian(data.Slice(40,8));
if(width is <16 or >8192||height is <16 or >8192||(long)width*height>16777216||data.Length!=48+(long)width*height*stride
||!double.IsFinite(ox+oz+ex+ez)||Math.Abs(ox)>1000000||Math.Abs(oz)>1000000||ex is <1000 or >1000000||ez is <1000 or >1000000)
throw new InvalidDataException("银河全景范围或像素数据不完整。");
if(floats)for(var i=48;i<data.Length;i+=4)
{
var value=BinaryPrimitives.ReadSingleLittleEndian(data.Slice(i,4));
if(!float.IsFinite(value)||value<0||value>1)throw new InvalidDataException("银河全景像素超出有效密度范围。");
}
return new(width,height,ox,oz,ex,ez,data[48..].ToArray(),floats);
}
}
using System.Buffers.Binary;
namespace XFEEDToolBox.Core.Galaxy;
/// <summary>Complete original Stellar Forge density raster, in the game's Galactic coordinate frame.</summary>
public sealed record GalaxyDensityMap(int Width,int Height,double OriginX,double OriginZ,double ExtentX,double ExtentZ,byte[] Values,bool FloatValues=false)
{
public static GalaxyDensityMap Read(string path)
{
if(new FileInfo(path).Length is <48 or >66*1024*1024)throw new InvalidDataException("银河全景资源大小无效。");
return Parse(File.ReadAllBytes(path));
}
public static GalaxyDensityMap Parse(ReadOnlySpan<byte> data)
{
if(data.Length<48||!(data[..8].SequenceEqual("XFEGDM1\0"u8)||data[..8].SequenceEqual("XFEGDM2\0"u8)))throw new InvalidDataException("银河全景资源头无效。");
var floats=data[6]=='2';var stride=floats?4:2;
var width=BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8,4));var height=BinaryPrimitives.ReadInt32LittleEndian(data.Slice(12,4));
var ox=BinaryPrimitives.ReadDoubleLittleEndian(data.Slice(16,8));var oz=BinaryPrimitives.ReadDoubleLittleEndian(data.Slice(24,8));
var ex=BinaryPrimitives.ReadDoubleLittleEndian(data.Slice(32,8));var ez=BinaryPrimitives.ReadDoubleLittleEndian(data.Slice(40,8));
if(width is <16 or >8192||height is <16 or >8192||(long)width*height>16777216||data.Length!=48+(long)width*height*stride
||!double.IsFinite(ox+oz+ex+ez)||Math.Abs(ox)>1000000||Math.Abs(oz)>1000000||ex is <1000 or >1000000||ez is <1000 or >1000000)
throw new InvalidDataException("银河全景范围或像素数据不完整。");
if(floats)for(var i=48;i<data.Length;i+=4)
{
var value=BinaryPrimitives.ReadSingleLittleEndian(data.Slice(i,4));
if(!float.IsFinite(value)||value<0||value>1)throw new InvalidDataException("银河全景像素超出有效密度范围。");
}
return new(width,height,ox,oz,ex,ez,data[48..].ToArray(),floats);
}
}