基本操作

MyLua.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class MyLua : MonoBehaviour
{
    //Lua代码,模拟lua调用c#
    private string luaScript = @"
            -- Lua调用C#时,需要在C#的命名空间之前加入前缀CS
            local GameObject = CS.UnityEngine.GameObject --获取C#中的类
            local Debug = CS.UnityEngine.Debug --获取C#中的方法
            local web = GameObject('baidu')
            Debug.Log(web.name)
            local myCamera = GameObject.Find('Main Camera')
            Debug.Log(myCamera.name)
        ";
    void Start()
    {
        //创建Xlua虚拟机,全局有且只有一个
        LuaEnv luaEnv = new LuaEnv();
        //C#代码内执行Lua代码,不常用
        luaEnv.DoString("print('helloworld')");
        //C#调用外部的Lua代码文件
        //执行在resource文件夹中的lua文件,只支持txt bytes等
        //因为不能识别.lua文件,因此脚本名需要为test.lua.txt
        luaEnv.DoString("require 'test'");
        //C#获取Lua代码中的数据
        //调用数值
        int a = luaEnv.Global.Get<int>("a");
        //调用字符串
        string b = luaEnv.Global.Get<string>("b");
        //调用布尔变量
        bool c = luaEnv.Global.Get<bool>("c");
        //调用函数
        LuaFunction d = luaEnv.Global.Get<LuaFunction>("d");
        Debug.Log(a);
        Debug.Log(b);
        Debug.Log(c);
        //执行函数
        d.Call();
        //Lua调用C#
        luaEnv.DoString(luaScript);
    }
}

test.lua.txt

print('hello world')
a=123
b='test'
c=false
function d()
    print('ddd')
end

HotFix热补丁

环境初始化步骤

  • 增加宏信息:File->BuildSetting->PlayerSetting->Player->Configuration->ScriptingDefineSymbols:HOTFIX_ENABLE
  • 执行菜单生成命令:Xlua->GenerateCode,会生成一大堆Wrap文件,存放到Xlua/Gen文件夹下
  • 执行菜单注入命令:Xlua->HotfixInjectInEditor,成功之后会在控制台输出成功消息,若失败注意要将Tools放到与Assets同级目录

热补丁演示

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
//需要添加Hotfix标签,表示该类可以被热修复
[Hotfix]
public class MyHotfix : MonoBehaviour
{
    private LuaEnv luaEnv;
    private string luaHotScript = @"
            xlua.hotfix(CS.MyHotfix, 'Hello', function()
                print('Lua Hello')
            end)
            
            xlua.hotfix(CS.MyHotfix, 'Add', function(self, a, b)
                print('Lua ' .. a+b)
            end)
        ";
    void Start()
    {
        luaEnv = new LuaEnv();
    }
    private void Hello()
    {
        Debug.Log("C# Hello");
    }
    private void Add(int a,int b)
    {
        Debug.Log("C# " + (a + b));
    }
    void Update()
    {
        //直接按A执行的是C#代码,按空格后再按A执行的是lua热修复代码
        if (Input.GetKeyDown(KeyCode.A))
        {
            Hello();
            Add(10, 5);
        }
        if (Input.GetKeyDown(KeyCode.Space))
        {
            luaEnv.DoString(luaHotScript);
        }
    }
}

注意:

  • 每次修改完C#都要执行一次注入命令
  • 有参方法修复时,需要传递当前脚本对象this,在lua中用self代替

加载外部文件热修复

MyHotfix2.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
//需要添加Hotfix标签,表示该类可以被热修复
[Hotfix]
public class MyHotfix2 : MonoBehaviour
{
    private void Hello()
    {
        Debug.Log("C# Hello");
    }
    private void Add(int a, int b)
    {
        Debug.Log("C# " + (a + b));
    }
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            Hello();
            Add(10, 5);
        }
    }
}

HotfixManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class HotfixManager : MonoBehaviour
{
    private LuaEnv luaEnv;
    void Awake()
    {
        luaEnv = new LuaEnv();
        luaEnv.DoString("require 'luaFix'");
    }
}

luaFix.lua.txt

xlua.hotfix(CS.MyHotfix2, 'Add', function(self, a, b)
    print('Lua ' .. a+b)
end)
print('over')

有参游戏逻辑修复

HotfixManager代码不变

CreateWall.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
/// <summary>
/// 无参 公开字段
/// </summary>
[Hotfix]
public class CreateWall : MonoBehaviour
{
    public GameObject cube;
    private void CreateCubeWall(GameObject prefab)
    {
        for (int i = 0; i < 10; i++)
        {
            for (int j = 0; j < 10; j++)
            {
                Instantiate(prefab, new Vector3(i, j, 0), Quaternion.identity);
            }
        }
    }
    void Start()
    {
        CreateCubeWall(cube);
    }
}

luaFix.lua.txt

local GameObject = CS.UnityEngine.GameObject
local Vector3 = CS.UnityEngine.Vector3
local Quaternion = CS.UnityEngine.Quaternion

xlua.hotfix(CS.CreateWall, 'CreateCubeWall', function (self, prefab)
    for i=1,3,1 do
        for j=1,3,1 do
            GameObject.Instantiate(prefab, Vector3(i, j, 0), Quaternion.identity);
        end
    end
end)

print('over')

无参游戏物体逻辑修复

两种解决方式

  • 方法1:可以在lua代码内通过“self.字段名“进行访问,前提是该字段必须是public修饰的,可能会破坏C#语言的”封装性“
  • 方法2:在lua语言中,使用代码获取C#类中private对象的访问权:xlua.private_accessible(CS.类名)就可以在lua脚本中访问到C#类中的私有成员,同时不会破坏C#语言的”封装性“和逻辑关系

CreateWall.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
/// <summary>
/// 无参 公开字段
/// </summary>
[Hotfix]
public class CreateWall2 : MonoBehaviour
{
    public GameObject cube;

    private void CreateCubeWall()
    {
        for (int i = 0; i < 10; i++)
        {
            for (int j = 0; j < 10; j++)
            {
                Instantiate(cube, new Vector3(i, j, 0), Quaternion.identity);
            }
        }
    }
    void Start()
    {
        CreateCubeWall();
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
/// <summary>
/// 无参 私有字段
/// </summary>
[Hotfix]
public class CreateWall3 : MonoBehaviour
{
    private GameObject cube;

    private void CreateCubeWall()
    {
        for (int i = 0; i < 10; i++)
        {
            for (int j = 0; j < 10; j++)
            {
                Instantiate(cube, new Vector3(i, j, 0), Quaternion.identity);
            }
        }
    }
    void Start()
    {
        cube = Resources.Load<GameObject>("Cube");
        CreateCubeWall();  
}

luaFix.lua.txt

--方法1
xlua.hotfix(CS.CreateWall2, 'CreateCubeWall', function (self)
    for i=1,3,1 do
        for j=1,3,1 do
            GameObject.Instantiate(self.cube, Vector3(i, j, 0), Quaternion.identity);
        end
    end
end)

--方法2
xlua.private_accessible(CS.CreateWall3)
xlua.hotfix(CS.CreateWall3, 'CreateCubeWall', function (self)
    for i=1,3,1 do
        for j=1,3,1 do
            GameObject.Instantiate(self.cube, Vector3(i, j, 0), Quaternion.identity);
        end
    end
end)

print('over')