using System.IO.Compression; using System.Numerics; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text.Json; using XFEEDToolBox.Core.Models; namespace XFEEDToolBox.Core.Rendering; /// The authored GalaxyGlow mesh, its named FGM values and original noise mip chain. public sealed class GalaxyOriginalCoreResources { public IReadOnlyList Positions {get;} public IReadOnlyList Indices {get;} public IReadOnlyList MaterialConstants {get;} public IReadOnlyList NoiseMips {get;} public ReadOnlyMemory NoisePayload {get;} public const float WorldScale=40000; public static Vector3 WorldCentre=>new(50000,40955,50000); internal GalaxyOriginalCoreResources(JsonElement metadata,byte[] mesh,byte[] noise) { static void Verify(byte[] bytes,JsonElement part,int length,string hash) { if(bytes.Length!=length||part.GetProperty("payloadBytes").GetInt32()!=length|| part.GetProperty("payloadSha256").GetString()!=hash||Convert.ToHexStringLower(SHA256.HashData(bytes))!=hash) throw new InvalidDataException("原银河核心资源校验失败。"); } var meshInfo=metadata.GetProperty("mesh");var texture=metadata.GetProperty("texture"); Verify(mesh,meshInfo,2952,"0a3cefa5719b74a016079198183902a25bffb71ca2af970efc4afdcc198f8250"); Verify(noise,texture,3072,"4ce432549ca60cd1704064588bfe3e1030aef468fe2bc5bfd11ae749288e30e9"); if(meshInfo.GetProperty("vertexCount").GetInt32()!=150||meshInfo.GetProperty("indexCount").GetInt32()!=576|| texture.GetProperty("width").GetInt32()!=16||texture.GetProperty("height").GetInt32()!=16||texture.GetProperty("dxgiFormat").GetInt32()!=71) throw new InvalidDataException("原银河核心资源布局无效。"); Positions=Array.AsReadOnly(MemoryMarshal.Cast(mesh.AsSpan(0,1800)).ToArray()); Indices=Array.AsReadOnly(MemoryMarshal.Cast(mesh.AsSpan(1800)).ToArray()); MaterialConstants=Array.AsReadOnly(metadata.GetProperty("shaderMaterialConstantVectors").EnumerateArray().Select(a=> { var v=a.EnumerateArray().Select(n=>n.GetSingle()).ToArray();return new Vector4(v[0],v[1],v[2],v[3]); }).ToArray()); NoiseMips=Array.AsReadOnly(JsonSerializer.Deserialize(texture.GetProperty("mips"),ToolboxSettings.JsonOptions)!); NoisePayload=noise; if(MaterialConstants.Count!=8||NoiseMips.Count!=5||Indices.Any(i=>i>=Positions.Count)|| MaterialConstants[3]!=new Vector4(50000,40955,50000,20000)||MaterialConstants[4].X!=80000|| NoiseMips[^1].Offset+NoiseMips[^1].Size!=noise.Length) throw new InvalidDataException("原银河核心材质数据无效。"); } } public static class GalaxyOriginalCore { private static readonly Lazy reference=new(Read); public static GalaxyOriginalCoreResources Reference=>reference.Value; private static GalaxyOriginalCoreResources Read() { var assembly=typeof(GalaxyOriginalCore).Assembly; using var jsonStream=assembly.GetManifestResourceStream("XFEEDToolBox.Core.Rendering.original-galaxy-core.json")!; using var json=JsonDocument.Parse(jsonStream); byte[] Payload(string name,int length) { using var stream=assembly.GetManifestResourceStream("XFEEDToolBox.Core.Rendering.original-galaxy-core-"+name+".gz")!; using var gzip=new GZipStream(stream,CompressionMode.Decompress);var bytes=new byte[length];gzip.ReadExactly(bytes); if(gzip.ReadByte()!=-1)throw new InvalidDataException("原银河核心资源超出范围。");return bytes; } return new(json.RootElement,Payload("mesh.bin",2952),Payload("noise.bc1",3072)); } }