# Lua/C# 脚本与热更新

不发版也能修 Bug 和更新内容——热更新是线上游戏的命脉

前置知识:2_1_v8Learn(编译原理与脚本系统)+ 第10章 游戏架构设计模式


阅读指南(初学者必看)

为什么你需要学习脚本与热更新?

游戏上线后,每次发版都要经过应用商店审核(iOS 1~3天),紧急 Bug 等不起。热更新让你在不动客户端的情况下修复逻辑、更新活动、调整数值——这是线上运营的基本能力。

学完本章,你能回答:

  • Lua 热更新的原理是什么?为什么游戏逻辑用 Lua 写而不是 C++?
  • Unity/C# 的三种热更新方案(ILRuntime/HybridCLR/xLua)各有什么优劣?
  • H5 游戏的热更新为什么比原生游戏简单得多?

本文结构

第一部分:Lua 热更新——脚本语言的天生优势
第二部分:C# 热更新方案——Unity 生态的三大选择
第三部分:H5 热更新——最简单的热更新方案

一、Lua 热更新

Lua 热更新原理:

1. 游戏逻辑用 Lua 编写
2. 更新时只替换 Lua 文件
3. 不需要重新编译 C++/Java 代码
4. 不需要重新发布客户端

LuaJIT 性能:
- 解释执行比标准Lua快10倍
- JIT编译后接近C语言速度
- 但JIT在某些平台受限(iOS禁止JIT)

热更新流程:
1. 修改 Lua 脚本
2. 上传到 CDN
3. 客户端检测版本号
4. 下载差异文件
5. 热加载新脚本(require 替换)

二、C# 热更新方案

Unity/C# 热更新方案对比:

| 方案 | 原理 | 性能 | 限制 |
|------|------|------|------|
| ILRuntime | 解释执行IL | 中 | 部分特性不支持 |
| HybridCLR | 补充AOT编译 | 高 | 需要构建管线 |
| xLua/tolua | Lua桥接 | 中 | 跨语言调用开销 |

三、H5 热更新

H5游戏(Cocos Creator)热更新:
- JS 本身就是解释型语言
- 热更新 = 替换 JS Bundle
- 资源热更新 = 替换 CDN 上的资源
- 比原生游戏热更新简单得多

风险:缓存问题
- 浏览器和 CDN 都有缓存
- 解决方案:文件名加哈希(game.a1b2c3.js)
- HTML 入口不缓存(Cache-Control: no-cache)

自问自答

Q:为什么原生游戏不直接用 JS 热更新? A:因为原生游戏的底层是 C++/Java 编译后的二进制代码,不像 JS 是运行时解释执行。所以原生游戏需要一个"可解释执行"的脚本层(Lua/C# 解释器)来实现热更新,而 H5 游戏的 JS 天然就支持。

Q:xLua 和 ILRuntime 怎么选? A:xLua 用 Lua 写热更逻辑,跨语言调用有开销但生态成熟(腾讯在用);ILRuntime 用 C# 写热更逻辑,语言统一但部分特性不支持。如果团队熟悉 Lua 选 xLua,想统一 C# 选 ILRuntime。大型项目可能两者混用。

Q:热更新可以改数据结构吗? A:可以但很危险。改逻辑没问题(替换函数),但改数据结构(加字段、改类型)可能导致旧数据和新代码不兼容。最佳实践:1)数据结构设计时预留扩展字段;2)热更只改逻辑不改结构;3)如果必须改结构,写迁移脚本。


实践任务

  • 任务1:实现一个简单的 Lua 热更新流程——修改脚本 → 上传 CDN → 客户端检测版本 → 下载并热加载
  • 任务2:对比 xLua 和 ILRuntime 的跨语言调用性能(循环调用 10000 次,测耗时)
  • 任务3:在 H5 游戏中实现资源热更新——修改图片/音频资源,客户端检测并下载更新
  • 任务4:设计一个热更新的版本管理方案——如何处理回滚、灰度发布、A/B 版本
  • 任务5:模拟一个"热更新导致数据不兼容"的 Bug,写迁移脚本修复

与其他章节的关联

本章内容 关联章节 关联点
Lua 热更新 2_1_v8Learn V8 的 JIT 编译和 LuaJIT 的 JIT 原理类似
ECS + 热更新 第10章 游戏架构设计模式 ECS 的 System 是纯逻辑,天然适合热更新
活动系统 第09章 游戏运营与商业化 活动逻辑是热更新的高频需求
脚本安全 第08章 游戏安全与反作弊 热更新包的完整性校验和签名验证
技术选型 第12章 技术选型与决策 热更新方案的选择本身就是技术选型

上一章:10-游戏架构设计模式 下一章:12-技术选型与决策