Lua快速入门篇(基础概述)(Yanlz+toLua+xLua)

Lua热更新》

##Lua热更新》发布说明:html

++++Lua热更新”开始了,立钻哥哥终于开始此部分的探索了。java

++++做为游戏发布迭代的重要技术:Lua热更新在网络游戏迭代更新中很是重要,特别是对于AppStore这样的平台,咱们只须要按期更新主App,原则上能够随时灵活更新咱们的以Lua热更新框架为基础的代码。node

++++固然,做为一项新引入的技术,咱们一般是以【快速入门】=>【基础夯实】=>【中级进阶】=>【高级实战】=>【立钻哥哥带您学Lua热更新】等几个阶段进行探索。linux


##Lua热更新》目录:android

#第一篇:Lua快速入门篇ios

#第二篇:Lua基础夯实篇git

#第三篇:Lua中级进阶篇github

#第四篇:Lua高级实战篇web

#第五篇:立钻哥哥带您学Lua热更新数据库




#第一篇:Lua快速入门篇

#第一篇:Lua快速入门篇

++++第一章:Lua基础概述

++++第二章:xLua教程

++++第三章:Lua基础拓展

++++第四章:立钻哥哥带您学Lua热更新




##第一章:Lua基础概述

++第一章:Lua基础概述

++++1.1Lua热更新框架

++++1.2toLua#热更新框架

++++1.3xLua热更新框架

++++1.4、立钻哥哥带您学Lua基础




###1.1Lua热更新框架

++1.1Lua热更新框架

++++toLuahttps://github.com/topameng/tolua

++++uLua: http://ulua.org/index.html

++++xLua: https://github.com/Tencent/xLua

++++C#在开发效率和运行效率平衡得很好,语言特性也比较全,是很优秀的一门语言。

++++lua被称为游戏脚本之王,在游戏领域应用比较普遍,它设计之初就考虑到嵌入式领域,好比相对它提供的特性来讲,它体积很是小,启动占资源也很少,性能是脚本里的佼佼者。

++++lua相对于C#而言,首先是它支持解析执行,进而支持热更新。(免编译对开发效率提高也很大,特别是较大的项目。)(从运行效率上说C#比最快的lua方案也要快50倍左右。)

++++IOS不能热更新,不是由于不能用反射,是由于【System.Reflection.Assembly.Load】、【System.Reflection.Emit】、【System.CodeDom.Compiler】等没法使用,Unity原生的代码逻辑,不管是之前的MonoAOT或者后来的il2cpp,都是编译成native codeiOS下是跑不了的,立钻哥哥:IOS下不能动态载入dll或者cs文件,已经编译进App的没有问题

++++立钻哥哥:以lua热更技术为基础的框架有:toLuauLuaxLuaSLuaC#light等。(ulua+ngui)(tolua+gui)(xlua+ngui)(ulua做者已再也不维护,转至tolua)(tolua的性能表现好)



++1.1.1toLua

++++toLuagitHub):https://github.com/topameng/tolua

++++toLua是一个工具,将UnityC#代码包装以后导出给Lua,同时提供了一些访问Lua的接口,使得UnityLua能够相互调用。

++++toLua#Unity静态绑定Lua的一个解决方案,它经过C#提供的反射信息分析代码生成包装的类。(它是一个用来简化在C#中集成Lua的插件,能够自动生成用于在Lua中访问Unity的绑定代码,并把C#中的常量、变量、函数、属性、类以及枚举暴露给lua。)

++++toLua#底层库是使用toLuaC语言编写),那么就须要经过C#来调用原生代码。

++++toLua#集成主要分两部分:

--第一部分:运行时须要的代码,包括一些手写的和自动生成的绑定代码;

--第二部分:编辑器相关代码,主要提供代码生成、编译lua文件等操做,具体就是Unity编辑器中提供的功能。

 

++++ToLua/Assembly-CSharp】:References/Source/ToLua/

--References/】:

--Source/】:Generate/LuaConst.cs

    ----Generate/:这个文件里面是生成的绑定代码;

    ----LuaConst.cs:这个文件是一些lua路径等配置文件;

--ToLua/】:BaseType/Core/Examples/MiscReflectionReadMe.txt

    ----BaseType/:一些基础类型的绑定代码;

    ----Core/:提供的一些核心功能,包括封装的LuaFunctionLuaTableLuaThreadLuaStateLuaEvent、调用tolua原生代码等;

    ----Examples/:示例代码;

    ----Misc/:杂项,包括LuaClientLuaCoroutine(协程)、LuaLooper(用于tick)、LuaResLoader(用于加载Lua文件);

    ----Reflection/:反射相关;

++++ToLua/Assembly-CSharp-Editor】:References/Editor/ToLua/

--Editor/Custom/CustomSettings.cs】:自定义配置文件,用于定义哪些类做为静态类型、哪些类须要导出、哪些附加委托须要导出等。

--ToLua/Editor】:Extend/ToLuaExport.csToLuaMenu.csToLuaTree.cs

    ----Extend/:扩展一些类的方法;

    ----ToLuaExport.cs:真正生成Lua绑定的代码;

----ToLuaMenu.csLua菜单上功能对应的代码;

----ToLuaTree.cs:辅助树结构;

++++Generate All流程:生成绑定代码主要放在ToLuaExport.cs里面:

--GenLuaDelegates()函数】:生成委托绑定的代码,它会从CustomSettings.customDelegateList里面取出全部自定义导出的委托列表,而后把CustomSettings.customTypeList里面的全部类型中的委托根据必定规则加入到list中,最后调用ToLuaExport.GenDelegates()方法来生成委托绑定的代码,生成的代码在DelegateFactory.cs文件中。(立钻哥哥:该函数的详细实现可查看ToLuaExport.cs中的函数实现。)

--GenerateClassWraps()函数】:遍历全部须要导出的类,而后调用ToLuaExport.Generate()方法来生成类的绑定代码。



++1.1.2uLua

++++uLua.org: http://ulua.org/index.html

++++uLua:基于tolua#Lua热更新UGUI/NGUI框架。(uLua已中止维护,由toLua#代替。)

++++uLua的原理:给GameObject添加上一个C#脚本组件做为中间层,在中间层上绑定上一个Lua脚本,将Unity的全部回调接口经过中间层传递到Lua。(Lua脚本也能够经过中间层操做GameObject。)

++++uLua要使用最新版本,早期的uLua是使用反射机制,脚本的运行效率比较糟糕,新的uLua集成了cstolua,预先生成一批代码把Unity的类和函数导出给lua,而后lua再调用,这样不管是效率仍是GC的角度说都是比较完美的。


++1.1.3xLua

++++xLua官方: https://github.com/Tencent/xLua

++++xLuaUnity3DLua编程解决方案,腾讯已将xLua开源到GitHub

++++xLua20153月完成第一个版本;201612月末,xLua实现新的突破:全平台支持用Lua修复C#代码bug

++++xLuaUnity.NetMonoC#环境增长Lua脚本编程的能力,借助xLua,这些Lua代码能够方便和C#相互调用。(xLua在功能、性能、易用性都有很多突破。)

++++xLua的突破:1、能够运行时把C#实现(方法,操做符,属性,事件等等)替换成lua实现;2、出色的GC优化,自定义struct,枚举在LuaC#间传递无C# gc alloc3、编辑器下无需生成代码,开发更轻量。

++++xLua热补丁技术支持在运行时把一个C#实现(函数,操做符,属性,事件,或者整个类)替换成Lua实现,意味着咱们能够:1、平时用C#开发;2、运行也是C#,性能秒杀Lua3、有bug的地方下发个Lua脚本fix了,下次总体更新时能够把Lua的实现换回正确的C#实现,更新时甚至能够作到不重启游戏;

++++xLua热修复框架工程结构参考:

 

++++Resource/xLua/Main.lua】:xlua热修复入口。

++++Resource/xLua/Common/】:提供给lua代码使用的一些工具方法,提供lua逻辑代码到C#调用的一层封装。

++++Scripts/xLua/XLuaManager.cs】:xLua热修复环境,包括luaState管理,自定义loader

++++Scripts/xLua/Util/】:为xLualua脚本提供的C#侧代码支持,被Resources/xLua/Common/所使用。

++++Scripts/HotfixTest】:须要热修复的C#脚本。

++++Resource/xLua/HotFix】:热修复脚本。




###1.2toLua#热更新框架

++1.2toLua#热更新框架

++++toLuahttps://github.com/topameng/tolua

++++toLua#Unity静态绑定lua的一个解决方案,它经过C#提供的反射信息分析代码并生成包装的类。它是一个用来简化在C#中集成lua的插件,能够自动生成用于在lua中访问Unity的绑定代码,并把C#中的常量、变量、函数、属性、类以及枚举暴露给lua

