# LunLuaFramework
**Repository Path**: nomat/LunLuaFramework
## Basic Information
- **Project Name**: LunLuaFramework
- **Description**: LunLuaFramework是基于tolua的Unity热更新框架,通过使用Lua脚本组件替代C#脚本组件的方式实现热更新。因此使用此框架在开发流程上不会有改变,非常适合于习惯C#脚本组件开发流程的开发者使用此框架实现游戏的热更新功能。同样也可以把完成后的游戏通过替换脚本的方式渐进实现热更新,如此不用把所有C#脚本替换为Lua脚本就可以一步一步调试运行,避免代码修改过多调试困难。
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 1
- **Created**: 2021-09-27
- **Last Updated**: 2024-09-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: Unity, ToLua, 热更新, 简单方便, lun-framework
## README
# lun-framework框架
`lun-framework`是基于tolua的Unity热更新框架,通过使用Lua脚本组件替代C#脚本组件的方式实现热更新。因此使用此框架在开发流程上不会有改变,非常适合于习惯C#脚本组件开发流程的开发者使用此框架实现游戏的热更新功能。同样也可以把完成后的游戏通过替换脚本的方式渐进实现热更新,如此不用把所有C#脚本替换为Lua脚本就可以一步一步调试运行,避免代码修改过多造成调试困难。
实例项目;
[Unity官方Tanks项目热更新重写](https://gitee.com/nomat/unity-game-tanks)
[lun-framework框架功能示例](https://gitee.com/nomat/lun-framework-examples)
## 开发者须知
1. 由于框架基于`tolua`实现,因此开发者应该比较熟悉`Lua`语言。并且最好对`tolua`的类绑定有一定了解,毕竟在开发过程中可能会添加新类以便在`Lua`中进行操作。
## 框架安装配置流程
### 1、把框架`lun-framework-client`目录和`tolua`的`Plugins`目录放到项目`Assets`目录下
框架目录内的文件除非有特殊需求,一般不需要更改。
tolua的Plugins目录,可以在Demo或者例子工程中找到。
### 2、在`Resources`目录(如果没有自行创建)下右键选择`Create -> CreateLunLuaConfig`创建配置资源文件`LunLuaConfig.asset`,点击文件打开检查器并配置。


* `ToLua生成路径` 为`tolua`绑定文件生成目录,默认为`ToLuaGenerate`,也可以修改在`Assets`目录下,框架目录外的任意位置。
* `启用AssetBundle` 仅表示在编辑器中使用真实的AssetBundle,所以需要确保在`StreamingAssets`目录中存在`AssetBundles`,一般用于游戏开发完成后在编辑器中测试热更新使用。**提示:框架发布后就是用这种方式使用资源**
* `启用AssetBundle模拟` 仅表示在编辑器中使用`AssetLabel`加载资源。一般在构建`AssetBundles`后,就会自动配置所有资源配置路径内资源的`AssetLabel`。这个选项可以用于在编辑器中模拟其他目录内的`AssetLabel`资源。
* `启用资源配置路径` 表示在编辑器中直接使用资源配置路径表中的资源。一般在开发的时候使用这种资源使用模式。
* `资源配置路径表` 在编辑器中表示资源的搜索路径表,每个配置目录类似Unity中的Resources目录,通过路径加载资源。同时在构建`AssetBundles`时,资源配置路径表中所有的文件都会自动设置`AssetLabel`,并且同目录中的所有资源设置为同一资源包,因此每个场景文件需要分开放在单独目录中。
### 3、在顶部菜单栏中选择`LunLua -> ToLua -> Generate All`生成`tolua`绑定文件,生成的文件放在配置的`ToLua生成路径`目录内。

如果需要添加新绑定类,可以在`Editor`目录(如果没有自行创建)内添加`ToLuaSettings.cs`,并且根据下面的示例编辑;
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace LuaEditor
{
public static partial class ToLuaSettings
{
static ToLuaSettings()
{
// 添加代理绑定
//customDelegateList.Add(_DT(typeof(System.Action)));
// 添加绑定类型
//customTypeList.Add(_GT(typeof(ParticleSystem.MainModule)));
// 添加类成员过滤(不生成此成员绑定)
//memberFilter.Add("MeshRenderer.receiveGI");
// 添加不需要绑定的类
//dropType.Add(typeof(Plane));
}
}
}
```
然后依次点击`Clear warp files`和`Generate All`重新生成所有绑定文件。
## 框架使用流程
### 1、添加资源配置路径
在开始使用前,请确保`资源配置路径表`中配置了工作路径。配置的路径中的资源和Lua代码才能热更新
### 2、LuaMonoBehaviour组件检查器说明
`LuaMonoBehaviour`组件被设计成可以替换其他C#脚本组件,所以检查器面板功能相似。具体如下实例说明;

* `使用主引擎` 框架支持多引擎,但是一般使用主引擎就可以。
* `Lua组件模块` 对应Lua代码中的组件实现文件`require`路径,在编辑器中可以拖动对应的Lua文件到此处以自动设置。
* `启用Update` 由于效率问题所以Update类函数,是在Lua端实现的。只有启用Update Lua实现组件才会回调`Update()`
* `启用LateUpdate` 同上
* `启用FixedUpdate` 同上
* `变量绑定` 可以绑定数值、字符串、布尔值、对象、游戏对象,组件、颜色、向量和LayerMask等到Lua实现组件里面,通过变量名称直接调用。
1、 如果绑定的变量是`LuaMonoBehaviour`组件,则对应在Lua实现组件里面绑定是该`LuaMonoBehaviour`组件对应的Lua实现组件实例。说明这两个组件在Lua里面可以直接调用(需要在相同引擎中)。
2、如果想绑定复杂数据类型,可以通过修饰变量名称实现。
例如数组;
```
数组类型使用 名称#序号
变量名称 var#1 -> 123
变量名称 var#2 -> "test"
在Lua实现组件里面使用
self.var -> [ 123, "test" ]
```
例如对象;
```
对象类型使用 名称.成员
变量名称 var.t1 -> 123
变量名称 var.t2 -> "test"
在Lua实现组件里面使用
self.var -> { t1 = 123, t2 = "test" }
```
例如更复杂对象或数组;
```
变量名称 var#1.t -> 123
变量名称 var#2.t -> "test"
在Lua实现组件里面使用
self.var -> [ { t = 123 }, { t = "test" } ]
```
更复杂的对象可以自己尝试组合
对比下面的C#实现的组件,面板上的功能基本一致。

### 3、LuaMonoBehaviour组件对应的Lua实现说明
`LuaMonoBehaviour`组件在Lua中都应该有对应的实现,也就是`Lua组件模块`所对应的文件。
例如下面`Scripts/Managers/GameManager`组件模块所对应的文件内容;
```
local GameManager = class("GameManager", require("unity.LuaMonoBehaviour"))
function GameManager:Start()
self:SpawnAllTanks()
self:SetCameraTargets()
coroutine.start(function()
self:GameLoop()
end)
end
...
return GameManager
```
`unity.LuaMonoBehaviour`是Lua实现组件的基类,`class`是框架中模拟类的函数。`Start()`等生命周期函数和C#组件中的一致。
对比下面的C#实现的组件,基本一致。
```
public class GameManager : MonoBehaviour
{
private void Start()
{
// Lua有更方便的协程处理方式,这里在Lua中不需要
m_StartWait = new WaitForSeconds(m_StartDelay);
m_EndWait = new WaitForSeconds(m_EndDelay);
SpawnAllTanks();
SetCameraTargets();
StartCoroutine(GameLoop());
}
...
}
```
框架中的协程实现如下,基本完全可以替代C#的协程使用;
* `coroutine.start(fn)` 使用指定函数启动协程。
* `coroutine.sleep(time)` 在协程中等待指定时间。
* `coroutine.step(frame)` 在协程中等待指定帧数。
* `coroutine.waitasync(ao)` 在协程中等待异步操作完成。
* `coroutine.waituntil(fn)` 在协程中等待直到fn函数返回true。
可以在`lun-framework-client/Source/Lua`中查看源码,了解更多功能。
### 4、框架Lua中资源检查更新与加载释放
框架Lua使用`AssetManager`管理资源,通过`local assetManager = require("unity.AssetManager")`引入。资源管理器有如下功能;
* `检查更新` 通过调用`assetManager:CheckUpdateAsync(remoteURL)`或者`assetManager:CheckUpdate(remoteURL)`完成。
特别注意:`AssetManager`中的函数通常有两种实现方式,以后缀`Async`表示的异步实现和没有后缀表示的同步实现。特别注意`Async`异步实现需要在协程中调用。例如;
```
coroutine.start(function()
local result = assetManager:CheckUpdateAsync("http://localhost/AssetBundles/PC/")
if result then
print("需要更新")
end
end)
```
* `更新资源` 通过调用`assetManager:UpdateAssetsAsync(OnProgress, OnMessage)`或者`assetManager:UpdateAssets(OnProgress, OnMessage)`完成。
* `加载场景` 通过调用`assetManager:LoadSceneAsync(assetPath, isAdditive)`或者`assetManager:LoadScene( assetPath, isAdditive)`完成。
`assetPath`表示资源路径,类似Resources.Load使用方式。
特别注意`assetPath`路径中的目录解析为`assetBundleName`,文件解析为`assetName`。
* `加载资源` 通过调用`assetManager:LoadAssetAsync(assetPath)`或者`assetManager:LoadAsset(assetPath)`完成。也可以通过`assetManager:LoadAssetsAsync(assetPaths)`或者`assetManager:LoadAssets(assetPaths)`加载多个资源。
* `卸载资源包` 通过调用`assetManager:UnloadAssetBundle(assetBundleName, unloadObjects)`完成。但是只能卸载通过加载场景或者资源触发的资源包。