Initial commit: Client Doc docs Server Tools
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,307 @@
|
||||
# C# 热更联机小游戏架构设计
|
||||
|
||||
- 日期:2026-06-18
|
||||
- 状态:已通过头脑风暴评审,待编写实现计划
|
||||
- 适用范围:客户端(Unity)+ 服务端(.NET)统一的 C# 热更小游戏平台
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
在现有工程基础上,建立一套**客户端与服务端都用 C# 热更**的联机小游戏架构,支持内部团队**独立制作小游戏并上传**,客户端**动态下载小游戏资源、加载并运行**。
|
||||
|
||||
### 现有工程现状
|
||||
|
||||
- 客户端:Unity + URP,已集成 **HybridCLR**(C# 热更,`Client/Assets/Base/LoadDll.cs` 负责增量下载 AOT/热更 DLL + AssetBundle,已适配 android/ios/webgl/微信小游戏)+ **XLua**(Lua 热更)。
|
||||
- 资源分发:AssetBundle(`.unity3d`)+ md5 清单(`dllfiles.txt`/`files.txt`)做增量下载。
|
||||
- 已有样例:`Client/Assets/MiniGames/RockPaperScissors`(石头剪刀布联机小游戏,旧版 IMGUI + Lua,服务端 `main.lua`,含匹配 + 15 秒 AI 兜底;已按 §2.4 目录规范迁入 `MiniGames/`,待 C# 重写)。
|
||||
- 服务端:`Server/` 目录为空,尚未实现。
|
||||
- 现有规则(`Doc/Rule/UnityProject.md`)规定小游戏逻辑用 Lua、不用 C#——本设计将**取代该规则**。
|
||||
|
||||
### 已锁定的核心决策(评审确认)
|
||||
|
||||
1. 小游戏**全面转向 C# 热更**,弃用 Lua 小游戏路线;`RockPaperScissors` 后续用 C# 重写。
|
||||
2. **权威服务端**模型:服务端动态加载每个小游戏的 C# 逻辑,跑权威对局。
|
||||
3. 小游戏代码组织为**共享逻辑核心 + 两端薄层**。
|
||||
4. 上传者仅限**内部可信团队**;安全从轻,以签名校验 + 版本管理为主,不上重量级进程沙箱。
|
||||
5. 目标平台:**App(Android/iOS,HybridCLR)+ 微信小游戏(WASM)都要**,传输层统一 **WebSocket**。
|
||||
6. 联机节奏:**轻实时(状态同步 10–20Hz)+ 回合制**。
|
||||
|
||||
### 关键技术选型(评审确认)
|
||||
|
||||
- **A1**:共享核心源码一份,客户端/服务端各自编译(客户端编进 HybridCLR 热更 DLL,服务端编成普通 .NET DLL)。
|
||||
- **B1**:服务端单进程 + 可卸载 `AssemblyLoadContext` 动态加载小游戏逻辑(预留将来子进程隔离 B2 的接口)。
|
||||
- **C1**:复用并扩展现有 `LoadDll` + md5 清单机制,叠加"小游戏 manifest"维度,不另起炉灶。
|
||||
|
||||
## 2. 整体分层与小游戏组成
|
||||
|
||||
### 2.1 三层 + 两宿主
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 框架层 (Framework, 常驻不热更) │
|
||||
│ 客户端宿主: LoadDll/AB加载/网络/UI根/小游戏生命周期 │
|
||||
│ 服务端宿主: 网关/匹配/房间宿主/ALC加载器/持久化 │
|
||||
│ 共享: 网络协议编解码 / 小游戏SDK接口定义 │
|
||||
└───────────────┬─────────────────────────────┘
|
||||
│ 通过稳定接口加载/调用 (不反向依赖小游戏)
|
||||
┌────────────────────┼────────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐
|
||||
│ 小游戏·共享核心 │ │ 小游戏·客户端薄层 │ │ 小游戏·服务端薄层 │
|
||||
│ <Game>.Core.dll │ │ <Game>.Client.dll│ │ <Game>.Server.dll │
|
||||
│ 纯C#:规则/状态/ │ │ HybridCLR加载: │ │ .NET ALC加载: │
|
||||
│ 协议/校验 │ │ 渲染/UI/输入/表现 │ │ 房间/AI/持久化 │
|
||||
│ 依赖→平台能力接口 │ │ 依赖→Core+客户端SDK│ │ 依赖→Core+服务端SDK│
|
||||
└─────────────────┘ └─────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
**依赖方向铁律**:框架 ← 小游戏(小游戏依赖框架接口,框架永不依赖具体小游戏)。Core 只依赖纯 C# + 平台能力接口,绝不引用 `UnityEngine`、`System.IO`、socket 等平台 API。
|
||||
|
||||
### 2.2 一个小游戏发布包的组成
|
||||
|
||||
| 内容 | 说明 | 跑在哪 |
|
||||
|---|---|---|
|
||||
| `<Game>.Core.dll` | 平台无关规则/状态/协议(A1:源码一份,两端各编一次) | 客户端 + 服务端 |
|
||||
| `<Game>.Client.dll` | 客户端表现层(HybridCLR 热更 DLL) | 客户端 |
|
||||
| `<Game>.Server.dll` | 服务端权威逻辑(普通 .NET DLL,服务端侧不打 AB,原样下发 ALC) | 服务端 ALC |
|
||||
| 客户端 AB `.unity3d` 若干 | **脚本与美术统一打 AB**:`<Game>.Core.dll`/`<Game>.Client.dll` 以 `.bytes`(TextAsset) 打进 AB,`res/` 美术/UI/音效另打 AB(§2.4) | 客户端 |
|
||||
| `game.json` 元数据 | 游戏 id、版本、入口类型名、最小框架版本、人数、AI 兜底参数等 | 两端读取 |
|
||||
| `manifest`(md5 清单) | 上述文件 md5 + size + 依赖,挂到现有 `LoadDll` 体系(C1) | 客户端下载用 |
|
||||
|
||||
> 客户端发布产物**全部是 AB(`.unity3d`)**:热更 DLL 与美术资源都走同一套 AB 下载/版本/校验管线,避免两条管线(独立 `.bytes` vs AB)并存。服务端的 `<Game>.Server.dll`/`<Game>.Core.dll` 仍是普通 .NET DLL(ALC 直接 `Assembly.LoadFrom`,不打 AB)。
|
||||
|
||||
### 2.3 小游戏入口契约
|
||||
|
||||
框架定义稳定接口,小游戏实现,框架按 `game.json` 的类型名反射实例化:
|
||||
|
||||
- `IGameClient`:客户端薄层实现(生命周期 + 网络消息 + 帧更新)。
|
||||
- `IGameServerRoom`:服务端薄层实现(房间生命周期 + 消息 + tick)。
|
||||
- `IGameLogic`(Core 内):纯函数式推进状态 `Step(state, input) -> (newState, events)`,两端共用做权威计算与客户端预演。
|
||||
|
||||
新增一个小游戏 = 写 1 个 Core + 各 1 个薄层实现接口,框架零改动。
|
||||
|
||||
### 2.4 客户端源码目录规范
|
||||
|
||||
每个小游戏的**客户端源文件统一收敛在一个目录**下,便于团队独立维护、打包工具按目录扫描、热更资源整目录打 AB:
|
||||
|
||||
```
|
||||
Client/Assets/MiniGames/<Game>/ # 一个小游戏一个根目录(<Game> = gameId,如 RockPaperScissors)
|
||||
scripts/ # 客户端脚本(C# 热更源码)
|
||||
Core/ # 共享核心源码(A1:一份源码,客户端编进 HybridCLR 热更 DLL,服务端 <Compile Include> 链接同一批 .cs 编 .NET DLL)
|
||||
Client/ # 客户端薄层:IGameClient 实现 + 渲染/UI/输入/表现
|
||||
res/ # 美术 / UI / 预制体 / 音效(按 AB 目录规则组织,打成 AssetBundle)
|
||||
```
|
||||
|
||||
约定:
|
||||
|
||||
- **`scripts/` 与 `res/` 都参与打 AB**。`scripts/` 编出的热更 DLL(`<Game>.Core.dll`/`<Game>.Client.dll`)以 `.bytes`(TextAsset) 形式打进 AB;`res/` 资源按目录打 AB。客户端发布产物全是 `.unity3d`(§2.2)。
|
||||
- **依赖方向**:`scripts/Core` 不得引用 `UnityEngine`(纯 C#,§2.1 铁律);`scripts/Client` 可引用 `UnityEngine` + 框架客户端 SDK + Core。
|
||||
- **共享 Core 一份源码**:`scripts/Core` 是 Core 的**唯一源码位置**;服务端薄层工程(`Server/games-src/<Game>/<Game>.Server`)通过 `<Compile Include="...MiniGames/<Game>/scripts/Core/**/*.cs">` 链接同一批 `.cs`,杜绝两端逻辑漂移(A1)。服务端薄层(`IGameServerRoom` 实现)属服务端源码,仍留在 `Server/games-src/`,不进客户端 `MiniGames/`。
|
||||
- 框架加载器(`Client/Assets/Script/xmain/MiniGame/`)是**常驻框架**,不属于任何单个小游戏,不放进 `MiniGames/`。
|
||||
|
||||
## 3. 三条核心数据流
|
||||
|
||||
### 3.1 发布流程(制作 → 上传 → 上架)
|
||||
|
||||
```
|
||||
开发者本地
|
||||
├─ 写 <Game>.Core / .Client / .Server (Core/Client 源码在 Client/Assets/MiniGames/<Game>/scripts/,Server 在 Server/games-src/<Game>/) [§2.4]
|
||||
├─ 一键构建工具(Editor菜单):
|
||||
│ 1. Core 编两次 → 热更DLL(给HybridCLR) + .NET DLL(给服务端) [A1]
|
||||
│ 2. Client 编成 HybridCLR 热更 DLL
|
||||
│ 3. 脚本+美术统一打 AB:Core/Client 热更 DLL 转 .bytes(TextAsset) 打进 AB + res/ 按目录打 AB → 全是 .unity3d [§2.2/§2.4]
|
||||
│ 4. 生成 game.json + 计算各文件 md5 → 小游戏 manifest
|
||||
│ 5. 全部 → 签名(防篡改)
|
||||
└─ 上传到「发布服务」(内部后台)
|
||||
│
|
||||
发布服务 ├─ 校验签名 + 最小框架版本兼容
|
||||
├─ 写入版本库(灰度/正式通道), 资源/DLL 落 CDN
|
||||
├─ 客户端侧: 把小游戏 manifest 并入 LoadDll 的清单维度 [C1]
|
||||
└─ 服务端侧: 通知房间宿主「有新版本 <Game> vN 可用」
|
||||
```
|
||||
|
||||
关键点:**一次构建产出客户端包和服务端包**,版本号绑定,避免两端逻辑漂移。
|
||||
|
||||
### 3.2 客户端:进入 → 下载 → 加载 → 运行
|
||||
|
||||
```
|
||||
玩家点击某小游戏
|
||||
→ 框架查 manifest: 对比本地 md5, 增量下载缺失/变更文件 (复用 LoadDll, 断点续传/重试)
|
||||
→ 校验签名+md5
|
||||
→ 加载该小游戏全部 AB(.unity3d):含脚本 AB 与美术 AB
|
||||
→ 从脚本 AB 取出 Core/Client 的 .bytes(TextAsset) → HybridCLR.LoadMetadataForAOTAssembly + Assembly.Load(Core, Client)
|
||||
→ 反射实例化 game.json 指定的 IGameClient 入口
|
||||
→ 框架建小游戏根节点/UI根, 注入 ctx(资源加载器/网络通道/退出回调)
|
||||
→ IGameClient.OnEnter() 接管; OnUpdate 每帧驱动
|
||||
退出: IGameClient.OnExit() → 卸载AB → 卸载小游戏根 → (DLL常驻, 内存可控)
|
||||
```
|
||||
|
||||
微信小游戏分支:传输强制 WebSocket,代码下载走 WX 文件系统缓存。**热更代码下载需符合微信平台政策**(见 6.6 降级策略)。
|
||||
|
||||
### 3.3 对局流程(权威服务端 + 轻实时状态同步)
|
||||
|
||||
```
|
||||
客户端 服务端(网关/房间宿主)
|
||||
│── 请求匹配(gameId,version) ──▶ 匹配队列(按gameId+version分桶)
|
||||
│ ├─ 凑齐N人 或 15s超时→AI兜底(沿用RPS规则)
|
||||
│ ├─ 房间宿主: 若未加载该版本Server DLL
|
||||
│ │ → 用可卸载ALC加载 <Game>.Server.dll [B1]
|
||||
│ └─ new IGameServerRoom, OnRoomStart(players)
|
||||
│◀──── 房间就绪/初始状态快照 ─────┤
|
||||
│ │ 服务端权威循环:
|
||||
│── 玩家输入(intent) ──────────▶ OnMessage → Core.Step() 推进权威状态
|
||||
│ │ OnTick(10-20Hz): 生成状态快照/增量
|
||||
│◀──── 状态快照/事件广播 ────────┤ (轻实时: 客户端可用Core.Step本地预演+插值)
|
||||
│ IGameClient渲染表现 │
|
||||
│── ... 直到结束 ──────────────▶ OnRoomEnd → 结算落库 → 通知客户端
|
||||
│◀──── 结算结果 ────────────────┤ → ALC 在无房间引用时可卸载(热更新版本)
|
||||
```
|
||||
|
||||
**权威性保证**:胜负/随机/关键状态只认服务端 `Core.Step` 的结果;客户端 `Core.Step` 仅用于预演和插值,最终以服务端快照校正。两端跑同一份 Core,天然一致。
|
||||
|
||||
## 4. 服务端运行时架构
|
||||
|
||||
### 4.1 进程内组件(单进程,B1)
|
||||
|
||||
```
|
||||
┌──────────────────────── 服务端主进程 (.NET 8+) ──────────────────────────┐
|
||||
│ [接入层] WebSocket 网关 (Kestrel/ASP.NET Core) │
|
||||
│ ├─ 连接/鉴权/心跳, 统一收发框架协议帧 │
|
||||
│ └─ Session 管理(playerId ↔ 连接), 断线重连窗口 │
|
||||
│ [路由层] 消息路由: 框架消息(匹配/心跳/大厅) vs 小游戏消息(转给房间) │
|
||||
│ [匹配服务] 按 (gameId, version) 分桶队列 │
|
||||
│ ├─ 凑齐N人建房; 15s超时→请求房间用该游戏AI兜底 │
|
||||
│ └─ 不跨版本匹配(避免 Core 不一致) │
|
||||
│ [房间宿主 RoomHost] ★核心 │
|
||||
│ ├─ GameModuleRegistry: gameId+version → 已加载的 ALC + 入口工厂 │
|
||||
│ ├─ ALC 加载器: 可卸载 AssemblyLoadContext, 按需加载 <Game>.Server.dll │
|
||||
│ │ + 对应 Core.dll; 注入服务端能力(IRandom权威/ITimer/日志/存储) │
|
||||
│ ├─ Room 实例池: 每对局 1 个 IGameServerRoom; 统一 Tick 调度(10-20Hz) │
|
||||
│ └─ 房间结束回收; 某版本无房间引用 → 标记可卸载 │
|
||||
│ [基础设施] 持久化(对局结果/玩家数据) · 日志/监控 · 配置 · 发布通知订阅 │
|
||||
└──────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 4.2 ALC 生命周期(服务端热更核心)
|
||||
|
||||
```
|
||||
新版本发布通知到达
|
||||
→ 房间宿主创建新的可卸载 ALC, 加载 <Game>.Server.dll vN+1
|
||||
→ 新匹配的房间用 vN+1; 旧房间(vN)继续用旧 ALC 跑完, 互不影响 (版本共存)
|
||||
→ 旧版本所有房间结束 + 无引用 → ALC.Unload() + GC → 内存回收
|
||||
约束:
|
||||
- Core/Server DLL 与框架之间只通过框架程序集里的接口交互
|
||||
(接口类型必须在「框架默认ALC」, 不随小游戏卸载, 否则类型无法跨界)
|
||||
- 小游戏 DLL 不得静态持有跨房间/跨版本的全局状态(否则阻碍卸载)
|
||||
```
|
||||
|
||||
**不重启热更**的关键:老对局用老逻辑跑完,新对局用新逻辑,平滑切换;绝不强制踢掉在玩的对局。
|
||||
|
||||
### 4.3 技术栈
|
||||
|
||||
| 关注点 | 选择 | 理由 |
|
||||
|---|---|---|
|
||||
| 运行时 | .NET 8 LTS(或更新 LTS) | `AssemblyLoadContext.Unload` 成熟,性能好,跨平台 |
|
||||
| 接入 | ASP.NET Core Kestrel + WebSocket | 多端统一 WS(微信小游戏只能 WS),生态成熟 |
|
||||
| 协议编解码 | 共享层(框架协议)+ 各小游戏 Core 自定义消息 | 两端同一份编解码,杜绝不一致 |
|
||||
| 调度 | 单线程 per-room 逻辑 + 房间分配到线程池/channel | 房间内逻辑无锁、确定性好;房间间并行 |
|
||||
| 持久化 | 先用轻量(SQLite/文件)跑通,接口抽象预留 MySQL/Redis | 内部阶段不过度设计 |
|
||||
|
||||
### 4.4 确定性与随机
|
||||
|
||||
权威 `IRandom` 由服务端房间持有种子,关键随机只在服务端 `Core.Step` 产生;客户端预演用服务端下发的种子/结果校正。保证"客户端预测—服务端权威"一致,也方便回放/复盘。
|
||||
|
||||
## 5. 关键接口契约
|
||||
|
||||
```csharp
|
||||
// —— 共享核心层 (<Game>.Core, 纯 C#) ——
|
||||
public interface IGameLogic<TState, TInput, TEvent> {
|
||||
TState CreateInitial(RoomConfig cfg, IRandom rng);
|
||||
StepResult<TState, TEvent> Step(TState s, TInput input, IRandom rng); // 纯函数式权威推进
|
||||
byte[] Encode(TState s); TState Decode(byte[] data); // 快照编解码(两端共用)
|
||||
}
|
||||
|
||||
// —— 框架提供的平台能力(注入给小游戏, 隔离平台差异) ——
|
||||
public interface IRandom { int Next(int max); } // 服务端权威/客户端用下发种子
|
||||
public interface ITimer { float Now { get; } }
|
||||
public interface ILogger { void Info(string m); /* ... */ }
|
||||
public interface IStorage { /* ... */ } // 仅服务端注入
|
||||
|
||||
// —— 客户端薄层入口 ——
|
||||
public interface IGameClient {
|
||||
void OnEnter(IGameClientCtx ctx); // ctx: 资源加载/网络发送/退出
|
||||
void OnNetMessage(NetMessage msg);
|
||||
void OnUpdate(float dt);
|
||||
void OnExit();
|
||||
}
|
||||
|
||||
// —— 服务端薄层入口 ——
|
||||
public interface IGameServerRoom {
|
||||
void OnRoomStart(IReadOnlyList<PlayerInfo> players, IRoomCtx ctx);
|
||||
void OnMessage(int playerId, NetMessage msg);
|
||||
void OnTick(float dt); // 10-20Hz, 内部调用 Core.Step + 广播快照
|
||||
void OnRoomEnd();
|
||||
}
|
||||
```
|
||||
|
||||
> 这些接口类型**定义在常驻框架程序集**(不随小游戏 ALC 卸载),保证跨边界类型一致。
|
||||
|
||||
## 6. 错误处理与容错
|
||||
|
||||
| 场景 | 处理 |
|
||||
|---|---|
|
||||
| 客户端下载失败/md5 不符 | 重试 + 断点续传;超阈值回大厅报错,不进半成品小游戏(复用 LoadDll 现有逻辑) |
|
||||
| 签名/版本不兼容 | 拒绝加载,提示更新框架版本 |
|
||||
| 小游戏 Server 逻辑抛异常 | 房间隔离:捕获→该房间安全结束并落败/重开,不拖垮主进程;记录日志告警 |
|
||||
| 玩家断线 | 重连窗口内恢复 Session;超时→AI 接管或判负(按 game.json 配置) |
|
||||
| ALC 卸载失败(有泄漏引用) | 监控驻留版本数;告警并保留旧 ALC,绝不强卸导致崩溃 |
|
||||
| 微信小游戏热更代码政策受限(6.6) | 合规审核通道发版 / 必要时主包内置基础小游戏,热更仅增量 |
|
||||
|
||||
### 6.6 微信小游戏热更风险(需重点验证)
|
||||
|
||||
微信小游戏平台对"下载并执行远端代码"有政策约束。落地前必须验证 HybridCLR 在 WX-WASM 环境下的热更代码下载是否合规。降级策略:基础/首发小游戏内置主包,热更仅做增量与资源更新;正式发版走微信审核通道。
|
||||
|
||||
## 7. 安全(内部可信,从轻)
|
||||
|
||||
- **签名校验**:发布产物全部签名,客户端/服务端加载前验签(防中间人篡改 DLL)。
|
||||
- **传输**:WSS(TLS)。
|
||||
- **来源限定**:只加载发布服务登记过的 manifest,不接受任意 URL。
|
||||
- 不上进程沙箱 / 字节码校验(内部信任,YAGNI);第 5 节的能力接口注入天然限制小游戏可触达的 API,预留将来收紧空间。
|
||||
|
||||
## 8. 测试策略
|
||||
|
||||
| 层 | 测试方式 |
|
||||
|---|---|
|
||||
| Core(纯 C#) | 单元测试:`Step` 确定性、编解码往返、规则边界。两端共用 Core,测一次双端受益 |
|
||||
| 协议编解码 | 往返一致性 + 跨版本兼容用例 |
|
||||
| 服务端房间 | 用假网络/假玩家驱动 `IGameServerRoom`,含断线/超时/AI 兜底用例 |
|
||||
| ALC 热更 | 集成测试:加载 v1→建房→发布 v2→新房用 v2、旧房跑完→v1 卸载、内存回收断言 |
|
||||
| 端到端 | 用 RPS 跑通:匹配→对局→结算→热更换版本 |
|
||||
|
||||
## 9. 渐进落地路线(每步可独立验证)
|
||||
|
||||
1. **框架接口与协议层**:定义第 5 节接口、网络协议编解码(共享层),先不接小游戏。
|
||||
2. **服务端骨架**:Kestrel WS 网关 + Session + 匹配 + RoomHost + ALC 加载器(先加载一个 hello 房间验证热更/卸载闭环)。
|
||||
3. **客户端骨架**:扩展 `LoadDll` 支持小游戏 manifest 维度 + HybridCLR 加载小游戏 DLL + 生命周期接管。
|
||||
4. **构建/发布工具链**:一键产出两端包 + manifest + 签名 + 上传(A1 的双编译)。
|
||||
5. **试金石:用 C# 重写 RockPaperScissors**(Core 规则 + 客户端薄层 + 服务端薄层 + AI 兜底),跑通端到端 + 热更换版本。
|
||||
6. **沉淀模板**:把 RPS 抽成"新小游戏脚手架模板",验证"写一个新小游戏 = 框架零改动"。
|
||||
|
||||
每一步对应第 8 节测试,独立验证后再进入下一步。
|
||||
|
||||
## 10. 待跟进 / 风险清单
|
||||
|
||||
### 10.1 「脚本+美术统一打 AB」改造清单(相对已实现代码的增量)
|
||||
|
||||
现有实现把热更 DLL 落成**独立 md5 命名的 `.bytes`**、与美术 AB 走两条管线;本设计(§2.2/§2.4)改为**DLL 以 `.bytes` 打进 AB、与美术同走一条 AB 管线**。需改造(其余模块零改动):
|
||||
|
||||
- **客户端目录迁移**:已完成——`RockPaperScissors` 迁入 `Client/Assets/MiniGames/RockPaperScissors/`(`Art→res`、`script→scripts`,保留 `.meta` GUID)。新增小游戏一律按 §2.4 落在 `MiniGames/<Game>/`。
|
||||
- **Editor 构建(`Client/Assets/Editor/MiniGamePublishMenu.cs`)**:第 3 步由「DLL→.bytes 旁路 + 美术打 AB」改为「DLL→.bytes 作为 TextAsset 与 `res/` 一起 `BuildAssetBundles`」,产物全是 `.unity3d`。
|
||||
- **发布布局(`Server/PublishTool/PublishLayout.cs` + `GameSpec`/`GameJsonWriter`)**:客户端侧不再 `CopyBytes` 单独落 DLL `.bytes`;改为把脚本 AB 与美术 AB 一并按 md5 命名落盘并登记进 `files.txt`;`game.json` 用 AB 名(含脚本 AB)替代 `coreDll`/`clientDll` 字段语义。同步更新 `PublishTool.Tests`。
|
||||
- **客户端加载器(`Client/Assets/Script/xmain/MiniGame/`)**:`MiniGameAssemblyLoader` 由 `File.ReadAllBytes(<dll>.bytes)` 改为从已加载 AB 取 `TextAsset` 字节再 `Assembly.Load`;`MiniGameDownloader` 不再特判 `.bytes`(全部条目按 AB 增量下载);`MiniGameManifest` 解析 game.json 的 AB 字段。**须 Unity Editor/真机核对**(本环境无 Unity,无法验证 HybridCLR 从 AB 加载 DLL)。
|
||||
|
||||
### 10.2 其他
|
||||
|
||||
- 微信小游戏热更代码政策合规性(6.6)——上线前必须验证。
|
||||
- 现有 `Doc/Rule/UnityProject.md` 的"小游戏用 Lua"规则需更新为 C# 路线。
|
||||
- HybridCLR 在 WASM 下对小游戏热更 DLL 的 AOT 泛型/裁剪约束需实测。
|
||||
- ALC 卸载的内存泄漏边界(静态字段、事件订阅、未释放的 native 句柄)需在第 2 步集成测试中重点验证。
|
||||
Reference in New Issue
Block a user