++++Unity C#<==>Tolua#<==>Tolua(c)

++++toLua特性:

--自动生成绑定代码文件,非反射调用;

--大量内建基础类型支持,如枚举,委托,事件,Type,数组,迭代器等;

--支持多种协同形式;

--支持全部unity内部类导出,支持委托类型导出;

--支持导出自定义,跳过某个空的基类,修改导出名称等;

--支持扩展函数自定义导出,好比DoTween

--支持值类型Nullable导出,包括Nullable<Vector3>等;

--支持Luafunction转委托,能够区分须要不一样委托的参数的重载函数;

--支持C# LuaFunction对象转委托,简化调用方式。支持无GC的多参数调用形式;

--支持重载函数自动排序,如:参数个数相同,object参数执行级最低,不会出现错误匹配状况;

--支持导出函数重命名,能够分离导出某个重载函数(能够导出被折叠掉的函数);

--支持使用编辑器类改写导出规则;

--支持this数组访问,索引为int能够经过[]访问,其余可以使用.get_Item或者.this.get()访问数组成员;

--支持委托(事件)+-lua function。支持经过函数接口的AddRemove委托操做;

--支持静态反射操做,形式同C#

--支持peer表,可在lua端扩展导出的userdata

--支持自定义struct压入和读取,作到无GC,而且结构成员无类型限制;

--支持preloading,能够经过require后绑定wrap文件;

--支持int64unit64

--大量的lua数学类型,如Quaternion, Vector3, Mathf等;

--包含第三方lua扩展,包括luasocket, struct, lpeg, utf8, pb等库;

--lua出现异常,可以同时捕获C#端和lua端堆栈,便于调试;

--print信息,在编辑器点击日志,能自动打开对应lua文件;

--支持unity全部版本;

--支持Lua hook C#代码实现,必定程度上支持利用Lua代码修改C#端代码的bug

++++tolua#集成主要两部分:1、运行时须要的代码包括一些手写和自动生成的绑定代码,2、编辑器相关代码,主要提供代码生成、编译lua文件等操做,具体就是Unity编辑器中提供的功能。



++1.2.1、【MenuItem(“Lua/Generate All”)】流程

++++ToLuaMenu.cs/GenLuaAll()GenLuaDelegates()GenerateClassWraps()GenLuaBinder()

--GenLuaDelegate()】:生成委托绑定代码,它会从CustomSettings.customDelegateList里面取出全部自定义导出的委托列表,而后把CustomSettings.customTypeList里面的全部类型中的委托根据必定规则加入到list中,最后调用ToLuaExport.GenDelegates()方法来生成委托绑定的代码,生成的代码在DelegateFactory.cs文件中。

--GenerateClassWraps()】:遍历全部须要导出的类,而后调用ToLuaExport.Generate()方法来生成类的绑定代码。

--GenLuaBinder()】:生成向lua注册C#类的绑定代码,这个代码存放在LuaBinder.cs文件中,这部分代码中不包含BaseTypeArrayEnumObjectString等等)的注册。

//立钻哥哥:GenLuaAlltolua-master-\Assets\ToLua\Editor\ToLuaMenu.cs

using UnityEngine;

using UnityEditor;

using System;

 

[InitializeOnLoad]

public static class ToLuaMenu{

    [MenuItem(Lua/Generate All, false, 5)]

    static void GenLuaAll(){

        if(EditorApplication.isCompiling){

            EditorUtility.DisplayDialog(立钻哥哥警告, 请等待编辑器完成编译再执行此功能, 肯定);

            return;

        }

 

        beAutoGen = true;

        GenLuaDelegates();

        AssetDatabase.Refresh();

        GenerateClassWraps();

        GenLuaBinder();

        beAutoGen = false;

    }

 

    [MenuItem(Lua/Gen Lua Delegates, false, 2)]

    static void GenLuaDelegates(){

        if(!beAutoGen && EditorApplication.isCompiling){

            EditorUtility.DisplayDialog(立钻哥哥警告, 请等待编辑器完成编译再执行此功能, 肯定);

            return;

        }

 

        ToLuaExport.Clear();

        List<DelegateType> list = new List<DelegateType>();

        list.AddRange(CustomSettings.customDelegateList);

        HashSet<Type> set = GetCustomTypeDelegates();

 

        foreach(Type t in set){

            if(null == list.Find((p)=>{  return p.type == t;  })){

                list.Add(new DelegateType(t));

            }

        }

 

        ToLuaExport.GenDelegates(list.ToArray());

        set.Clear();

        ToLuaExport.Clear();

        AssetDatabase.Refresh();

 

        Debug.Log(立钻哥哥:Create lua delegate over!);

    }

 

    [MenuItem(Lua/Gen Lua Wrap Files, false, 1)]

    public static void GenerateClassWraps(){

        if(!bAutoGen && EditorApplication.isCompiling){

            EditorUtility.DisplayDialog(立钻哥哥警告, 请等待编辑器完成编译再执行此功能, 肯定);

            return;

        }

 

        if(!File.Exists(CustomSettings.saveDir)){

            Directory.CreateDirectory(CustomSettings.saveDir);

        }

 

        allTypes.Clear();

        BindType[] typeList = CustomSettings.customTypeList;

 

        BindType[] list = GenBindTypes(typeList);

        ToLuaExport.allTypes.AddRange(baseType);

 

        for(int i = 0;  i < list.Length;  i++){

            ToLuaExport.allTypes.Add(list[i].type);

        }

 

        for(int i = 0;  i < list.Length;  i++){

            ToLuaExport.Clear();

            ToLuaExport.className = list[i].name;

            ToLuaExport.type = list[i].type;

            ToLuaExport.isStaticClass = list[i].IsStatic;

            ToLuaExport.baseType = list[i].baseType;

            ToLuaExport.wrapClassName = list[i].wrapName;

            ToLuaExport.libClassName = list[i].libName;

            ToLuaExport.extendList = list[i].extendList;

            ToLuaExport.Generate(CustomSettings.saveDir);

        }

 

        Debug.Log(立钻哥哥:Generic lua binding files over!);

        ToLuaExport.allTypes.Clear();

        allTypes.Clear();

        AssetDatabase.Refresh();

    }

 

    [MenuItem(Lua/Gen LuaBinder File, false, 4)]

