Files
2026-07-10 10:24:29 +08:00

74 lines
3.5 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.IO;
namespace XWorld.PublishTool
{
// 把构建产物落成发布目录 + 清单 + (可选)签名。
// privateKeyPem 传 null = 不签名:files.txt.sig 落空文件(两端验签均为"未配置则跳过")。
public sealed class PublishLayout
{
// 服务器树:outDir 即 <gamesRoot>/<id>/<ver>/ 的内容(普通文件名,不做 md5 命名)
public void PublishServer(string srcDir, string outDir, GameSpec spec, string privateKeyPem)
{
Directory.CreateDirectory(outDir);
CopyTo(srcDir, spec.ServerAssembly, outDir);
CopyTo(srcDir, spec.CoreDll, outDir);
// game.json 先写,确保其 md5 纳入清单
File.WriteAllText(Path.Combine(outDir, "game.json"), GameJsonWriter.WriteServer(spec));
var fm = new FilesManifest();
foreach (var name in new[] { spec.ServerAssembly, spec.CoreDll, "game.json" })
{
byte[] b = File.ReadAllBytes(Path.Combine(outDir, name));
fm.Add(name, Md5Util.OfBytes(b), b.Length);
}
WriteManifestAndSig(outDir, fm, privateKeyPem);
}
// 客户端树:outDir 即 CDN/minigame/<id>/<ver>/<platform>/ 的内容。
// spec.CodeAb / spec.Assets 均为完整 AB 文件名(code.unity3d / res.unity3d),统一 AB:无散 .bytes。
public void PublishClient(string srcDir, string outDir, GameSpec spec, string privateKeyPem)
{
if (string.IsNullOrEmpty(spec.CodeAb))
throw new InvalidOperationException("spec.CodeAb 为空:客户端发布需要代码 AB(统一 AB 格式)");
Directory.CreateDirectory(outDir);
var fm = new FilesManifest();
CopyMd5Named(srcDir, spec.CodeAb, outDir, fm);
foreach (var ab in spec.Assets) CopyMd5Named(srcDir, ab, outDir, fm);
File.WriteAllText(Path.Combine(outDir, "game.json"), GameJsonWriter.WriteClient(spec));
WriteManifestAndSig(outDir, fm, privateKeyPem);
}
private static void WriteManifestAndSig(string outDir, FilesManifest fm, string privateKeyPem)
{
File.WriteAllText(Path.Combine(outDir, "files.txt"), fm.Render());
byte[] sig = privateKeyPem == null
? Array.Empty<byte>()
: ManifestSigner.Sign(fm.Digest(), privateKeyPem);
File.WriteAllBytes(Path.Combine(outDir, "files.txt.sig"), sig);
}
private static void CopyTo(string srcDir, string name, string dstDir)
=> File.Copy(Path.Combine(srcDir, name), Path.Combine(dstDir, name), true);
// 落盘 md5 命名(name_md5.ext,与 MiniGameDownloader.Md5Name 推导一致),files.txt 登记逻辑名
private static void CopyMd5Named(string srcDir, string name, string dstDir, FilesManifest fm)
{
byte[] data = File.ReadAllBytes(Path.Combine(srcDir, name));
string md5 = Md5Util.OfBytes(data);
File.WriteAllBytes(Path.Combine(dstDir, Md5Name(name, md5)), data);
fm.Add(name, md5, data.Length);
}
// name.ext -> name_md5.ext(无扩展名则 name_md5
private static string Md5Name(string filename, string md5)
{
int pos = filename.LastIndexOf('.');
return pos >= 0 ? $"{filename.Substring(0, pos)}_{md5}{filename.Substring(pos)}"
: $"{filename}_{md5}";
}
}
}