Initial commit: Client Doc docs Server Tools
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
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; // 否则是值内嵌文本,继续找
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user