    static void GenLuaBinder(){

        if(!beAutoGen && EditorApplication.isCompiling){

            EditorUtility.DisplayDialog(立钻哥哥警告, 请等待编辑器完成编译再执行此功能, 肯定);

            return;

        }

 

        allTypes.Clear();

        ToLuaTree<string> tree = InitTree();

        StringBuilder sb = new StringBuilder();

        List<DelegateType> dtList = new List<DelegateType>();

 

        List<DelegateType> list = new List<DelegateType>();

        list.AddRange(CustomSetting.customDelegateType);

        HashSet<Type> set = GetCustomTypeDelegates();

 

        List<BindType> backupList = new List<BindType>();

        backupList.AddRange(allTypes);

        ToLuaNode<string> root = tree.GetRoot();

        string libname = null;

 

        foreach(Type t in set){

            if(null == list.Find(p) => {  return p.type == t;  }){

                DelegateType dt = new DelegateType(t);

                AddSpaceNameToTree(tree, root, ToLuaExport.GetNameSpace(t, out libname));

                list.Add(dt);

            }

        }

 

        sb.AppendLineEx(//立钻哥哥:this source code was auto-generated by tolua#, do not modify it);

        sb.AppendLineEx(using System);

        sb.AppendLineEx(using UnityEngine);

        sb.AppendLineEx(using LuaInterface);

        sb.AppendLineEx();

        sb.AppendLineEx(public static class LuaBinder);

        sb.AppendLineEx({);

        sb.AppendLineEx(\tpublic static void Bind(LuaState L));

        sb.AppendLineEx(\t{);

        sb.AppendLineEx(\t\tfloat t = Time.realtimeSinceStartup;);

        sb.AppendLineEx(\t\tL.BeginModule(null););

 

        GenRegisterInfo(null, sb, list, dtList);

 

        Action<ToLuaNode<string>> begin = (node)=>{

            if(node.value == null){

                return;

            }

 

            sb.AppendFormat(\t\tL.BeginModule(\{0}\);\r\n, node.value);

            string space = GetSpaceNameFromTree(node);

 

            GenRegisterInfo(space, sb, list, dtList);

        };

 

        Action<ToLuaNode<string>> end = (node) =>{

            if(node.value != null){

                sb.AppendLineEx(\t\tL.EndModule(););

            }

        };

 

        tree.DepthFirstTraversal(begin, end, tree.GetRoot());

        sb.AppendLineEx(\t\tL.EndModule());

 

        if(CustomSettings.dynamicList.Count > 0){

            sb.AppendLineEx(\t\tL.BeginPreLoad(););

 

            for(int i = 0;  i < CustomSettings.dynamicList.Count;  i++){

                Type t1 = CustomSettings.dynamicList[i];

                BindType bt = backupList.Find((p)=>{  return p.type == t1;  });

                if(bt != null){

                    sb.AppendFormat(\t\tL.AppPreLoad(\{0}\, LuaOpen_{1}, typeof({0}));\r\n, bt.name, bt.wrapName);

                }

            }

 

            sb.AppendLineEx(\t\tL.EndPreLoad(););

        }

 

        sb.AppendLineEx(\t\tDebugger.Log(\立钻哥哥:Register lua type cost time: {0}\, Time.realtimeSinceStartup - t););

        sb.AppendLineEx(\t});

 

        for(int i = 0; i < dtList.Count;  i++){

            ToLuaExport.GenEventFunction(dtList[i].type, sb);

        }

 

        if(CustomSettings.dynamicList.Count > 0){

            for(int i = 0;  i < CustomSettings.dynamicList.Count;  i++){

                Type t = CustomSettings.dynamicList[i];

                BindType bt = backupList.Find((p)=>{  return p.type == t;  });

                if(bt != null){

                    GenPreLoadFunction(bt, sb);

                }

            }

        }

 

        sb.AppendLineEx(}\r\n);

        allTypes.Clear();

        string file = CustomSettings.saveDir + LuaBinder.cs;

 

        using(StreamWriter textWriter = new StreamWriter(file, false, Encoding.UTF8)){

            textWriter.Write(sb.ToString());

            textWriter.Flush();

            textWriter.Close();

        }

 

        AssetDatabase.Refresh();

 

        Debugger.Log(立钻哥哥:Generate LuaBinder over!);

    }

 

}    //立钻哥哥:public static class ToLuaMenu{}

 


++1.2.2、【ToLuaExport.cs/Generate()】流程

++++ToLuaExport.Generate()基本流程:若是这个类是枚举类型,那么会调用枚举导出的接口,若是这个类型是一个普通的类,那么就会调用相应的流程将代码导出。

 

//立钻哥哥:Generate()流程(tolua-master-\Assets\ToLua\Editor\ToLuaExport.cs

using UnityEngine;

using System;

 

public static class ToLuaExport{

    public static void Generate(string dir){

        #if !EXPORT_INTERFACE

        Type iterType = typeof(System.Collections.IEnumerator);

        if(type.IsInterface && type != iterType){

            return;

        }

        #endif

 

        Debugger.Log(立钻哥哥:Begin Generate lua Wrap for class {0}, className);

        sb = new StringBuilder();

        usingList.Add(System);

 

        if(wrapClassName == “”){

            wrapClassName = className;

        }

 

        if(type.IsEnum){

            BeginCodeGen();

            GenEnum();

            EndCodeGen(dir);

            return;

        }

 

        InitMethods();

        InitPropertyList();

        InitCtorList();

 

        BeginCodeGen();

 

        GenRegisterFunction();

        GenConstructFunction();

        GenItemPropertyFunction();

        GenFunctions();

        //GenToStringFunction();

        GenIndexFunc();

        GenNewIndexFunc();

        GenOutFunction();

        GenEventFunctions();

 

        EndCodeGen(dir);

    }

 

    static void BeginCodeGen(){

        sb.AppendFormat(public class {0}Wrap\r\n, wrapClassName);

        sb.AppendLineEx({);

    }

 

    static void GenEnum(){

        fields = type.GetFields(BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static);

        List<FieldInfo> list = new List<FieldInfo>(fields);

 

        for(int i = list.Count - 1;  i > 0;  i--){

            if(IsObsolete(list[i])){

                list.RemoveAt(i);

            }

        }

 

        fields = list.ToArray();

 

        ....  //立钻哥哥:此处省略一万字

    }

 

    static void EndCodeGen(string dir){

        sb.AppendLineEx(}\r\n);

        SaveFile(dir + wrapClassName + Wrap.cs);

    }

 

    static void InitMethods(){

        bool flag = false;

    

        if(baseType != null || isStaticClass){

            binding |= BindingFlags.DeclaredOnly;

            flag = true;

        }

 

        List<_MethodBase> list = new List<_MethodBase>();

        MethodInfo[] infos = type.GetMethods(BindingFlags.Instance | binding);

 

        for(int i = 0;  i < infos.Length;  i++){

            list.Add(new _MethodBase(infos[i]));

        }

 

        ....    //立钻哥哥:此处省略一万字

    }

 

    static void InitPropertyList(){

        props = type.GetProperties(BindingFlags.GetProperty | BindingFlags.SetProperty | BindingFlags.Instance | binding);

        propList.AddRange(type.GetProperties(BindingFlags.GetProperty | BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase));

        fields = type.GetFields(BindingFlags.GetField | BindingFlags.SetField | BindingFlags.Instance | binding);

        events = type.GetEvents(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);

        eventList.AddRange(type.GetEvents(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public));

 

        List<FieldInfo> fieldList = new List<FieldInfo>();

        fieldList.AddRange(fields);

 

        ....    //立钻哥哥:此处省略一万字

    }

 

    static void InitCtorList(){

        if(isStaticClass || type.IsAbstract || typeof(MonoBehaviour).IsAssignableFrom(type)){

            return;

        }

 

        ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Instance | binding);

 

        ....    //立钻哥哥:此处省略一万字

    }

 

