131 lines
6.3 KiB
C#
131 lines
6.3 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
|
||
namespace XGame.MiniGame
|
||
{
|
||
// game.json 客户端视图(字段名大小写不敏感解析)
|
||
public sealed class MiniGameManifest
|
||
{
|
||
public string GameId;
|
||
public int Version;
|
||
public string ClientEntryType;
|
||
public string CoreDll;
|
||
public string ClientDll;
|
||
public string CodeAb; // 代码 AB 文件名(统一 AB:Core/Client DLL 的 .bytes 都在里面)
|
||
public int MinFrameworkVersion;
|
||
public List<string> Assets = new List<string>();
|
||
|
||
// files.txt 解析出的 name->(md5,size),用于增量下载校验
|
||
public Dictionary<string, FileEntry> Files = new Dictionary<string, FileEntry>();
|
||
|
||
public sealed class FileEntry { public string Md5; public int Size; }
|
||
|
||
// 极简手写 JSON 解析(避免引入 Unity JsonUtility 的字段限制;只认本 schema 的扁平字段 + assets 字符串数组)
|
||
// 注意:生产可换成项目已用的 JSON 库;此实现仅解析本 schema,键大小写不敏感。
|
||
public static MiniGameManifest ParseGameJson(string json)
|
||
{
|
||
if (string.IsNullOrEmpty(json)) throw new FormatException("game.json 为空");
|
||
var m = new MiniGameManifest
|
||
{
|
||
GameId = JsonMini.GetString(json, "gameId"),
|
||
Version = JsonMini.GetInt(json, "version"),
|
||
ClientEntryType = JsonMini.GetString(json, "clientEntryType"),
|
||
CoreDll = JsonMini.GetString(json, "coreDll"),
|
||
ClientDll = JsonMini.GetString(json, "clientDll"),
|
||
CodeAb = JsonMini.GetString(json, "codeAb"),
|
||
MinFrameworkVersion = JsonMini.GetInt(json, "minFrameworkVersion"),
|
||
};
|
||
m.Assets = JsonMini.GetStringArray(json, "assets");
|
||
if (string.IsNullOrEmpty(m.GameId)) throw new FormatException("game.json 缺少 gameId");
|
||
if (string.IsNullOrEmpty(m.ClientEntryType)) throw new FormatException("game.json 缺少 clientEntryType");
|
||
if (string.IsNullOrEmpty(m.CoreDll) || string.IsNullOrEmpty(m.ClientDll)) throw new FormatException("game.json 缺少 coreDll/clientDll");
|
||
if (string.IsNullOrEmpty(m.CodeAb))
|
||
throw new FormatException("game.json 缺少 codeAb(统一 AB 新格式;旧 .bytes 直下包不再支持,请用 XWorld/生成小游戏更新 重新发布)");
|
||
if (m.Version <= 0) throw new FormatException("game.json version 必须为正");
|
||
return m;
|
||
}
|
||
|
||
// 与发布工具 FilesManifest.Digest() 完全一致:按 name 的 Ordinal 排序,拼 name=md5;
|
||
public string Digest()
|
||
{
|
||
var keys = new System.Collections.Generic.List<string>(Files.Keys);
|
||
keys.Sort(System.StringComparer.Ordinal);
|
||
var sb = new System.Text.StringBuilder();
|
||
foreach (var k in keys) sb.Append(k).Append('=').Append(Files[k].Md5).Append(';');
|
||
return sb.ToString();
|
||
}
|
||
|
||
// files.txt 行格式(沿用 dllfiles):{'name','md5',size},
|
||
public void LoadFilesList(string content)
|
||
{
|
||
Files.Clear();
|
||
if (string.IsNullOrEmpty(content)) return;
|
||
foreach (var raw in content.Split('\n'))
|
||
{
|
||
string line = raw.Trim();
|
||
if (line.Length < 5) continue;
|
||
// 去掉首 { 与尾 }, ,再去引号
|
||
int lb = line.IndexOf('{'); int rb = line.LastIndexOf('}');
|
||
if (lb < 0 || rb <= lb) continue;
|
||
string inner = line.Substring(lb + 1, rb - lb - 1).Replace("'", "");
|
||
string[] p = inner.Split(',');
|
||
if (p.Length < 3) continue;
|
||
int size; int.TryParse(p[2].Trim(), out size);
|
||
Files[p[0].Trim()] = new FileEntry { Md5 = p[1].Trim(), Size = size };
|
||
}
|
||
}
|
||
}
|
||
|
||
// 极小 JSON 取值器(仅供本 schema;非通用)
|
||
internal static class JsonMini
|
||
{
|
||
public static string GetString(string json, string key)
|
||
{
|
||
int i = FindKey(json, key); if (i < 0) return null;
|
||
int c = json.IndexOf(':', i); if (c < 0) return null;
|
||
int q1 = json.IndexOf('"', c + 1); if (q1 < 0) return null;
|
||
int q2 = json.IndexOf('"', q1 + 1); if (q2 < 0) return null;
|
||
return json.Substring(q1 + 1, q2 - q1 - 1);
|
||
}
|
||
public static int GetInt(string json, string key)
|
||
{
|
||
int i = FindKey(json, key); if (i < 0) return 0;
|
||
int c = json.IndexOf(':', i); if (c < 0) return 0;
|
||
int j = c + 1; while (j < json.Length && (json[j] == ' ' || json[j] == '\t')) j++;
|
||
int s = j; while (j < json.Length && (char.IsDigit(json[j]) || json[j] == '-')) j++;
|
||
int v; int.TryParse(json.Substring(s, j - s), out v); return v;
|
||
}
|
||
public static System.Collections.Generic.List<string> GetStringArray(string json, string key)
|
||
{
|
||
var list = new System.Collections.Generic.List<string>();
|
||
int i = FindKey(json, key); if (i < 0) return list;
|
||
int lb = json.IndexOf('[', i);
|
||
if (lb < 0) return list; // 键存在但无数组
|
||
int rb = json.IndexOf(']', lb);
|
||
if (rb <= lb) return list;
|
||
string inner = json.Substring(lb + 1, rb - lb - 1);
|
||
foreach (var part in inner.Split(','))
|
||
{
|
||
int q1 = part.IndexOf('"'); int q2 = part.LastIndexOf('"');
|
||
if (q1 >= 0 && q2 > q1) list.Add(part.Substring(q1 + 1, q2 - q1 - 1));
|
||
}
|
||
return list;
|
||
}
|
||
private static int FindKey(string json, string key)
|
||
{
|
||
string needle = "\"" + key + "\"";
|
||
int from = 0;
|
||
while (true)
|
||
{
|
||
int idx = json.IndexOf(needle, from, StringComparison.OrdinalIgnoreCase);
|
||
if (idx < 0) return -1;
|
||
int after = idx + needle.Length;
|
||
int j = after;
|
||
while (j < json.Length && (json[j] == ' ' || json[j] == '\t' || json[j] == '\r' || json[j] == '\n')) j++;
|
||
if (j < json.Length && json[j] == ':') return idx; // 确认是键
|
||
from = idx + 1; // 否则是值内嵌文本,继续找
|
||
}
|
||
}
|
||
}
|
||
}
|