XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
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;

/// <summary>The authored GalaxyGlow mesh, its named FGM values and original noise mip chain.</summary>
public sealed class GalaxyOriginalCoreResources
{
    public IReadOnlyList<Vector3> Positions {get;}
    public IReadOnlyList<ushort> Indices {get;}
    public IReadOnlyList<Vector4> MaterialConstants {get;}
    public IReadOnlyList<GalaxyOriginalSpriteMip> NoiseMips {get;}
    public ReadOnlyMemory<byte> 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<byte,Vector3>(mesh.AsSpan(0,1800)).ToArray());
        Indices=Array.AsReadOnly(MemoryMarshal.Cast<byte,ushort>(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<GalaxyOriginalSpriteMip[]>(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<GalaxyOriginalCoreResources> 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));
    }
}