    static void BeginCodeGen(){

        sb.AppendFormat(public class {0}Wrap\r\n, wrapClassName);

        sb.AppendLineEx({);

    }

 

    static void GenRegisterFunction(){

        sb.AppendLineEx(\tpublic static void Register(LuaState L));

        sb.AppendLineEx(\t{);

    

        ....

 

        GenRegisterFuncItems();

        GenRegisterOpItems();

        GenRegisterVariables();

        GenRegisterEventTypes();    //立钻哥哥:注册事件类型

 

        ....

    }

 

    static void GenConstructFunction(){

        ....

    }

 

    //立钻哥哥:this[] 非静态函数

    static void GenItemPropertyFunction(){

        ....

    }

 

    static void GenFunctions(){

        HashSet<string> set = new HashSet<string>();

 

        ....

    }

 

    static void GenIndexFunc(){

        ....

    }

 

    static void GenNewIndexFunc(){

        ....

    }

 

    static void GenOutFunction(){

        if(isStaticClass || CustomSettings.outList.IndexOf(type) < 0){

            return;

        }

 

        sb.AppendLineEx(\r\n\r[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]);

        sb.AppendLineEx(\tstatic int get_out(IntPtr L));

        sb.AppendLineEx(\t{);

        sb.AppendFormat(\t\tToLua.PushOut<{0}>(L, new LuaOut<{0}>());\r\n, className);

        sb.AppendLineEx(\t\treturn 1;);

        sb.AppendLineEx(\t});

    }

 

    static void GenEventFunctions(){

        foreach(Type t in eventSet){

            GetEventFunction(t, sb);

        }

    }

 

    static void EndCodeGen(string dir){

        sb.AppendLineEx(}\r\n);

        SaveFile(dir + wrapClassName + Wrap.cs);

    }

 

}    //立钻哥哥:public static class ToLuaExport{}



++1.2.3toLua#核心运行时

++++toLua#的运行代码包含【Source/Generate/】下的绑定代码,以及【ToLua/BaseType/】代码,以及【ToLua/Core/】下的核心代码。

++++LuaAttribute.cs】:在toLua#生成绑定代码时作一些标示使用。

++++LuaBaseRef.cs】:Lua中对象对应C#中对象的一个基类,主要做用是用一个reference指向lua里面的对象,引用计数判断两个对象是否相等。(好比:LuaFunction里面的reference是指向lua里面的一个闭包的,而LuaTablereference是指向lua中的一个table的。)

++++LuaDll.cs】:这个类的主要做用就是实现了C#调用原生代码的功能。

++++LuaState.cs】:对真正的lus_State的封装,包括初始化lua路径,加载相应的lua文件,注册生成的绑定代码以及各类辅助函数。

++++ObjectTranslator.cs】:给lua中对C#对象的交互提供了基础,简单来讲就是C#中的对象在传给lua时并非直接把对象暴露给lua,而是在这个ObjectTranslator里面注册并返回一个索引(句柄),并把这个索引包装成一个userdata传递给lua,而且设置元表。(在lua须要经过传到lua里面的对象调用C#的方法时,它会调用ToLua.CheckObject或者ToLua.ToObjectObjectTranslator获取真正的C#对象。)




++1.2.4、关于反射

++++toLua#不支持动态反射。(动态反射对于重载函数有参数匹配问题,函数排序问题,ref, out参数问题等等。)

++++toLua#提供的替换方法是:

--1preloading,把将来可能须要的类型添加到导出列表customTypeList,同时也添加到dynamicList列表中,这样导出后该类型不会随binder注册到lua中,能够经过require “namespace.classname”动态注册到lua中,对于非枚举类型toLua#系统也能够在第一次push该类型时动态载入,固然也可在过场动画、资源下载、登陆、场景加载或者某个的函数中require这个类型。

--2、静态反射。经过静态反射支持精确的函数参数匹配和类型检查。不会存在重载函数参数混乱匹配错误问题。(注意iOS必须配置好link.xml

++++link.xmltolua-master-\Assets\link.xml

//立钻哥哥:link.xmliOS必须配置好link.xml

<?xml version=1.0 encoding=utf-8?>

<linker>

    <assembly fullname=mscorlib>

        <namespace fullname=System.Collections.Generic perserve=all/>

    </assembly>

</linker>



++1.2.5toLua简单示例:HelloWorld(最小的toLua#环境)

//立钻哥哥:HelloWorld示例(\Assets\ToLua\Examples\01_HelloWorld\HelloWorld.cs

using UnityEngine;

using LuaInterface;

using System;

 

public class HelloWorld : MonoBehaviour{

    void Awake(){

        LuaState myLua = new LuaState();

        myLua.Start();

        string myHello = @print(立钻哥哥:hello tolua#);

 

        myLua.DoString(myHello, HelloWorld.cs);

        myLua.CheckTop();

        myLua.Dispose();

        myLua = null;

    }

}    //立钻哥哥:public class HelloWorld : MonoBehaviour{}

++++立钻哥哥:该简单示例展现了最小的toLua#环境。

++++LuaState】封装了对lua主要数据结构lua_State指针的各类堆栈操做。

++++通常对于客户端,推荐只建立一个LuaState对象。(若是要使用多State须要在Unity中设置全局宏MULTI_STATE

++++LuaState.Start()】:须要在toLua代码加载到内存后调用。(若是使用assetbundle加载lua文件,调用Start()以前assetbundle必须加载好)

++++LuaState.DoString()】:执行一段lua代码。(比较少用这种方式加载代码,没法避免代码重复加载覆盖等状况,需调用者本身保证。第二个参数用于调试信息,或者error消息(用于提示出错代码所在文件名称。))

++++LuaState.CheckTop()】:检查堆栈是否平衡,通常放在update中,C#中任何使用lua堆栈操做,都须要调用者本身平衡堆栈,当CheckTop出现警告时其实早已经离开了堆栈操做范围,这是需自行review代码。

++++LuaState.Dispose()】:释放LuaState以及其资源。


++1.2.6toLua简单示例:ScriptsFromFileDoFileRequire的区别)

//立钻哥哥:ScriptsFromFile示例(\ToLua\Examples\02_ScriptsFromFile\ScriptsFromFile.cs

using UnityEngine;

using System.Collections;

using LuaInterface;

using System;

using System.IO;

 

//立钻哥哥:展现searchpath使用,requiredofile区别

public class ScriptsFromFile : MonoBehaviour{

    LuaState myLua = null;

    private string strLog = “”;

 

    void Start(){

        #if UNITY_5 || UNITY_2017 || UNITY_2018

            Application.logMessageReceived += Log;

        #else

            Application.RegisterLogCallback(Log);

        #endif

 

        myLua = new LuaState();

        myLua.Start();

 

        //立钻哥哥:若是移动了ToLua目录,手动修复配置

        string fullPath = Application.dataPath + \\ToLua/Examples/Yanlz_ScriptsFromFile;

        myLua.AddSearchPath(fullPath);

    }

 

    void Log(string msg, string stackTrace, LogType type){

        strLog += msg;

        strLog += \r\n;

    }

 

    void OnGUI(){

        GUI.Label(new Rect(100, Screen.height/2 - 100, 600, 400), strLog);

 

        if(GUI.Button(new Rect(50, 50, 120, 45), DoFile)){

            strLog = “”;

            myLua.DoFile(ScriptsFromFile.lua);

 

        }else if(GUI.Button(new Rect(50, 150, 120, 45), Require)){

            strLog = “”;

            myLua.Require(ScriptsFromFile);

        }

 

        myLua.Collect();

        myLua.CheckTop();

    }

 

    void OnApplicationQuit(){

        myLua.Dispose();

        myLua = null;

 

        #if UNITY_5 || UNITY_2017 || UNITY_2018

            Application.logMessageReceived -= Log;

        #else

            Application.RegisterLogCallback(null);

        #endif

    }

 

}    //立钻哥哥:public class ScriptsFromFile : MonoBehaviour{}

++++立钻哥哥:该示例展现了dofilerequire区别。

++++toLua#DoFile函数,和Lua保持一致行为,能屡次执行一个文件。

++++toLua#中加入了新的Require函数,不管C#lua谁先require一个lua文件,都能保证加载惟一性。

++++LuaState.AddSearchPath()】:增长搜索目录,这样DoFileRequire函数能够只用文件名,无需写全路径。

++++LuaState.DoFile()】:加载一个lua文件,注意dofile须要扩展名,可反复执行,后面的变量会覆盖以前的DoFile加载的变量。

++++LuaState.Require()】:同lua require(modname)操做,加载指定模块而且把结果写入到package.loaded中,若是modname存在,则直接返回package.loaded[modname]

++++LuaState.Collect()】:垃圾回收,对于被自动gcLuaFunctionLuaTable,以及委托减掉的LuaFunction,延迟删除的Object类等须要延迟处理的回收,都在这里自动执行。



++1.2.7toLua#示例:CallLuaFunction(调用Lua函数)

//立钻哥哥:CallLuaFunction示例(\ToLua\Examples\03_CallLuaFunction\CallLuaFunction.cs

using UnityEngine;

using System.Collections;

using LuaInterface;

using System;

 

public class CallLuaFunction : MonoBehaviour{

    private string script =

        @   

        function luaFunc(num)

            return num + 1;

        end

 

        Test = {};

       Test.luaFunc = luaFunc;

        ”;

 

    LuaFunction luaFunc = null;

    LuaState myLua = null;

    string myTips = null;

 

    void Start(){

        #if UNITY_5 || UNITY_2017 || UNITY_2018

            Application.logMessageReceived += ShowTips;

        #else

            Application.RegisterLogCallback(ShowTips);

        #endif

 

        new LuaResLoader();

        myLua = new LuaState();

        myLua.Start();

        DelegateFactory.Init();

        myLua.DoString(script);

 

        //立钻哥哥:Get the fucntion object

        luaFunc = myLua.GetFunction(test.luaFunc);

   

        if(luaFunc != null){

            int myNum = luaFunc.Invoke<int, int>(123456);

            Debugger.Log(立钻哥哥:generic call return: {0}, myNum);

 

            myNum = CallFunc();

            Debugger.Log(立钻哥哥:expansion call return: {0}, myNum);

 

            Func<int, int> myFunc = luaFunc.ToDelegate<Func<int, int>>();

            myNum = myFunc(123456);

            Debugger.Log(立钻哥哥:Delegate call return: {0}, myNum);

 

            myNum = myLua.Invoke<int, int>(test.luaFunc, 123456, true);

            Debugger.Log(立钻哥哥:luastate call return: {0}, myNum);

        }

 

        myLua.CheckTop();

    }

 

    void ShowTips(string msg, string stackTrace, LogType type){

        myTips += msg;

        myTips += \r\n;

    }

 

    #if ! TEST_GC

        void OnGUI(){

            GUI.Label(new Rect(Screen.width/2 - 200, Screen.height/2 - 150, 400, 300), myTips);

         }

    #endif

 

    void OnDestroy(){

        if(luaFunc != null){

            luaFunc.Dispose();

            luaFunc = null;

        }

 

        myLua.Dispose();

        myLua = null;

 

        #if UNITY_5 || UNITY_2017 || UNITY_2018

            Application.logMessageReceived -= ShowTips;

        #else

            Application.RegisterLogCallback(null);

        #endif

    }

 

    int CallFunc(){

        luaFunc.BeginPCall();

        luaFunc.Push(123456);

        luaFunc.PCall();

    

        int myNum = (int)luaFunc.CheckNumber();

        luaFunc.EndPCall();

 

        return myNum;

    }

 

}    //立钻哥哥:public class CallLuaFunction : MonoBehaviour{}

++++立钻哥哥:toLua#简化了lua函数的操做,经过LuaFunction封装(并缓存)一个lua函数,并提供各类操做,建议频繁调用函数使用无GC方式。

++++LuaState.GetLuaFunction()】:获取并缓存一个lua函数,此函数支持串式操做,如“test.luaFunc”表明test表中的luaFunc函数。

++++LuaState.Invoke()】:临时调用一个lua function并返回一个值,这个操做并不缓存lua function,适合频率很是低的函数调用。

++++LuaFunction.Call()】:不须要返回值的函数调用操做。

++++LuaFunction.Invoke():有一个返回值的函数调用操做。

++++LuaFunction.BeginPCall():开始函数调用。

++++LuaFunction.Push()】:压入函数调用须要的参数,经过众多的重载函数来解决参数转换gc问题。

++++LuaFunction.PCall()】:调用lua函数。

++++LuaFunction.CheckNumber()】:提取函数返回值,并检查返回值为lua number类型。

++++LuaFunction.EndPCall()】:结束lua函数调用,清除函数调用形成的堆栈变化。

++++LuaFunction.Dispose()】释放LuaFunction,递减引用计数,若是引用计数为0,则从_R表删除该函数。

++++立钻哥哥:不管Call仍是PCall只至关于lua中的函数“.”调用。(self:call(...) == self.call(self, ...)C#中须要按self.call(self, ...)方式调用,即必须主动传入第一个参数self



++1.2.8toLua#示例:AccessingLuaVariables(访问lua变量)

//立钻哥哥:AccessingLuaVariables示例(\04_AccessingLuaVariables\AccessingLuaVariables.cs

using UnityEngine;

using System.Collections.Generic;

using LuaInterface;

 

public class AccessingLuaVariables : MonoBehaviour{

    private string myScript = @

        print(立钻哥哥:Objs2Spawn is:  .. Objs2Spawn)

        var2read = 42

        varTable = { 1, 2, 3, 4, 5 }

        varTable.default = 1

        varTable.map = {}

        varTable.map.name = map

    

        meta = { name = meta }

        setmetatable(varTable, meta)

    

        function TestFunc(strs)

            print(立钻哥哥:func by variable);

        end

        ”;

 

    void Start(){

        #if UNITY_5 || UNITY_2017 || UNITY_2018

            Application.logMessageReveived += MyShowTips;

        #else

            Application.RegisterLogCallback(MyShowTips);

        #endif

 

        new LuaResLoader();

        LuaState myLua = new LuaState();

        myLua.Start();

        myLua[Objs2Spawn] = 5;

        myLua.DoString(myScript);

 

        //立钻哥哥:经过LuaState访问

        Debugger.Log(立钻哥哥:Read var from lua:{0}, lua[var2read]);

        Debugger.Log(立钻哥哥:Read table var from lua:{0}, lua[varTable.default]);

 

        LuaFunction myFunc = myLua[TestFunc] as LuaFunction;

        myFunc.Call();

        myFunc.Dispose();

 

        //立钻哥哥:cacheLuaTable进行访问

        LuaTable myTable = myLua.GetTable(varTable);

        Debugger.Log(立钻哥哥:Read varTable from lua, default:{0} name:{1}, myTable[default], myTable[map.name]);

 

        myTable[map.name] = new;    //立钻哥哥:table字符串只能是key

        Debugger.Log(立钻哥哥:Modify varTable name:{0}, table[map.name]);

 

        myTable.AddTable(newmap);

        LuaTable myTable1 = (LuaTable)myTable[newmap];

        myTable1[name] = table1;

        Debugger.Log(立钻哥哥:varTable.newmap name:{0}, myTable1[name]);

        myTable1.Dispose();

 

        myTable1 = myTable.GetMetaTable();

 

        if(myTable1 != null){

            Debugger.Log(立钻哥哥:varTable metatable name: {0}, myTable1[name]);

        }

 

        object[] myList = myTable.ToArray();

        for(int i = 0;  i < myList.Length;  i++){

            Debugger.Log(立钻哥哥:varTable[{0}], is {1}, i, myList[i]);

        }

 

        myTable.Dispose();

        myLua.CheckTop();

        myLua.Dispose();

    }

 

    private void OnApplicationQuit(){

        #if UNITY_5 || UNITY_2017 || UNITY_2018

            Application.logMessageReceived -= MyShowTips;

        #else

            Application.RegisterLogCallback(null);

        #endif

    }

 

    string myTips = null;

    void MyShowTips(string msg, string stackTrace, LogType type){

        myTips += msg;

        myTips += \r\n;

    }

 

    void OnGUI(){

        GUI.Label(new Rect(Screen.width/2 - 300, Screen.height/2 - 200, 600, 400), tips);

    }

 

}    //立钻哥哥:public class AccessingLuaVariables : MonoBehaviour{}

++++立钻哥哥:该示例展现了如何访问lua中的变量,table的操做。

++++luaState[Objs2Spawn]】:LuaState经过重载this操做符,访问lua_G表中的变量Objs2Spawn

++++LuaState.GetTable()】:从lua中获取一个lua table,能够串式访问,如:lua.GetTable(“varTable.map.name”)等同:varTable->map->name

++++LuaTable支持this操做符,但此this不支持串式访问。好比table[“map.name”]中,“map.name”只是一个key,不是table->map->name

++++LuaTable.GetMetaTable()】:能够获取当前tablemetatable

++++LuaTable.ToArray()】:获取数组表中的全部对象存入到object[]表中。

++++LuaTable.AddTable(name)】:在当前的table表中添加一个名字为name的表。

++++LuaTable.GetTable(key)】:获取t[key]值到C#,相似于lua_gettable

++++LuaTable.SetTable(key, value)】:等价于t[k]=v的操做,相似于lua_settable

++++LuaTable.RawGet(key)】:获取t[key]值到C#,相似于lua_rawget

++++LuaTable.RawSet(key, value)】:等价于t[k]=v的操做,相似于lua_rawset



++1.2.9toLua#示例:TestCoroutine(使用lua协同)

//立钻哥哥:TestCoroutine示例(\Assets\ToLua\Examples\05_LuaCoroutine\TestCoroutine.cs

using UnityEngine;

using System;

using System.Collections;

using LuaInterface;

 

public class TestCoroutine : MonoBehaviour{

    public TextAsset luaFile = null;

    private LuaState myLua = null;

    private LuaLooper myLooper = null;

 

    void Awake(){

        #if UNITY_5 || UNITY_2017 || UNITY_2018

            Application.logMessageReceived += MyShowTips;

        #else

            Application.RegisterLogCallback(MyShowTips);

        #endif

 

        new LuaResLoader();

        myLua = new LuaState();

        myLua.Start();

        LuaBinder.Bind(myLua);

        DelegateFactory.Init();

        myLooper = gameObject.AddComponent<LuaLooper>();

        myLooper.luaState = myLua;

 

        myLua.DoString(luaFile.text, TestLuaCoroutine.lua);

        LuaFunction myF = myLua.GetFunction(TestMyCoroutine);

        myF.Call();

        myF.Dispose();

        myF = null;

    }

 

    void OnApplicationQuit(){

        myLooper.Destroy();

        myLua.Dispose();

        myLua = null;

  

        #if UNITY_% || UNITY_2017 || UNITY_2018

            Applicaiton.logMessageReceived -= MyShowTips;

        #else

            Application.RegisterLogCallback(null);

        #endif

    }

 

    string myTips = null;

    void MyShowTips(string msg, string stackTrace, LogType type){

        myTips += msg;

        myTips += \r\n;

    }

 

    void OnGUI(){

        GUI.Label(new Rect(Screen.width/2 - 300, Screen.height/2 - 200, 600, 400), myTips);

 

        if(GUI.Button(new Rect(50, 50, 120, 45), Start Counter)){

            myTips = null;

            LuaFunction myFunc = myLua.GetFunction(StartDelay);

            myFunc.Call();

            myFunc.Dispose();

 

        }else if(GUI.Button(new Rect(50, 150, 120, 45), Stop Counter)){

            LuaFunction myFunc = myLua.GetFunction(StopDelay);

            myFunc.Call();

            myFunc.Dispose();

 

        }else if(GUI.Button(new Rect(50, 250, 120, 45), 立钻哥哥:GC)){

            myLua.DoString(collectgarbage(collect), TestCoroutine.cs);

            Resources.UnloadUnusedAssets();

        }

    }

 

}    //立钻哥哥:public class TestCoroutine : MonoBehaviour{}

 

//立钻哥哥:TestLuaCoroutine.lua(使用lua协同,lua代码部分)

//tolua-master-\Assets\ToLua\Examples\Resources\Lua\TestLuaCoroutine.lua.bytes

//fib函数负责计算一个斐波那契n

function fib(n)

    local a, b = 0, 1

    while n > 0 do

        a, b = b, a + b

        n = n - 1

    end

 

    return a

end

 

function CoFunc()

    print(立钻哥哥:Coroutine started!);

    for i = 0, 10, 1 do

        print(fib(i))

        coroutine.wait(0.1)

    end

 

    print(立钻哥哥:current framewCount:  .. Time.frameCount)

    coroutine.step()

    print(立钻哥哥:yield frameCount:  .. Time.frameCount);

 

    local myWww = UnityEngine.WWW(http://www.baidu.com);

    coroutine.www(myWww);

    local s = tolua.tolstring(myWww.bytes)

    print(s:sub(1, 128));

    print(立钻哥哥:Coroutine ended)

end

 

function TestMyCoroutine()

    coroutine.start(CoFunc)

end

 

local coDelay = nil

function Delay()

    local c = 1

 

    while true do

        coroutine.wait(1)

        print(立钻哥哥:Count: .. c)

        c = c + 1

    end

end

 

function StartDelay()

    coDelay = coroutine.start(Delay)

end

 

function StopDelay()

    coroutine.stop(coDelay)

end

 

++++立钻哥哥:该示例展现了如何使用lua协同。(必须启动LuaLooper驱动协同,这里将一个lua的半双工协同转换为相似unity的全双工协同。)

++++coroutine.start()】:启动一个lua协同。

++++coroutine.wait()】:协同中等待一段时间,单位:秒。

++++coroutine.step()】:协同中等待一帧。

++++coroutine.www()】:等待一个WWW完成。

++++tolua.tolstring()】:转换byte数组为lua字符串缓冲。

++++coroutine.stop():中止一个协同。





###1.3xLua热更新框架

++1.3xLua热更新框架

++++xLuahttps://github.com/Tencent/xLua

++++xLuaUnity.NetMonoC#环境增长Lua脚本编程的能力,借助xLua,这些Lua代码能够方便和C#相互调用。


++1.3.1xLua的突破

++++xLua在功能、性能、易用性都有很多突破,最具表明性的是:

--1、能够运行时把C#实现(方法,操做符,属性,事件等等)替换成Lua实现;

--2、出色的GC优化,自定义struct,枚举在LuaC#间传递无C# gc alloc

--3、编辑器下无需生成代码,开发更轻量;

++++【整体特性】

--1Lua虚拟机支持Lua5.3Luajit2.1

--2Unity3D版本支持:各版本支持;

--3、平台支持windows64/32androidios 64/32/bitcodeosxuwpwebgl

--4、互访技术:生成适配代码、反射;

--5、易用性:解压便可用;开发期无需生成代码;生成代码和反射间可无缝切换;更简单的无GC api;菜单简单易懂;配置能够多份,按模块划分,也能够直接在目标类型上打Attribute标签;自动生成link.xml防止代码剪裁;Plugins部分采用cmake编译,更简单;核心代码不依赖生成代码,能够随时删除生成目录;

--6、性能lazyload技术,避免用不上的类型的开销;lua函数映射到C# delegatelua table映射到interface,可实现接口层面无C# gc alloc开销;全部基本值类型,全部枚举,字段都是值类型的struct,在LuaC#间传递无C# gc allocLuaTable,LuaFunction提供无gc访问接口;经过代码生成期的静态分析,生成最优代码;支持C#Lua间指针传递;自动解除已经DestroyUnityEngine.Object的引用;

--7、扩展性:不用改代码就能够加入Lua第三方扩展;生成引擎供接口作二次开发;

++++【支持C#实现打补丁】:构造函数、析构函数、成员函数、静态函数、泛化函数、操做符重载、成员属性;静态属性;事件;

++++Lua代码加载】:加载字符串;支持加载后当即执行;支持加载后返回一个delegate或者LuaFunction,调用delegate或者LuaFunction后可传脚本参数;Resources目录的文件;直接require;自定义loaderLua里头require时触发;require参数透传给loaderloader读取Lua代码返回;Lua原有的方式;Lua原有的方式都保留;

++++Lua调用C#

--1、建立C#对象C#静态属性,字段;C#静态方法;C#成员属性,字段;C#成员方法;C#继承;子类对象能够直接调用父类的方法,访问父类属性;子类模块能够直接调用父类的静态方法,静态属性;

--2、扩展方法(Extension methods:就像普通成员方法同样使用;

--3、参数的输入输出属性(out, refout对应一个lua返回值;ref对应一个lua参数以及一个lua返回值;

--4、函数重载:支持重载;因为lua数据类型远比C#要少,会出现没法判断的状况,可经过扩展方法来调用;操做符重载;

--5、支持的操做符+-*/==<<=%[];其余操做符能够借助扩展方法调用;

--6、参数默认值C#参数有默认值,在Lua能够不传;

--7、可变参数:在对应可变参数部分,直接输入一个参数便可,不须要把这些参数扩到一个数组里头;

--8、泛化方法调用:静态方法能够自行封装使用;成员函数可经过扩展方法封装使用;

--9、枚举类型:数字或字符串到枚举的转换;

--10delegate:调用一个C# delegate+操做符;-操做符;把一个lua函数做为一个c# delegate传递给C#

--11evnet:增长事件回调;移除事件回调;

--1264位整数:传递无gc并且无精度损失;lua53下使用原生64位支持;能够和number运算;以java的方式支持无符号64位整数;

--13table的自动转换到C#复杂类型

--14obj.complexField = { a=1, b = { c = 1}}obj是一个C#对象,complexField是两层嵌套的struct或者class

--15typeof:对应C#typeof操做符,返回Type对象;

--16lua侧直接clone

--17decimal:传递无gc并且无精度损失;

++++C#调用Lua:调用lua函数;以delegate方式调用Lua函数;以LuaFunction调用Lua函数;访问LuatableLuaTable的泛化Get/Set接口,调用无gc,可指明KeyValue的类型;用标注了CSharpCallLuainterface访问;值拷贝到structclass

++++Lua虚拟机】:虚拟机gc参数读取及设置;

++++【工具链】Lua Profiler;可根据函数调用总时长,平均每次调用时长,调用次数排序;显示lua函数名及其所在文件的名字及行号;若是C#函数,会显示这个C#函数;支持真机调试;


++1.3.2xLua常见问题(立钻哥哥:初学者FAQ

++++1xLua发布包怎么用xLua目前已zip包形式发布,在工程目录下解压便可。

++++2xLua能够放别的目录吗?

--能够,但生成代码目录须要配置一下(默认放Assets/XLua/Gen目录);

--更改目录要注意的是:生成代码和xLua核心代码必须在同一程序集。若是要用热补丁特性,xLua核心代码必须在Assembly-CSharp程序集;

++++3lua源码只能以txt后缀?

--什么后缀均可以。

--若是想以TextAsset打包到安装包(好比放到Resources目录),Unity不认lua后缀,这是Unity的规则;

--若是不打包到安装包,就没有后缀的限制:好比自行下载到某个目录(这也是热更的正确姿式),而后经过CustomLoader或者设置package.path去读这个目录;

--为啥xLua自己带的lua源码(包括示例)为何都是txt结尾呢?由于xLua自己就一个库,不含下载功能,也不方便运行时去某个地方下载代码,经过TextAsset是较简单的方式;

++++4、编辑器(或非il2cppandroid)下运行正常,ios下运行调用某函数报“attempt to call a nil value

--il2cpp默认会对诸如引擎、C#系统api,第三方dll等等进行代码裁剪。(简单来讲就是这些地方的函数若是C#代码没访问到的就不编译到最终发布包。)

--解决办法:增长引用(好比配置到LuaCallCSharp,或者本身C#代码增长那函数的访问),或者经过link.xml配置(当配置了ReflectionUse后,xlua会自动帮咱们配置到link.xml)告诉il2cpp别剪裁某类型;

++++5Plugins源码在哪里能够找到,怎么使用?

--Plugins源码位于xLua_Project_Root/build下。

--源码编译依赖cmake,按照cmake后执行make_xxxx_yyyy.zz便可。(xxxx表明平台,好比iosandroid等)(yyyy是要集成的虚拟机,有lua53luajit)(zz是后缀,window下是bat,其余平台是sh

--windows编译依赖Visual Studio 2015

--android编译在linux下执行,依赖NDK,而且须要把脚本中ANDROID_NDK指向NDK的安装目录。

--iososx须要在mac下编译。

++++6、报相似“xlua.access, no field _Hitfix0_Update”的错误怎么解决?

--Hotfix操做指南一步步操做。

--https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/hotfix.md

--使用方式:

    ----1、添加HOTFIX_ENABLE宏打开该特性(在Unity3DFile->Build Setting->Scripting Define Symbols下添加)。(编辑器、各手机平台这个宏要分别设置!若是是自动化打包,要注意在代码里头用API设置的宏是不生效的,须要在编辑器设置)(建议平时开发业务代码不打开HOTFIX_ENABLE,只在build手机版本或者要在编辑器下开发补丁时打开HOTFIX_ENABLE

    ----2、执行xLua/Generate Code菜单;

    ----3、注入,构建手机包这个步骤会在构建时自动进行,编辑器下开发补丁须要手动执行“XLua/Hotfix Inject In Editor”菜单。(注入成功会打印“hotfix inject finish!”或者“had injected!”)

--约束:不支持静态构造函数。(目前只支持Assets下代码的热补丁,不支持引擎,C#系统库的热补丁。)

++++7、报“please install the Tools:没有把Tools安装到Assets平级目录,安装包,或者master下都能找到这个目录。

++++8、报“This delegate/interface must add to CSharpCallLua: XXX”异常怎么解决?

--在编辑器下xLua不生成代码均可以运行,出现这种提示,要么是该类型没加CSharpCallLua,要么是加以前生成过代码,没从新执行生成。

--解决方法,确认XXX(类型)加上CSharpCallLua后,清除代码后运行。

--若是编辑器下没有问题,发布到手机报这错,表示你发布前没有生成代码(执行“XLua/Generate Code”)。

++++9Unity5.5以上执行“XLua/Hotfix Inject In Editor”菜单会提示“WARNING: The runtime version supported by this application is unavailable.

--这是由于注入工具是用.net3.5编译,而Unity5.5MonoBleedingEdgemono环境并没3.5支持致使的,不过通常而言都向下兼容,目前为止也没发现该warning带来什么问题。

--可能有人发现定义INJECT_WITHOUT_TOOL用内嵌模式会没有该warning,但问题是这模式是调试问题用的,不建议使用,由于可能会有一些库冲突问题。

++++10hotfix下怎么触发一个event

--首先经过xlua.private_accessible开启私有成员访问。

--跟着经过对象的“&事件名”字段调用delegate。(例如:self[‘&MyEvent’](),其中MyEvent是事件名。)

++++11、怎么对Unity Coroutine的实现函数打补丁?

--Hotfix操做指南。

--https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/hotfix.md

--xLua能够用lua函数替换C#的构造函数,函数,属性,事件的替换。Lua实现都是函数,好比属性对于一个getter函数和一个setter函数,事件对应一个add函数和一个remove函数。

--Unity协程:经过util.cs_generator能够用一个function模拟一个IEnumerator,在里头用coroutine.yield,就相似C#里头的yield return

++++12、支持NGUI(后者UGUI/DOTween等)么?

--支持,xLua最主要的特性是让原来用C#写的地方能够换成用lua写,C#能用的插件,基本都能用。

++++13、若是须要调试,CustomLoaderfilepath参数该如何处理?

--lua里头调用require ‘a.b’时,CustomLoader会被调用,并传入字符串“a.b”,须要理解这字符串,(从文件/内存/网络等)加载好lua文件,返回两个东西,第一个是调试器能够理解的路径,好比:a/b.lua,这个经过设置ref类型的filepath参数返回,第二个是UTF8格式的源码的字节流(byte[]),经过返回值返回。

++++14、什么是生成代码?

--xLua支持的luaC#间交互技术之一,这种技术经过生成二者间的适配代码来实现交互,性能较好,是推荐的方式。

--另外一种交互技术是反射,这种方式对安装包的影响更少,能够在性能要求不高或者对安装包大小很敏感的场景下使用。

++++15、改了接口后,以前生成的代码出现错误怎么办?

--清除掉生成代码(执行“Clear Generated Code”菜单,若是重启过,会找不到这个菜单,这是能够手动删除整个生成代码目录),等编译完成后从新生成。

++++16、应该何时生成代码?

--开发期不建议生成代码,能够避免不少因为不一致致使的编译失败,以及生成代码自己的编译等待。

--build手机版本前必须执行生成代码,建议作成自动化的。

--作性能调优,性能测试前必须执行生成代码,由于生成和不生成性能的区别仍是很大的。

++++17CS命名空间下有全部C# API是否是很占内存?

--因为用了lazyload,这个“有”只是个虚拟的概念,好比UnityEngine.GameObject,是访问第一次CS.UnityEngine.GameObject或者第一个实例往lua传送才加载该类型方法,属性等。

++++18LuaCallSharp以及CSharpCallLua两种生成各在什么场景下用?

--看调用者和被调用者,好比要在lua调用C#GameObject.Find函数,或者调用gameobject的实例方法,属性等,GameObject类要加LuaCallSharp,而想把一个lua函数挂到UI回调,这时调用者是C#,被调用的是一个lua函数,因此回调声明的delegate要加CSharpCallLua

--有时会比较迷惑人,好比List.Find(Predicate match)的调用,List固然是加LuaCallSharp,而Predicate却要加CSharpCallLua,由于match的调用者在C#,被调用的是一个lua函数。

--更无脑一点的方式是看到“立钻哥哥:This delegate/interface must add to CSharpCallLua:XXX”,就把XXX加到CSharpCallLua便可。

++++19、值类型传递会有gc alloc么?

--若是使用的是delegate调用lua函数,或者用LuaTableLuaFunction的无gc接口,或者数组的话,已下值类型都没有gc的:

----1、全部的基本值类型(全部整数,全部浮点数,decimal);

----2、全部的枚举类型;

----3、字段只包含值类型的struct,可嵌套其它只包含值类型struct

----立钻哥哥:其中23须要把该类型加到GCOptimize

++++20、反射在ios下可用吗?

--ios下的限制有两个:1、没有jit2、代码剪裁(stripping);

--对于C#经过delegate或者interface调用lua,若是不生成代码是反射的emit,这依赖jit,因此这目前只在编辑器可用。

--对于lua调用C#,主要会被代码剪裁影响,这时能够配置ReflectionUse(不要配LuaCallSharp),执行“Generate Code”,这时不会对该类生成封装代码,而是生成link.xml把该类配置为不剪裁。

--简而言之,除了CSharpCallLua是必须的(这类生成代码每每很少),LuaCallSharp生成均可以改成用反射。

++++21、支持泛型方法的调用么?

--部分支持,支持的程度能够看示例9

--其它状况也有办法调用到。若是是静态方法,能够本身写个封装来实例化泛型方法。

--若是是成员方法,xLua支持扩展方法,能够添加一个扩展方法来实例化泛型方法。(该扩展方法使用起来就和普通成员方法同样。)

//立钻哥哥:扩展方法实例化泛型方法

//C#

public static Button GetButton(this GameObject go){

    return go.GetComponent<Button>();

}

//--lua

local go = CS.UnityEngine.GameObject.Find(button)

go.GetButton().onClick:AddListener(

    function() print(onClick) end

)

++++22、支持lua调用C#重载函数吗?

--支持,但没有C#端支持的那么完善,好比重载方法void Foo(int a)void Foo(short a),因为intshort都对应luanumber,是无法根据参数判断调用的是哪一个重载。这是能够借助扩展方法来为其中一个起一个别名。

++++23、编辑器下运行正常,打包的时候生成代码报“没有某方法/属性/字段定义”怎么办?

--每每是因为该方法/属性/字段是扩在条件编译里头,只在UNITY_EDITOR下有效,这是能够经过这方法/属性/字段加到黑名单来解决,加了以后要等编译完成后从新执行代码生成。

++++24this[string field]或者this[object field]操做符重载为何在lua没法访问?(好比Dictionary<string, xxx>Dictionary<object, xxx>lua中没法经过dic[abc]或者dic.abc检索值)

--由于1:这个特性会致使基类定义的方法、属性、字段等没法访问(好比Animation没法访问到GetComponent方法);

--由于2key为当前类某方法、属性、字段的名字的数据没法检索,好比Dictionary类型,dic[‘TryGetValue’]返回的是一个函数,指向DictionaryTryGetValue方法。

--若是版本大于2.1.11,能够用get_Item来获取值,用set_Item来设置值。要注意只有this[string field]或者this[object field]才有这两个替代api,其它类型的key是没有的。

--若是版本小于或等于2.1.11,建议直接方法该操做符的等效方法,好比DictionaryTryGetValue,若是该方法没有提供,能够在C#那经过Extension method封装一个使用。

++++25、有的Unity对象,在C#null,在lua为啥不为nil呢?好比一个已经DestroyGameObject

--其实那C#对象并不为null,是UnityEngine.Object重载的==操做符,当一个对象被Destroy,未初始化等状况,obj==null返回true,但这C#对象并不为null,能够经过System.Object.ReferenceEquals(null,obj)来验证下。

--对这种状况,能够为UnityEngine.Object写一个扩展方法:

[LuaCallCSharp]

[ReflectionUse]

public static class UnityEngineObjectExtention{

    public static bool IsNull(this UnityEngine.Object o){

        return o == null;

    }

}

--而后在lua那对全部UnityEngine.Object实例都使用IsNull判断:

print(go.GetComponent(Animator):IsNull())

++++26、泛型实例怎么构造?

--涉及的类型都在mscorlibAssembly-CSharp程序集的话,泛型实例的构造和普通类型时同样的,都是CS.namespace.typename(),可能比较特殊的是typename的表达,泛型实例的typename的表达包含了标识符非法符号,最后一部分要换成[“typename”],以List为例:

    ----local lst = CS.System.Collections.Generic[‘List`1[System.String]’]();

--若是某个泛型实例的typename不肯定,能够在C#测打印下typeof(不肯定的类型).ToString()

--若是涉及mscorlibAssembly-CSharp程序集以外的类型的话,能够用C#的反射来作:

    ----local dic = CS.System.Activator.CreateInstance(CS.System.Type.GetType(System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[UnityEngine.Vector3, UnityEngine]], mscorlib))

    ----dic:Add(a, CS.UnityEngine.Vector3(1, 2, 3))

    ----print(dic:TryGetValue(a))

++++27、调用LuaEnv.Dispose时,报“try to dispose a LuaEnv with C# callback!”错是什么缘由?

--这是因为C#还存在指向lua虚拟机里头某个函数delegate,为了防止业务在虚拟机释放后调用这些无效(由于其引用的lua函数所在虚拟机都释放了)delegate致使的异常甚至崩溃,作了这个检查。

--怎么解决?释放这些delegate便可,所谓释放,在C#中,就是没有引用:

    ----是在C#经过LuaTable.Get获取并保存到对象成员,赋值该成员为null

    ----是在lua那把lua函数注册到一些事件事件回调,反注册这些回调;

    ----是经过xlua.hotfix(class, method, func)注入到C#,则经过xlua.hotfix(class, method, nil)删除;

--立钻哥哥:注意以上操做在Dispose以前完成。

++++28、调用LuaEnv.Dispose崩溃?

--极可能是这个Dispose操做是由lua那驱动执行,至关于在lua执行的过程当中把lua虚拟机给释放了,改成只由C#执行便可。

++++29C#参数(或字段)类型是object时,传递整数默认是以long类型传递,如何指明其它类型?好比int

//立钻哥哥:示例参考

using UnityEngine;

using XLua;

namespace YanlzXLuaTest{

    public class RawObjectTest : MonoBehaviour{

        public static void PrintType(object o){

            Debug.Log(立钻哥哥:type: + o.GetType() +  , value:  + o);

        }

 

        //Use this for initialization

        void Start(){

            LuaEnv luaenv = new LuaEnv();

 

            //直接传1234到一个object参数,xLua将选择能保留最大精度的long来传递

            luaenv.DoString(CS.YanlzXLuaTest.RawObjectTest.PrintType(1234));

 

            //立钻哥哥:经过一个继承RawObject的类,能实现指明以一个int来传递

            luaenv.DoString(CS.YanlzXLuaTest.RawObjectTest.PrintType(CS.XLua.Cast.Int32(1234)));

 

            luaenv.Dispose();

        }

 

    }    //立钻哥哥:public class RawObjectTest : MonoBehaviour{}

}    //立钻哥哥:namespace YanlzXLuaTest

++++30、如何作到先执行原来的C#逻辑,而后再执行补丁?

--util.hotfix_ex,能够调用原先的C#逻辑。

local util = require xlua.util

util.hotfix_ex(CS.HotfixTest, Add, function(self, a, b)

    local org_sum = self:Add(a, b)

    print(org_sum, org_sum)

    return a + b

end)

++++31、怎么把C#的函数赋值给一个委托字段?

--2.1.8及以前版本,把C#函数当成一个lua函数便可,性能会略低,由于委托调用时先经过Bridge适配代码调用lua,而后lua再调用回C#

--2.1.9 xlua.util新增createdelegate函数。

++++32、为何有时Lua错误直接中断了而没错误信息?

--状况1:错误代码用协程跑,而标准的lua,协程出错是经过resume返回值来表示。若是但愿协程出错直接抛异常,能够在resume调用那加个assert。(【coroutine.resume(co, ...)】改成:【assert(coroutine.resume(co, ...))】)

--状况2:上层catch后,不打印。(好比某些sdk,在回调业务时,try-catch后把异常吃了。)

++++33、重载含糊如何处理?

--好比因为忽略out参数致使的Physics.Raycast其中的一个重载调用不了,好比shortint没法区分的问题。

--首先out参数致使重载含糊比较少见,好比Physics.Raycast,建议经过自行封装来解决(short, int这种状况也适用):静态函数的直接封装个另外名字的,若是是成员方法则经过Extension method来封装。

++++34、支持interface扩展方法么?

    --考虑到生成代码量,不支持经过obj:ExtensionMethod()的方式去调用,支持经过静态方法的方式去调用CS.ExtensionClass.ExtensionMethod(obj)



 

++立钻哥哥推荐的拓展学习连接(Link_Url

++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/

++++Lua快速入门篇(基础概述)http://www.noobyard.com/article/p-pyzbbriu-u.html

++++框架知识点http://www.noobyard.com/article/p-pjzrrjmm-u.html

++++游戏框架(UI框架夯实篇)http://www.noobyard.com/article/p-nnroewdy-cu.html

++++游戏框架(初探篇)http://www.noobyard.com/article/p-klkilyrt-hy.html

++++设计模式简单整理http://www.noobyard.com/article/p-scmbzocc-hg.html

++++U3D小项目参考https://blog.csdn.net/vrunsoftyanlz/article/details/80141811

++++UML类图http://www.noobyard.com/article/p-aakurcwi-bm.html

++++Unity知识点0001http://www.noobyard.com/article/p-bqmetnys-ep.html

++++U3D_Shader编程(第一篇:快速入门篇)http://www.noobyard.com/article/p-ptwlpwbc-gz.html

++++U3D_Shader编程(第二篇:基础夯实篇)http://www.noobyard.com/article/p-dadqpvvp-hv.html

++++Unity引擎基础http://www.noobyard.com/article/p-ggcuedyq-ka.html

++++Unity面向组件开发http://www.noobyard.com/article/p-eiunlkzw-dt.html

++++Unity物理系统http://www.noobyard.com/article/p-mcqnwufb-kd.html

++++Unity2D平台开发http://www.noobyard.com/article/p-brjbvtac-hs.html

++++UGUI基础http://www.noobyard.com/article/p-nvzrvath-mc.html

++++UGUI进阶http://www.noobyard.com/article/p-tpspjolu-gt.html

++++UGUI综合http://www.noobyard.com/article/p-nfgrebqx-gg.html

++++Unity动画系统基础http://www.noobyard.com/article/p-otjpnbzz-dq.html

++++Unity动画系统进阶http://www.noobyard.com/article/p-hxghrtgb-bp.html

++++Navigation导航系统http://www.noobyard.com/article/p-skpvrobt-t.html

++++Unity特效渲染http://www.noobyard.com/article/p-sudpqrhk-bp.html

++++Unity数据存储http://www.noobyard.com/article/p-ybvcceul-m.html

++++Unity中Sqlite数据库http://www.noobyard.com/article/p-vxpuqxev-ca.html

++++WWW类和协程http://www.noobyard.com/article/p-alggjlwu-cy.html

++++Unity网络http://www.noobyard.com/article/p-bjvfgzwg-dw.html

++++C#事件http://www.noobyard.com/article/p-dietpjzv-gm.html

++++C#委托http://www.noobyard.com/article/p-oiohmxtc-gh.html

++++C#集合http://www.noobyard.com/article/p-vdfpislb-ex.html

++++C#泛型http://www.noobyard.com/article/p-vujvnprk-ee.html

++++C#接口http://www.noobyard.com/article/p-emexlwmu-dm.html

++++C#静态类https://blog.csdn.net/vrunsoftyanlz/article/details/78630979

++++C#中System.String类http://www.noobyard.com/article/p-uchiaxzw-cq.html

++++C#数据类型http://www.noobyard.com/article/p-kqtbvoyq-ba.html

++++Unity3D默认的快捷键http://www.noobyard.com/article/p-gbllyjbs-s.html

++++游戏相关缩写http://www.noobyard.com/article/p-pzpxsztf-gm.html

++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/



--_--VRunSoft : lovezuanzuan--_--