从零开始的SLua(一)——热更新原理及SLua的第一个Demo剖析

换工作后改做手游需要使用Lua来进行热更新,以前也没接触过Lua,这篇博客算是记录一些学习心得和资料

写这篇博客是接触Lua的第三天,有错误的地方还请大神们指正,Lua语法之类的就不提了,我们从热更新的原理机制开始:

什么是热更新?
为什么要使用Lua进行热更新?
Unity是如何使用Lua进行热更新的?

知乎这个问题的觉得下面已经给出了不少解释,其中一个回答又很好的解释了为什么Unity没有原生的热更新方案,看完这个我又开始疑问编译器和解释器的区别是什么?静态语言和脚本语言的本质区别又是什么?这篇博客给出了非常生形象的解释,然后,我们就可以深入到问题的核心:CIL,大佬也在博客里进行了详细的解释

至此,前两个问题我的理解如下:
1、作为 Unity 游戏来说,热更新即在游戏运行的过程中,编译并运行修改后的新代码
2、因为Ios 通过设置内存 No eXecute 限制了 JIT 的使用,而 Lua 可以通过 AoT 等方式编译运行

第三个问题,目前的方案是SLua, SLua使用起来非常简单方便,但不搞清楚其实现机制,用起来总是会心里没底,而SLua没有完全开源,其源码也少有注释,硬啃源码还是比较吃力

所以,在细究SLua的原理之前,得知道 Lua 和 C/C++ 通常是如何交互的,这篇博客给出了不错的解释,Lua 和 C 交互的核心就是栈,Lua 库也提供了大量 API 用来在 C 中对栈进行操作从而实现 Lua 和 C 的数据交换和函数调用

有了这些前置知识,我们开始看 Slua Unity 的第一个Demo

public class Circle : MonoBehaviour {


    LuaSvr svr;
    LuaTable self;
    LuaFunction update;

    [CustomLuaClass]
    public delegate void UpdateDelegate(object self);

    UpdateDelegate ud;

    void Start () {
        svr = new LuaSvr();
        svr.init(null, () =>
        {
            self = (LuaTable)svr.start("circle/circle");
            update = (LuaFunction)self["update"] ;
            ud = update.cast<UpdateDelegate>();
        });
    }

    void Update () {
        if (ud != null) ud(self);
    }
}

首先是 LuaSvr, LuaSvr 其实是对 Lua_State 的一个封装, 而 Lua_State 在这篇博客有详细的解释,主要是管理一个lua虚拟机的执行环境, 通过名为 L 的 int 指针作为 ref

接下来是 svr.init 其实是将 UnityEngine 的一些常用函数压栈以便接下来在 Lua 中调用,在 Editor 中具体调用如下:

IntPtr L = mainState.L;
LuaObject.init(L);
if (!UnityEditor.EditorApplication.isPlaying)
{
    doBind(L);
    doinit(mainState, flag);
    complete();
    mainState.checkTop();
}

LuaObject.init(L)我们先跳过,其中 dobind

static internal void doBind(IntPtr L)
{
    var list = collectBindInfo ();

    int count = list.Count;
    for (int n = 0; n < count; n++)
    {
        Action<IntPtr> action = list[n];
        action(L);
    }
}

调用了 list 中所有的委托,现在看看 list 里面存储了什么

        static List<Action<IntPtr>> collectBindInfo() {

            List<Action<IntPtr>> list = new List<Action<IntPtr>>();

            #if !SLUA_STANDALONE
            #if !USE_STATIC_BINDER
            Assembly[] ams = AppDomain.CurrentDomain.GetAssemblies();

            List<Type> bindlist = new List<Type>();
            for (int n = 0; n < ams.Length;n++ )
            {
                Assembly a = ams[n];
                Type[] ts = null;
                try
                {
                    ts = a.GetExportedTypes();
                }
                catch
                {
                    continue;
                }
                for (int k = 0; k < ts.Length; k++)
                {
                    Type t = ts[k];
                    if (t.IsDefined(typeof(LuaBinderAttribute), false))
                    {
                        bindlist.Add(t);
                    }
                }
            }

            bindlist.Sort(new System.Comparison<Type>((Type a, Type b) => {
                LuaBinderAttribute la = System.Attribute.GetCustomAttribute( a, typeof(LuaBinderAttribute) ) as LuaBinderAttribute;
                LuaBinderAttribute lb = System.Attribute.GetCustomAttribute( b, typeof(LuaBinderAttribute) ) as LuaBinderAttribute;

                return la.order.CompareTo(lb.order);
            }));

            for (int n = 0; n < bindlist.Count; n++)
            {
                Type t = bindlist[n];
                var sublist = (Action<IntPtr>[])t.GetMethod("GetBindList").Invoke(null, null);
                list.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值