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 Assets = new List(); // files.txt 解析出的 name->(md5,size),用于增量下载校验 public Dictionary Files = new Dictionary(); 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(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 GetStringArray(string json, string key) { var list = new System.Collections.Generic.List(); 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; // 否则是值内嵌文本,继续找 } } } }