Lua快速入门篇(XLua教程)(Yanlz+热更新+xLua+配置+热补丁+第三方库+API+二次开发+常见问题+示例参考)

                        《Lua热更新》

##《Lua热更新》发布说明:java

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

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

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

 

##《Lua热更新》目录:git

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

#第二篇:Lua基础夯实篇数据库

#第三篇:Lua中级进阶篇编程

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

#第五篇:立钻哥哥带您学Lua热更新windows

 

++++Lua快速入门篇(XLua拓展):http://www.javashuo.com/article/p-rrszijom-cm.html

++++Lua快速入门篇(XLua教程):http://www.javashuo.com/article/p-pduvmusb-ho.html

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

 

 

 

#第一篇:Lua快速入门篇

#第一篇:Lua快速入门篇

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

++++第二章:xLua教程

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

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

 

 

##第二章:xLua教程

++第二章:xLua教程

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

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

++++2.一、xLua教程

++++2.二、xLua的配置

++++2.三、热补丁操做指南

++++2.四、XLua增长删除第三方lua库

++++2.五、xLua API

++++2.六、生成引擎二次开发指南

++++2.七、xLua常见问题

++++2.八、xLua示例参考

++++2.九、xLua拓展总结

++++2.十、立钻哥哥带您学xLua

 

 

###2.一、xLua入门教程

###2.一、xLua入门教程

++2.一、xLua入门教程

++++xLua教程:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/XLua教程.md

++++2.1.一、Lua文件加载

++++2.1.二、C#访问Lua

++++2.1.三、Lua调用C#

 

++2.1.一、Lua文件加载

++++Lua文件加载:一、执行字符串;二、加载Lua文件;三、自定义Loader;

++++一、执行字符串(不推荐使用)

--最基本是直接用LuaEnv.DoString()执行一个字符串(字符串得符合Lua语法):

    ----luaenv.DoString(print(立钻哥哥))

++++二、加载Lua文件

--用lua的require函数便可:

    ----DoString(require byfile’”);

--require其实是调用一个个的loader去加载,有一个成功就再也不往下尝试,全失败则报文件找不到。(目前xLua除了原生的loader外,还添加了从Resource加载的loader,须要注意的是由于Resource只支持有限的后缀,放Resource下的Lua文件得加上txt后缀。)

--建议加载Lua脚本方式是:整个程序就一个DoString(“require ‘main’”),而后在main.lua加载其它脚本(相似lua脚本的命令执行:lua main.lua)

++++三、自定义Loader

--在xLua加自定义loader是很简单的,只涉及到一个接口:

    ----public delegate byte[] CustomLoader(ref string filepath);

    ----public void LuaEnv.AddLoader(CustomLoader loader)

--经过AddLoader能够注册一个回调,该回调参数是字符串,lua代码里头调用require时,参数将会透传给回调,回调中就能够根据这个参数去加载指定文件,若是须要支持调试,须要把filepath修改成真实路径传出。(该回调返回一个byte数组,若是为空表示该loader找不到,不然则为lua文件的内容。)

 

++2.1.二、C#访问Lua

++++这里指的是C#主动发起对Lua数据结构的访问。

++++一、获取一个全局基本数据类型

--访问LuaEnv.Global就能够了。

--luaenv.Global.Get<int>(a)

--luaenv.Global.Get<string>(b)

--luaenv.Global.Get<bool>(c)

++++二、访问一个全局的table

--2.一、映射到普通class或struct:

    ----定义一个class,有对应于table的字段的public属性,并且有无参数构造函数便可,好比对于{  f1 = 100, f2 = 100  }能够定义一个包含public int f1; public int f2;的class。

    ----table属性可多于或者少于class的属性。能够嵌套其它复杂类型。(立钻哥哥:这个过程是值拷贝,若是class比较复杂代价会比较大。)

    ----这个功能能够经过把类型加到GCOptimize生成下降开销。

--2.二、映射到一个interface:

    ----这种方式依赖于生成代码(若是没生成代码会抛InvalidCastException异常),代码生成器会生成这个interface的实例,若是get一个属性,生成代码会get对应的table字段,若是set属性也会设置对应的字段。(甚至能够经过interface的方法访问lua的函数。)

--2.三、更轻量级的by value方式:映射到Dictionary<>, List<>:

    ----不想定义class或者interface的话,能够考虑用这个,前提table下key和value的类型都是一致的。

--2.四、另一种by ref方式:映射到LuaTable类:

    ----这种方式好处是不须要生成代码,但也有一些问题,比较慢,没有类型检查。

++++三、访问一个全局的function

--仍然是用Get方法,不一样的是类型映射。

--3.一、映射到delegate:

    ----这种是建议的方式,性能好不少,并且类型安全。(缺点是要生成代码(若是没生成代码会抛InvalidCastException异常))。

    ----delegate要怎样声明呢?对于function的每一个参数就声明一个输入类型的参数。(多返回值要怎么处理?从左往右映射到C#的输出参数,输出参数包括返回值,out参数,ref参数。)

    ----参数、返回值类型支持哪些呢?(都支持,各类复杂类型,out,ref修饰的,甚至能够返回另一个delegate。)

    ----delegate的使用就更简单了,直接像个函数那样用就能够了。

--3.二、映射到LuaFunction:

    ----这种方式的优缺点恰好和第一种相反。(使用也简单,LuaFunction上有个变参的Call函数,能够传任意类型,任意个数的参数,返回值是object的数组,对应于lua的多返回值。)

++++四、使用建议

--4.一、访问lua全局数据,特别是table以及function,代价比较大,建议尽可能少作,好比在初始化时要调用的lua function获取一次(映射到delegate)后,保存下来,后续直接调用该delegate便可。(table也相似)

--4.二、若是lua侧的实现的部分都以delegate和interface的方式提供,使用方能够彻底和xLua解耦;由一个专门的模块负责xLua的初始化以及delegate、interface的映射,而后把这些delegate和interface设置到要用到它们的地方。

 

++2.1.三、Lua调用C#

++++lua调用C#:new C#对象;访问C#静态属性,方法;访问C#成员属性,方法;

++++【new C#对象】

--能够像C#这样new一个对象:

    ----var newGameObj = new UnityEngine.GameObject();    //C#

    ----local newGameObject = CS.UnityEngine.GameObject();    //lua

--基本相似,除了:一、lua里头没有new关键字;二、全部C#相关的都放到CS下,包括构造函数,静态成员属性、方法;

--xLua支持重载(多个构造函数等),好比调用GameObject的带一个string参数的构造函数:

    ----local newGameObj2 = CS.UnityEngine.GameObject(立钻哥哥)

++++【访问C#静态属性,方法】

--【读静态属性】:CS.UnityEngine.Time.deltaTime

--【写静态属性】:CS.UnityEngine.Time.timeScale = 0.5

--【调用静态方法】:CS.UnityEngine.GameObject.Find(立钻哥哥)

    ----立钻哥哥:若是须要常常访问的类,能够先用局部变量引用后访问,除了减小敲代码的时间,还能提升性能:

        ------local GameObject = CS.UnityEngine.GameObject

        ------GameObject.Find(立钻哥哥)

++++【访问C#成员属性,方法】

--【读成员属性】:testObj.YanlzScore

--【写成员属性】:testObj.YanlzScore = 1024

--【调用成员方法】:调用成员方法,第一参数须要传该对象,建议用冒号语法糖:

    ----testobj:MyTestFunc()

--【父类属性,方法】:

    ----xLua支持(经过派生类)访问基类的静态属性,静态方法,(经过派生类实例)访问基类的成员属性,成员方法。

--【参数的输入输出属性(out, ref)】:

    ----Lua调用侧的参数处理规则:C#的普通参数算一个输入形参,ref修饰的算一个输入形参,out不算,而后从左往右对应lua调用侧的实参列表。

    ----Lua调用侧的返回值处理规则:C#函数的返回值(若是有的话)算一个返回值,out算一个返回值,ref算一个返回值,而后从左往右对应lua的多返回值。

--【重载方法】:直接经过不一样的参数类型进行重载函数的访问:

    ----testobj:TestFunc(100)

    ----testobj:TestFunc(立钻哥哥)

    ----立钻哥哥:xLua只必定程度上支持重载函数的调用,由于lua的类型远远不如C#丰富,存在一对多的状况,好比C#的int,float,double都对应于lua的number。

--【操做符】:支持操做符有:+,-,*,/,==,<,<=,%,[]

--【参数带默认值的方法】:和C#调用有默认值参数的函数同样,若是所给的实参少于形参,则会用默认值补上。

--【可变参数方法】:

    --C#:void VariableParamsFunc(int a, params string[] strs);

    --lua:testobj:VariableParamsFunc(5, hello, 立钻哥哥)

--【使用Extension methods】:在C#里定义了,lua里就能直接使用。

--【泛化(模板)方法】:不直接支持,能够经过Extension methods功能进行封装后调用。

--【枚举类型】:枚举值就像枚举类型下的静态属性同样。

    ----testobj:EnumTestFunc(CS.Tutorial.TestEnum.E1)  

    ----枚举类支持__CastFrom方法,能够实现从一个整数或者字符串到枚举值的转换:

        ------CS.Tutorial.TestEnum.__CastFrom(1)

        ------CS.Tutorial.TestEnum.__CastFrom(E1)

--【delegate使用(调用,+,-)】:

    ----C#的delegate调用:和调用普通lua函数同样;

  ----操做符+:对应C#的+操做符,把两个调用串成一个调用链,右操做数能够是同类型的C# delegate或者是lua函数。

    ----操做符-:和+相反,把一个delegate从调用链中移除。

    ----立钻哥哥:delegate属性能够用一个luafunction来赋值。

--【event】:好比testobj里头有事件定义是这样:public event Action TestEvent;

    ----增长事件回调:testobj:TestEvent(+, lua_event_callback)

    ----移除事件回调:testobj:TestEvent(-, lua_event_callback)

--【64位整数支持】:

    ----Lua53版本64位整数(long, ulong)映射到原生的64位整数,而luajit版本,至关于lua5.1标准,自己不支持64位,xlua作了个64位支持的扩展库,C#的long和ulong都将映射到userdate:

        ------支持在lua里头进行64位的运算,比较,打印;

        ------支持和lua number的运算,比较;

        ------立钻哥哥:在64位扩展库中,实际上只有int64,ulong也会强转成long再传递到lua,而对ulong的一些运算,比较,咱们采起和java同样的支持方式,提供一组API。

--【C#复杂类型和table的自动转换】:对于一个无参构造函数的C#复杂类型,在lua侧能够直接用一个table来代替,该table对复杂类型的public字段有相应字段便可,支持函数参数传递,属性赋值等。

--【获取类型(至关于C#的typeof)】:

    ----好比要获取UnityEngine.ParticleSystem类的Type信息,能够这样:

        ----typeof(CS.UnityEngine.ParticleSystem)

--【“强”转】:lua没有类型,因此不会有强类型语言的“强转”。

    ----但有个有点像的东西:告诉xLua要用指定的生成代码去调用一个对象,这在什么状况下能用到呢?

    ----有的时候第三方库对外暴露的是一个interface或者抽象类,实现类的隐藏的,这样咱们没法对实现类进行代码生成。

    ----该实现类将会被xLua识别为未生成代码而用反射来访问,若是这个调用是很频繁的话仍是很影响性能的,这时咱们就能够把这个interface或者抽象类加到生成代码,而后指定用该生成代码来访问:

        ----cast(calc, typeof(CS.Tutorial.Calc))

 

 

 

###2.二、xLua的配置

###2.二、xLua的配置

++2.二、xLua的配置

++++xLua的配置:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/configure.md

++++xLua全部的配置都支持三种方式:打标签;静态列表;动态列表;

++++xLua配置有两必须和两建议:

--必须1:列表方式均必须是static的字段/属性;

--必须2:列表方式均必须放到一个static类;

--建议1:不用标签方式;

--建议2:列表方式配置放Editor目录(若是是Hotfix配置,并且类位于Assembly-CSharp.dll以外的其余dll,必须放Editor目录)

++++2.2.0、立钻哥哥带您xLua配置

++++2.2.一、打标签

++++2.2.二、静态列表

++++2.2.三、动态列表

++++2.2.四、XLua.LuaCallCSharp

++++2.2.五、XLua.ReflectionUse

++++2.2.六、XLua.DoNotGen

++++2.2.七、XLua.CSharpCallLua

++++2.2.八、XLua.GCOptimize

++++2.2.九、XLua.AdditionalProperties

++++2.2.十、XLua.BlackList

++++2.2.十一、CSObjectWrapEditor.GenPath

++++2.2.十二、CSObjectWrapEditor.GenCodeMenu

++++2.2.1三、立钻哥哥带您xLua配置

 

++2.2.一、打标签(不推荐使用)

++++xLua用白名单来指明生成哪些代码,而白名单经过attribute来配置;

++++好比想从lua调用C#某个类,但愿生成适配代码,能够为这个类型打一个LuaCallCSharp标签:

[LuaCallCSharp]

public class A{

}

++++该方式方便,但在il2cpp下会增长很多的代码量,不建议使用。

 

++2.2.二、静态列表

++++有时咱们没法直接给一个类型打标签,好比系统api,没源码的库,或者实例化的泛化类型,这时能够在一个静态类里声明一个静态字段,该字段的类型除[BlackList][AdditionalProperties]以外只要实现了IEnumerable<Type>就能够了。

[LuaCallCSharp]

public static List<Type> mymodule_lua_call_cs_list = new List<Type>(){

    typeof(GameObject),

    typeof(Dictionary<string, int>),

};

++++这个字段须要放到一个静态类里头,建议放到Editor目录。

 

++2.2.三、动态列表

++++声明一个静态属性,打上相应的标签便可。

[Hotfix]

public static List<Type> by_property{

    get{

        return (

            from type in Assembly.Load(Assembly-CSharp).GetTypes()

            where type.Namespace == XXXX

            select type).ToList();

    }

}

++++Getter是代码,能够实现不少效果,好比按名字空间配置,按程序集配置等等。

++++这个属性须要放到一个静态类里头,建议放到Editor目录。

 

++2.2.四、XLua.LuaCallCSharp

++++一个C#类型加了这个配置,xLua会生成这个类型的适配代码(包括构造该类型实例,访问其成员属性、方法,静态属性、方法),不然将会尝试用性能较低的反射方式来访问。

++++一个类型的扩展方法(Extension Methods)加了这配置,也会生成适配代码并追加到被扩展类型的成员方法上。

++++xLua只会生成加了该配置的类型,不会自动生成其父类的适配代码,当访问子类对象的父类方法,若是该父类加了[LuaCallCSharp]配置,则执行父类的适配代码,不然会尝试用反射来访问。

++++反射访问除了性能不佳以外,在il2cpp下还有可能由于代码剪裁而致使没法访问,后者能够经过[ReflectionUse]标签来避免。

 

++2.2.五、XLua.ReflectionUse

++++一个C#类型加了这个配置,xLua会生成link.xml阻止il2cpp的代码剪裁。

++++对于扩展方法,必须加上[LuaCallCSharp]或者[ReflectionUse]才能够被访问到。

++++建议全部要在Lua访问的类型,要么加[LuaCallCSharp],要么加上[ReflectionUse],这才可以保住在各平台都能正常运行。

 

++2.2.六、XLua.DoNotGen

++++指明一个类里头的部分函数、字段、属性不生成代码,经过反射访问。

++++标准Dictionary<Type, List>的field或者property。(key指明的是生效的类,value是一个列表,配置的是不生成代码的函数、字段、属性的名字。)

++++[DoNotGen][ReflectionUse]的区别是:

--一、[ReflectionUse]指明的是整个类;

--二、当第一次访问一个函数(字段、属性)时,[ReflectionUse]会把整个类都wrap,而[DoNotGen]只wrap该函数(字段、属性),换句话[DoNotGen]更lazy一些;

++++[DoNotGen][BlackList]的区别:

--一、[BlackList]配了就不能用;

--二、[BlackList]能指明某重载函数,[DoNotGen]不能;

 

++2.2.七、XLua.CSharpCallLua

++++若是但愿把一个lua函数适配到一个C# delegate(

--一类是C#侧各类回调:UI事件,delegate参数,好比List<T>:ForEach;

--另一类场景是经过LuaTable的Get函数指明一个lua函数绑定到一个delegate)。

++++或者把一个lua table适配到一个C# interface,该delegate或者interface须要加上该配置。

 

++2.2.八、XLua.GCOptimize

++++一个C#纯值类型(立钻哥哥:指的是一个只包含值类型的struct,能够嵌套其它只包含值类型的struct)或者C#枚举值加上了这个配置。

++++xLua会为该类型生成gc优化代码,效果是该值类型在lua和C#间传递不产生(C#)gc alloc,该类型的数组访问也不产生gc。各类无GC的场景。

++++除枚举以外,包含无参构造函数的复杂类型,都会生成lua table到该类型,以及该类型的一维数组的转换代码,这将会优化这个转换的性能,包括更少的gc alloc。

 

++2.2.九、XLua.AdditionalProperties

++++这个是[GCOptimize]的扩展配置,有的时候,一些struct喜欢把field作成是私有的,经过property来访问field,这时就须要用到该配置(默认状况下[GCOptimize]只对public的field打解包。)

++++标签方式比较简单,配置方式复杂一些,要求是Dictionary<Type, List<string>>类型,Dictionary的Key是要生效的类型,Value是属性名列表。

++++能够参考XLua对几个UnityEngine下值类型的配置,SysGCOptimize类等。

 

++2.2.十、XLua.BlackList

++++若是不要生成一个类型的一些成员的适配代码,能够经过这个配置来实现。

++++标签方式比较简单,对应的成员上加上就能够了。

++++因为考虑到有可能须要把重载函数的其中一个重载列入黑名单,配置方式比较复杂,类型是List<List<string>>,对于每一个成员,

--在第一层List有一个条目,

--第二层List是个string的列表,

--第一个string是类型的全路径名,

--第二个string是成员名,

++++若是成员是一个方法,还须要从第三个string开始,把其参数的类型全路径全列出来。

++++例如:对GameObject的一个属性以及FileInfo的一个方法列入黑名单[BlackList]

[BlackList]

public static List<List<string>> BlackList = new List<List<string>>(){

    new List<string>(){  UnityEngine.GameObject,  networkView  },

    new List<string>(){  System.IO.FileInfo,  GetAccessControl,  System.Security.AccessControl.AccessControlSections  },

};

 

++2.2.十一、CSObjectWrapEditor.GenPath

++++立钻哥哥:生成期配置,必须放到Editor目录下。

++++配置生成代码的放置路径,类型是string。

++++默认放在“Assets/XLua/Gen/”下。

 

++2.2.十二、CSObjectWrapEditor.GenCodeMenu

++++立钻哥哥:生成期配置,必须放到Editor目录下。

++++该配置用于生成引擎的二次开发,一个无参数函数加上了这个标签,在执行“XLua/Generate Code”菜单时会触发这个函数的调用。

 

 

 

 

###2.三、热补丁操做指南

###2.三、热补丁操做指南

++2.三、热补丁操做指南

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

++++热补丁操做指南:使用方式;约束;API;标识要热更新的类型;使用建议;打补丁;

++++2.3.一、使用方式

++++2.3.二、约束

++++2.3.三、API

++++2.3.四、标识要热更新的类型

++++2.3.五、使用建议

++++2.3.六、打补丁

 

++2.3.一、使用方式

++++步骤1:添加HOTFIX_ENABLE宏打开该特性(在Unity3D的File->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!”)

 

++2.3.二、约束

++++立钻哥哥:不支持静态构造函数。

++++目前只支持Assets下代码的热补丁(不支持引擎、C#系统库的热补丁)。

 

++2.3.三、API

++++立钻哥哥:xlua.hotfix(class, [method_name], fix)

--描述:注入lua补丁;

--class:C#类,两种表示方法:

----CS.Namespace.TypeName或者字符串方式“Namespace.TypeName”,

----字符串格式和C#的Type.GetType要求一致,若是是内嵌类型(Nested Type)是非Public类型的话,只能用字符串方式表示:“Namespace.TypeName+NestedTypeName”;

--method_name:方法名,可选;

--fix:若是传了method_name, fix将会是一个function,不然经过table提供一组函数。(table的组织按key是method_name, value是function的方式)

++++立钻哥哥:base(csobj)

--描述:子类override函数经过base调用父类实现。

--csobj:对象;

--返回值:新对象,能够经过该对象base上的方法。

++++立钻哥哥:util.hotfix_ex(class, method_name, fix)

--描述:xlua.hotfix的加强版本,能够在fix函数里头执行原来的函数,缺点是fix的执行会略慢。

--method_name:方法名;

--fix:用来替换C#方法的lua function;

++++立钻哥哥:示例参考:

xlua.hotfix(CS.BaseTest, Foo, function(self, p)

    print(BaseTest, p)

    base(self) : Foo(p)

end)

 

++2.3.四、标识要热更新的类型

++++立钻哥哥:和其它配置同样,有两种方式。

++++方式一:直接在类里头打Hotfix标签(不推荐)。

++++方式二:在一个static类的static字段或者属性里头配置一个列表。属性能够用于实现的比较复杂的配置,好比根据Namespace作白名单。

//立钻哥哥:若是涉及到Assembly-CSharp.dll以外的其余dll(须要放到Editor目录)

public static class YanlzHotfixCfg{

    [Hotfix]

    public static List<Type> by_field = new List<Type>(){

        typeof(HotFixSubClass),

        typeof(GenericClass<>),

    };

 

    [Hotfix]

    public static List<Type> by_property{

        get{

            return (from type in Assembly.Load(Assembly-CSharp).GetTypes()

                       where type.Namespace == XXXX

                       select type).ToList();

        }

    }

}    //立钻哥哥:public static class YanlzHotfixCfg

 

++2.3.五、Hotfix Flag

++++立钻哥哥:Hotfix标签能够设置一些标志位对生成代码及插桩定制化。

++++Hotfix标签:Stateless、Stateful;ValueTypeBoxing;IgnoreProperty;IgnoreNotPublic;Inline;IntKey;

++++【Stateless、Stateful】:遗留设置,Stateful方式在新版本已经删除,由于这种方式能够用xlua.util.state接口达到相似的效果。(因为没有Statefull,默认就是Stateless,因此也没有必要设置该标志位。)

++++【ValueTypeBoxing】:值类型的适配delegate会收敛到object,好处是代码量更少,很差的值类型会产生boxing及gc,适用于对text段敏感的业务。

++++【IgnoreProperty】:不对属性注入及生成适配代码,通常而言,大多数属性的实现都很简单,出错概率比较小,建议不注入。

++++【Inline】:不生成适配delegate,直接在函数体注入处理代码。

++++【IntKey】:不生成静态字段,而是把全部注入点放到一个数组集中管理。

 

++2.3.六、使用建议

++++立钻哥哥:对全部较大可能变更的类型加上[Hotfix]标识。

++++建议用反射找出全部函数的参数、字段、属性、事件涉及的delegate类型,标注[CSharpCallLua]

++++业务代码、引擎API、系统API,须要在Lua补丁里头高性能访问的类型,加上[LuaCallCSharp]

++++引擎API、系统API可能被代码剪裁掉(C#无引用的地方都会被剪裁),若是以为可能会新增C#代码以外的API调用,这些API所在的类型要么加上[LuaCallCSharp],要么加[ReflectionUse]

 

++2.3.七、打补丁

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

++++打补丁:函数;构造函数;属性;[]操做符;其余操做符;事件;析构函数;泛化类型;Unity协程;整个类;

++++【函数】:method_name传函数名,支持重载,不一样重载都是转发到同一个lua函数。

//立钻哥哥:要fix的C#类

[Hotfix]

public class HotfixCalc{

    public int Add(int a, int b){

        return a - b;

    }

 

    public Vector3 Add(Vector3 a, Vector3 b){

        return a - b;

    }

}    //立钻哥哥:public class HotfixCalc{}

 

xlua.hotfix(CS.HotfixCalc, Add, function(self, a, b)

    return a + b;

end);

--静态函数和成员函数的区别是:

----成员函数会加一个self参数,这个self在Stateless方式下是C#对象自己(对应C#的this);

----普通参数对于lua的参数,ref参数对应lua的一个参数和一个返回值,out参数对于lua的一个返回值。

--泛化函数的打补丁规则和普通函数同样。

++++【构造函数】:构造函数对应的method_name是“.ctor”。

--和普通函数不同的是,构造函数的热补丁并非替换,而是执行原有逻辑后调用lua。

++++【属性】:对于名为“AProp”属性。

--会对应一个getter,method_name等于get_AProp,setter的method_name等于set_AProp。

++++【[]操做符】:赋值对应set_Item,取值对应get_Item。

--第一个参数是self,赋值后面跟key,value,取值只有key参数,返回值是取出的值。

++++【其余操做符】:C#的操做符都有一套内部表示,好比+号的操做符函数名是op_Addition,覆盖这函数就覆盖了C#的+号操做符。

++++【事件】:好比对于事件“AEvent”,+=操做符是add_AEvent,-=对应的是remove_AEvent。

--这两个函数均是第一个参数self,第二个参数是操做符后面跟的delegate。

--立钻哥哥:经过xlua.private_accessible(版本号大于2.1.11不须要调用xlua.private_accessible)来直接访问事件对应的私有delegate的直接访问后,能够经过对象的“&事件名”字段直接触发事件,例如self[‘&MyEvent’](),其中MyEvent是事件名。

++++【析构函数】:method_name是“Finalize”,传一个self参数。

--和普通函数不同的是,析构函数的热补丁并非替换,而是开头调用lua函数后继续原有逻辑。

++++【泛化类型】:其余规则一致,须要说明的是,每一个泛化类型实例化后都是一个独立的类型,只能针对实例化后的类型分别打补丁。

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

++++【整个类】:若是要替换整个类,不须要一次次的调用xlua.hotfix去替换,能够整个一次完成。只要给一个table,按method_name = function组织便可。

//立钻哥哥:替换整个类示例

xlua.hotfix(CS.StatefullTest, {

    [.ctor] = function(csobj)

        return util.state(csobj, {  evt = {}, start = 0, prop = 0  })

    end;

    set_AProp = function(self, v)

        print(set_AProp, v)

        self.prop = v

    end;

    get_AProp = function(self)

        return self.prop;

    end;

    get_Item = function(self, k)

        print(get_Item, k)

        return 1024

    end;

    set_Item = function(self, k, v)

        print(set_Item, k, v)

    end;

    add_AEvent = function(self, cb)

        print(add_AEvent, cb)

        table.insert(self.evt, cb)

    end;

    remove_AEvent = function(self, cb)

        print(remove_AEvent, cb)

        for i, v in ipairs(self.evt) do

            if v == cb then

                table.remove(self.evt, i)

                break;

            end

        end

    end;

    Start = function(self)

        print(Start)

        for _, cb in ipairs(self.evt) do

            cb(self.start, 2)

        end

        self.start = self.start + 1

    end;

    StaticFunc = function(a, b, c)

        print(a, b, c)

    end

    GenericTest = function(self, a)

        print(self, a)

    end;

    Finalize = function(self)

        print(Finalize, self)

    end

})    //立钻哥哥:xlua.hotfix(CS.StatefullTest, {})

 

 

 

 

###2.四、XLua增长删除第三方lua库

###2.四、XLua增长删除第三方lua库

++2.四、XLua增长删除第三方lua库

++++https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/XLua增长删除第三方lua库.md

++++立钻哥哥:XLua增长删除第三方lua库。

++++XLua目前内置的扩展库:

--一、针对luajit的64位整数支持;

--二、函数调用耗时以及内存泄露定位工具;

--三、用于支持ZeroBraneStudio的luasocket库;

--四、tdr 4 lua;

++++随着使用项目的增长以及项目使用的深刻程度,仅有这几个扩展已经无法知足项目组了,而因为各个项目对扩展差别化比较大,以及手机平台对安装包大小的敏感,XLua是没法经过预集成去知足这些需求。

++++如何往xLua添加扩展库,分三步:

--步骤1:修改build文件、工程设置,把要集成的扩展编译到XLua Plugin里头;

--步骤2:调用xLua的C# API,使得扩展能够被按需(在lua代码里头require的时候)加载;

--步骤3:可选,若是扩展里头须要用到64位整数,能够经过XLua的64位扩展库来实现和C#的配合。

 

++2.4.一、添加扩展&编译(以lua-rapidjson为例)

++++步骤1:把xLua的C源码包解压到Unity工程的Assets同级目录下

--下载lua-rapidjson代码,按习惯放置。

--rapidjson头文件放到:$YanlzUnityPro\build\lua-rapidjson\include目录下,

--扩展的源码rapidjson.cpp放到:$YanlzUnityPro\build\lua-rapidjson\source目录下。

++++步骤2:在CMakeLists.txt加入扩展

--xLua的各平台Plugins编译使用cmake编译,好处是全部平台的编译都写在一个makefile,大部分编译处理逻辑是跨平台的。

--xLua配套的CMakeLists.txt为第三方扩展提供了扩展点(都是list):

    --i.THIRDPART_INC:第三方扩展的头文件搜索路径;

    --ii.THIRDPART_SRC:第三方扩展的源代码。

    --iii.THIRDPART_LIB:第三方扩展依赖的库。

++++立钻哥哥:rapidjson扩展参考

#begin lua - rapidjson

set (RAPIDJSON_SRC lua-rapidjson/source/rapidjson.cpp)

set_property(

    SOURCE ${  RAPIDJSON_SRC  }

    APPEND

    PROPERTY COMPILE_DEFINITIONS

    LUA_LIB

)

list(APPEND THIRDPART_INC lua-rapidjson/include)

set (THIRDPART_SRC ${THIRDPART_SRC} ${RAPIDJSON_SRC})

#end lua-rapidjson

++++步骤3:各平台编译

--全部编译脚本都是按这个方式命名:make_平台_lua版本.后缀

--好比:windows 64位lua53版本是:make_win64_lua53.bat;

--好比:android的luajit版本是:make_android_luajit.sh;

--要编译哪一个版本就执行相应的脚本便可。

--执行完编译脚本会自动拷贝到plugin_lua53或者plugin_luajit目录。

--配套的android脚本是在linux下使用的,脚本开头的NDK路径要根据实际状况修改。

 

++2.4.二、C#侧集成

++++全部lua的C扩展库都会提供:luaopen_xxx的函数(xxx是动态库的名字):

--好比lua-rapidjson库,该函数是:luaopen_rapidjson,

--这类函数由lua虚拟机在加载动态库时自动调用,而在手机平台,因为ios的限制咱们加载不了动态库,而是直接编译进进程里头。

++++xLua提供了一个API来替代这功能(LuaEnv的成员方法):

--public void AddBuildin(string name, LuaCSFunction initer)

    ----参数name:buildin模块的名字,require时输入的参数;

    ----参数initer:初始化函数,原型是这样的:public delegate int lua_CSFunction(IntPtr L),必须是静态函数,并且带MonoPInvokeCallbackAttribute属性修饰,这个api会检查这两个条件。

++++立钻哥哥:以luaopen_rapidjson的调用来分析使用:

--扩展LuaDLL.lua类,用pinvoke把luaopen_rapidjson导出到C#,而后写一个符合lua_CSFunction定义的静态函数,能够在里头作写初始化工做:

//立钻哥哥:以luaopen_rapidjson的调用为参考

namespace LuaDLL{

    public partial class Lua{

        [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]

        public static extern int luaopen_rapidjson(System.IntPtr L);

 

        [MonPInvokeCallback(typeof(LuaDLL.lua_CSFunction))]

        public static int LoadRapidJson(System.IntPtr L){

            return luaopen_rapidjson(L);

        }

    }    //立钻哥哥:public partial class Lua

}    //立钻哥哥:namespace LuaDLL{}

--而后调用AddBuildin:luaenv.AddBuildin(“rapidjson”, LuaDLL.Lua.LoadRapidJson)

//立钻哥哥:在lua代码中试试该扩展吧

local rapidjson = require(rapidjson)

local myT = rapidjson.decode({a:123})

print(myT.a)

myT.a = 888

local myS = rapidjson.encode(myT)

print(json, myS)

 

++2.4.三、64位改造

++++立钻哥哥:把i64lib.h文件include到须要64位改造的文件里头。

++++[i64lib.h]该头文件的API有:

--一、往栈上放一个int64/uint64:

    ----void lua_pushint64(lua_State* L, int64_t n);

    ----void lua_pushuint64(lua_State* L, uint64_t n);

--二、判断栈上pos位置是不是int64/uint64:

    ----int lua_isint64(lua_State* L, int pos);

    ----int lua_isuint64(lua_State* L, int pos);

--三、从栈上pos位置取一个int64/uint64:

    ----int64_t lua_toint64(lua_State* L, int pos);

    ----uint64_t lua_touint64(lua_State* L, int pos);

 

 

 

 

###2.五、xLua API

###2.五、xLua API

++2.五、xLua API

++++https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/XLua_API.md

++++XLua中C# API:LuaEnv类、LuaTable类、LuaFunction类;

++++XLua中Lua API:CS对象、类型映射、复杂数据类型、宏;

 

++2.5.一、C#API

++++立钻哥哥:C#API包括:LuaEnv类;LuaTable类;LuaFunction类;

++++【LuaEnv类】

--object[] DoString(string chunk, string chunkName = chuck, LuaTable env = null);

--T LoadString(string chunk, string chunkName = chuck, LuaTable env = null);

--LuaTable GLobal;

--void Tick();

--void AddLoader(CustomLoader loader);

--void Dispose();

++++【LuaTable类】

--T Get(string key);

--T GetInPath(string path);

--void SetInPath(string path, T val);

--void Get<TKey, TValue>(Tkey key, out TValue value);

--void Set<TKey, TValue>(TKey key, TValue value);

--T Cast();

--void SetMetaTable(LuaTable metaTable);

++++【LuaFunction类】

--object[] Call(params object[] args);

--object[] Call(object[] args, Type[] returnTypes);

--void SetEnv(LuaTable env);

 

 

++2.5.1.一、LuaEnv类

++++LuaEnv类:DoString()LoadString()Tick()AddLoader()Dispose()

++++object[] DoString(string chunk, string chunkName = chuck, LuaTable env = null);

++++T LoadString(string chunk, string chunkName = chuck, LuaTable env = null);

++++LuaTable GLobal;

++++void Tick();

++++void AddLoader(CustomLoader loader);

++++void Dispose();

 

++2.5.1.1.一、object[] DoString(string chunk, string chunkName = chuck, LuaTable env = null);

++++描述:执行一个代码块。

++++参数:

--chunk:Lua代码的字符串;

--chunkName:发生error时的debug显示信息中使用,指明某某代码的某行错误;

--env:这个代码块的环境变量;

++++返回值:

--代码块里return语句的返回值;

--好比:return 1,“立钻哥哥”,DoString返回将包含两个object数组,一个doube类型的1,一个是string类型的“立钻哥哥”。

++++例如:

LuaEnv luaenv = new LuaEnv();

object[] ret = luaenv.DoString(print(立钻哥哥)\r\nreturn 1);

UnityEngine.Debug.Log(ret=+ret[0]);

luaenv.Dispose();

 

++2.5.1.1.二、T LoadString(string chunk, string chunkName = chuck, LuaTable env = null);

++++描述:加载一个代码块,但不执行,只返回类型能够指定为一个delegate或者一个LuaFunciton。

++++参数:

--chunk:Lua代码的字符串;

--chunkName:发生error时的debug显示信息中使用,指明某某代码块的某行错误;

--env:这个代码块的环境变量;

++++返回值:表明该代码块的delegate或者LuaFunction类;

 

++2.5.1.1.三、LuaTable GLobal;

++++描述:表明Lua全局环境的LuaTable。

 

++2.5.1.1.四、void Tick();

++++描述:清除Lua的手动释放的LuaBase对象(好比:LuaTable,LuaFunction),以及其余一些事情。(须要按期调用,好比在MonoBehaviour的Update中调用。)

 

++2.5.1.1.五、void AddLoader(CustomLoader loader);

++++描述:增长一个自定义loader。

++++参数:

    --loader:一个包括了加载函数的委托,其类型为delegate byte[] CustomLoader(ref string filepath),当一个文件被require时,这个loader会被回调,其参数是调用require所使用的参数,若是该loader找到文件,能够将其读进内存,返回一个byte数组。若是须要支持调试的话,而filepath要设置成IDE能找到的路径(相对路径或绝对路径均可以)。

 

++2.5.1.1.六、void Dispose();

++++描述:Dispose该LuaEnv。

++++立钻哥哥:LuaEnv的使用建议:全局就一个实例,并在Update中调用GC方法,彻底不须要时调用Dispose

 

 

++2.5.1.二、LuaTable类

++++LuaTable类:Get()、GetInPath()、SetInPath()、Get<TKey, TValue>()、Set<TKey, TValue>、Cast()、SetMetaTable()、

++++T Get(string key);

++++T GetInPath(string path);

++++void SetInPath(string path, T val);

++++void Get<TKey, TValue>(Tkey key, out TValue value);

++++void Set<TKey, TValue>(TKey key, TValue value);

++++T Cast();

++++void SetMetaTable(LuaTable metaTable);

 

++2.5.1.2.一、T Get(string key);

++描述:获取在key下,类型为T的value,若是不存在或者类型不匹配,返回null。

 

++2.5.1.2.二、T GetInPath(string path);

++++描述:和Get的区别是,这个函数会识别path里头的“.”,好比var i = tbl.GetInPath<int>(“a.b.c”)至关于在lua里头执行i = tbl.a.b.c,避免仅为了获取中间变量而屡次调用Get,执行效率更高。

 

++2.5.1.2.三、void SetInPath(string path, T val);

++++描述:和GetInPath<T>对应的setter;

 

++2.5.1.2.四、void Get<TKey, TValue>(Tkey key, out TValue value);

++++描述:上面的API的Key都只能是string,而这个API无此限制。

 

++2.5.1.2.五、void Set<TKey, TValue>(TKey key, TValue value);

++++描述:对应Get<TKey, TValue>的setter;

 

++2.5.1.2.六、T Cast();

++++描述:把该table转成一个T指明的类型,能够是一个加了[CSharpCallLua]声明的interface,一个有默认构造函数的class或者struct,一个Dictionary,List等等。

 

++2.5.1.2.七、void SetMetaTable(LuaTable metaTable);

++++描述:设置metaTable为table的metatable。

 

 

++2.5.1.三、LuaFunction类

++++立钻哥哥:用该类访问Lua函数会有boxing、unboxing的开销,为了性能考虑,须要频繁调用的地方不要用该类。建议经过table.Get()获取一个delegate再调用(假设YanlzDelegate是C#的一个delegate)。在使用table.Get()以前,请先把YanlzDelegate加到代码生成列表。

++++LuaFunction类:Call()、Call()、SetEnv()、

++++object[] Call(params object[] args);

++++object[] Call(object[] args, Type[] returnTypes);

++++void SetEnv(LuaTable env);

 

++2.5.1.3.一、object[] Call(params object[] args);

++描述:以可变参数调用Lua函数,并返回该调用的返回值。

 

++2.5.1.3.二、object[] Call(object[] args, Type[] returnTypes);

++描述:调用lua函数,并指明返回参数的类型,系统会自动按指定类型进行转换。

 

++2.5.1.3.三、void SetEnv(LuaTable env);

++描述:至关于lua的setfenv函数。

 

 

++2.5.二、LuaAPI

++++立钻哥哥:CS对象、typeof函数、无符号64位支持、类型映射、宏、

++++【CS对象】

--CS.namespace.class(...);

--CS.namespace.class.field;

--CS.namespace.enum.field;

++++【typeof函数】

++++【无符号64位支持】

--uint64.tostring;

--uint64.divide;

--uint64.compare;

--uint64.remainder;

--uint64.parse;

--xlua.structclone;

--xlua.private_accessible(class);

--cast函数;

++++【类型映射】:基本数据类型、复杂数据类型;

++++【宏】

--HOTFIX_ENABLE;

--NOT_GEN_WARNING;

--GEN_CODE_MINIMIZE;

 

 

++2.5.2.一、CS对象

++++CS对象:class()、class.field、enum.field、

++++【CS对象】

--CS.namespace.class(...);

--CS.namespace.class.field;

--CS.namespace.enum.field;

 

++2.5.2.1.一、CS.namespace.class(...);

++++描述:调用一个C#类型的构造函数,并返回类型实例。

++++例如:local v1 = CS.UnityEngine.Vector3(1,1,1)

 

++2.5.2.1.二、CS.namespace.class.field;

++++描述:访问一个C#静态成员。

++++例如:print(CS.UnityEngine.Vector3.one)

 

++2.5.2.1.三、CS.namespace.enum.field;

++++描述:访问一个枚举值。

 

 

++2.5.2.二、typeof函数

++++描述:相似C#里头的typeof关键字,返回一个Type对象,好比GameObject.AddComponent()其中一个重载须要一个Type参数。

++++例如:newGameObj:AddComponent(typeof(CS.UnityEngine.ParticleSystem))

 

 

++2.5.2.三、无符号64位支持

++++无符号64位支持:uint64.tostring、uint64.divide、uint64.compare、uint64.remainder、uint64.parse、xlua.structclone、xlua.private_accessible()、cast()、

++++uint64.tostring;

++++uint64.divide;

++++uint64.compare;

++++uint64.remainder;

++++uint64.parse;

++++xlua.structclone;

++++xlua.private_accessible(class);

++++cast函数;

 

++2.5.2.3.一、uint64.tostring;

++++描述:无符号数转字符串。

 

++2.5.2.3.二、uint64.divide;

++++描述:无符号数除法。

 

++2.5.2.3.三、uint64.compare;

++++描述:无符号比较,相等返回0,大于返回正数,小于返回负数。

 

++2.5.2.3.四、uint64.remainder;

++++描述:无符号取模。

 

++2.5.2.3.5uint64.parse;

++++描述:字符串转无符号数。

 

++2.5.2.3.六、xlua.structclone;

++++描述:克隆一个C#结构体。

 

++2.5.2.3.七、xlua.private_accessible(class);

++++描述:让一个类的私有字段,属性,方法等可用。

 

++2.5.2.3.八、cast函数;

++++描述:指明以待定的接口访问对象,这在实现类没法访问的时候(好比internal修饰)颇有用,这时能够这么来(假设下面的calc对象实现了C#的YanlzPerforment.ICalc接口)

++++例如:cast(calc, typeof(CS.YanlzPerforment.ICalc))

++++而后有没有其余API访问CSharp对象和访问一个table同样,调用函数跟调用lua函数同样,也能够经过操做符访问C#的操做符,例如:

local v1 = CS.UnityEngine.Vector3(1,1,1)

local v2 = CS.UnityEngine.Vector3(1,1,1)

v1.x = 100

v2.y = 100

print(v1, v2)

local v3 = v1 + v3

print(v1.x, v2.x)

print(CS.UnityEngine.Vector3.one)

print(CS.UnityEngine.Vector3.Distance(v1, v2))

 

++2.5.2.四、类型映射

++++类型映射:基本数据类型、复杂数据类型

++++基本数据类型(Lua类型):number、userdate、userdate/lua_Integer(lua53)、string、boolean、string、

C#类型

Lua类型

sbyte, byte, short, ushort, int, uint, double, char, float

number

decimal

userdata

long, ulong

userdata/lua_Integer(lua53)

bytes[]

string

bool

boolean

string

string

 立钻哥哥:基本数据类型

 

++++复杂数据类型(Lua类型):table、function、userdata,table、function、

C#类型

Lua类型

LuaTable

table

LuaFunction

function

class或者struct的实例

userdate, table

method, delegate

function

立钻哥哥:复杂数据类型

 

++2.5.2.4.一、复杂数据类型

C#类型

Lua类型

LuaTable

table

LuaFunction

function

class或者struct的实例

userdate, table

method, delegate

function

立钻哥哥:复杂数据类型

++++【LuaTable】:C#侧指明从Lua侧输入(包括C#方法的输入参数或者Lua方法的返回值)LuaTable类型,则要求Lua侧为table。或者Lua侧的table,在C#侧未指明类型的状况下转换成LuaTable。

++++【LuaFunction】:C#侧指明从Lua侧输入(包括C#方法的输入参数或者Lua方法的返回值)LuaFunction类型,则要求Lua侧为function。或者Lua侧的function,在C#侧未指明类型的状况下转换成LuaFunction。

++++【LuaUserData】:对应非C# Managered对象的lua userdata。

++++【class或者struct的实例】:从C#传一个class或者struct的实例,将映射到Lua的userdata,并经过__index访问该userdata的成员,C#侧指明从Lua侧输入指定类型对象,Lua侧为该类型实例的userdata能够直接使用;若是该指明类型有默认构造函数,Lua侧是table则会自动转换,转换规则是:调用构造函数构造实例,并用table对应字段转换到C#对应值后赋值各成员。

++++【method,delegate】:成员方法以及delegate都是对应lua侧的函数。C#侧的普通参数以及引用参数,对应lua侧函数参数;C#侧的返回值对应于lua的第一个返回值;引用参数和out参数则按序对应于Lua的第2到第N个参数。

 

 

++2.5.2.五、宏

++++宏:HOTFIX_ENABLENOT_GEN_WARNINGGEN_CODE_MINIMIZE

++++【HOTFIX_ENABLE】:打开hotfix功能。

++++【NOT_GEN_WARNING】:反射时打印warning。

++++【GEN_CODE_MINIMIZE】:以偏向减小代码段的方式生成代码。

 

 

 

###2.六、生成引擎二次开发指南

###2.六、生成引擎二次开发指南

++2.六、生成引擎二次开发指南

++++https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/custom_generate.md

++++xLua的生成引擎支持二次开发,能够利用它来生成一些文本类型的文件(好比代码,配置等)。xLua自己的link.xml文件的生成就是一个生成引擎插件作的。其余应用场景,好比生成Lua IDE的自动完成配置文件,均可以用这特性来完成。

++++插件须要提供两个东西:一、生成文件的模板;二、一个回调函数,该回调函数接受用户的配置,返回须要注入到模板的数据以及文件的输出流。

 

++2.6.一、模板语法

++++模板语法只有三种元素:eval、code、literal。

++++【eval】:语法是<%=exp%>,exp是任意表达式,将计算并以字符串形式输出exp的值;

++++【code】:语法是<% if true then end%>

++++【literal】:除了eval和code以外其它部分,literal原样输出。

//立钻哥哥:示例参考

<%

require TemplateCommon

%>

 

<linker>

<%ForEachCsList(assembly_infos, function(assembly_info)%>

    <assembly fullname=<%=assembly_info.FullName%>>

        <%ForEachCsList(assembly_info.Types, function(type)

            %><type fullname=<%=type:ToString()%> preserve=all/>

            <%end)%>

    </assembly>

<%end)%>

</linker>

++++TemplateCommon有一些预约义的函数可使用,好比ForEachCsList。

 

++2.6.二、API

++++public static void CSObjectWrapEditor.Generator.CustomGen(string template_src, GetTasks get_tasks);

--template_src:模板的源码;

--get_tasks:回调函数,类型是GetTasks,用来接受用户的配置,返回须要注入到模板的数据以及文件的输出流;

++++public delegate IEnumerable<CustomGenTask> GetTasks(LuaEnv lua_env, UserConfig user_cfg);

--lua_env: LuaEnv对象,由于返回的模板数据须要放到LuaTable,须要用到LuaEnv.NewTable;

--user_cfg: 用户的配置;

--return: 返回值中,CustomGenTask表明的是一个生成文件,而IEnumerable类型表示同一个模板能够生成多个文件;

 

++2.6.三、标签

++++通常来讲能够经过MenuItem开一个菜单来执行触发自定义生成操做,但有时但愿生成操做直接由xLua的“Generate Code”菜单触发,就须要用到:CSObjectWrapEditor.GenCodeMenu。

++++示例:

[GenCodeMenu]    //立钻哥哥:加到Generate Code菜单里头

public static void GenLinkXml(){

    Generator.CustomGen(ScriptableObject.CreateInstance<LinkXmlGen>().Template.text, GetTasks);

}

++++立钻哥哥:以上全部相关代码都在“XLua/Src/Editor/LinkXmlGen”目录下,也是link.xml的生成功能的实现。

 

 

 

###2.七、xLua常见问题

###2.七、xLua常见问题

++2.七、xLua常见问题

++++https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/faq.md

 

++2.7.一、xLua发布包怎么用?

++++xLua目前以zip包形式发布,在工程目录下解压便可。

 

++2.7.二、报“please install the Tools”?

++++没有把Tools安装到Assets平级目录,安装包,或者master下都能找到这个目录。

 

++2.7.三、hotfix下怎么触发一个event?

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

++++跟着经过对象的”&事件名”字段调用delegate,例如:self[‘&YanlzEvent’]()。

 

++2.7.四、什么是生成代码?

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

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

 

++2.7.五、应该何时生成代码?

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

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

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

 

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

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

 

++2.7.七、[LuaCallSharp]以及[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]便可。

 

++2.7.八、支持lua调用C#重载函数吗?

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

 

++2.7.九、调用LuaEnv.Dispose()崩溃?

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

 

++2.7.十、支持interface扩展方法么?

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

 

 

 

###2.八、xLua示例参考

###2.八、xLua示例参考

++2.八、xLua示例参考

++++一个完整的例子仅需3行代码(安装好xLua,建一个MonoBehaviour拖到场景,在Start()加入代码):

XLua.LuaEnv luaenv = new XLua.LuaEnv();

luaenv.DoString(CS.UnityEngine.Debug.Log(立钻哥哥带您xLua热更新));

luaenv.Dispose();

++++说明1:DoString参数为string,可输入任意合法的lua代码。

++++说明2:一个LuaEnv实例对应Lua虚拟机,处于开销的考虑,建议全局惟一。

++++C#主动调用lua很简单,好比要调用lua的系统函数,推荐方式是:声明、绑定、调用

--【声明】:

[XLua.CSharpCallLua]

public delegate double LuaMax(double a, double b);

--【绑定】:

var myLuaMax = luaenv.Global.GetInPath<LuaMax>(math.max);

--【调用】:

Debug.Log(立钻哥哥:max:  + myLuaMax(32, 12));

--立钻哥哥建议:建议绑定一次,重复使用。生成了代码的话,调用max是不产生gc alloc的。

++++更多示例:01_Helloworld、02_U#DScripting、03_UIEvent、04_LuaObjectOrented、05_NoGc、06_Coroutine、07_AsyncTest、08_Hotfix、09_GenericMethod、10_SignatureLoader、11_RawObject、12_ReImplementInLua、

 

 

++2.8.一、01_Helloworld:快速入门的例子

//立钻哥哥:快速入门的例子(\Assets\XLua\Examples\01_Helloworld\Helloworld.cs)

using UnityEngine;

using XLua;

 

public class Helloworld : MonoBehaviour{

    //Use this for initialization

    void Start(){

        LuaEnv luaenv = new LuaEnv();

        luaenv.DoString(CS.UnityEngine.Debug.Log(立钻哥哥));

        luaenv.Dispose();

    }

 

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

 

 

 

++2.8.二、02_U3DScripting:展现怎么用lua来写MonoBehaviour

//立钻哥哥:展现怎么用lua来写MonoBehaviour

//(xLua-master\Assets\XLua\Examples\02_U3DScripting\LuaBehaviour.cs)

using UnityEngine;

using System.Collections;

using System.Collections.Generic;

using XLua;

using System;

 

[System.Serializable]

public class Injection{

    public string name;

    public GameObject value;

}    //立钻哥哥:public class Injection{}

 

[LuaCallCSharp]

public class LuaBehaviour : MonoBehaviour{

    public TextAsset luaScript;

    public Injection[] injections;

 

    //立钻哥哥:all lua behaviour shared one luaenv only!

    internal static LuaEnv luaEnv = new LuaEnv();

    internal static float lastGCTime = 0;

    internal const float GCInterval = 1;    //1 second

 

    private Action luaStart;

    private Action luaUpdate;

    private Action luaOnDestroy;

 

    private LuaTable scriptEnv;

 

    void Awake(){

        scriptEnv = luaEnv.NewTable();

 

        //为每一个脚本设置一个独立的环境,可防止脚本间全局变量、函数冲突

        LuaTable meta = luaEnv.NewTable();

        meta.Set(__index, luaEnv.Global);

        scriptEnv.SetMetaTable(meta);

        meta.Dispose();

 

        scriptEnv.Set(self, this);

        foreach(var injection in injections){

            scriptEnv.Set(injection.name, injection.value);

        }

 

        luaEnv.DoString(luaScript.text, LuaBehaviour, scriptEnv);

 

        Action luaAwake = scriptEnv.Get<Action>(awake);

        scirptEnv.Get(start, out luaStart);

        scriptEnv.Get(update, out luaUpdate);

        scriptEnv.Get(ondestroy, out luaOnDestroy);

 

        if(luaAwake != null){

            luaAwake();

        }

    }

 

    //Use this for initialization

    void Start(){

        if(luaStart != null){

            luaStart();

        }

    }

 

    //Update is Called once per frame

    void Update(){

        if(luaUpdate != null){

            luaUpdate();

        }

 

        if(Time.time - LuaBehaviour.lastGCTime > GCInterval){

            luaEnv.Tick();

            LuaBehaviour.lastGCTime = Time.time;

        }

    }

 

    void OnDestroy(){

        if(luaOnDestroy != null){

            luaOnDestroy();

        }

 

        luaOnDestroy = null;

        luaUpdate = null;

        luaStart = null;

        scriptEnv.Dispose();

        Injections = null;

    }

 

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

 

//立钻哥哥:lua部分(\Assets\XLua\Examples\02_U3DScripting\LuaTestScript.lua.txt)

local speed = 10

local lightCpnt = nil

 

function start()

    print(立钻哥哥:lua start...)

    print(立钻哥哥:injected object)

    lightCpnt = lightObject:GetComponent(typeof(CS.UnityEngine.Light))

end

 

function update()

    local r = CS.UnityEngine.Vector3.up * CS.UnityEngine.Time.deltaTime * speed

    self.transform:Rotate(r)

    lightCpnt.color = CS.UnityEngine.Color(CS.UnityEngine.Mathf.Sin(CS.UnityEngine.Time.time)/2 + 0.5, 0, 0, 1)

end

 

function ondestroy()

    print(立钻哥哥:lua destroy)

end

 

 

 

 

++2.8.三、03_UIEvent:展现怎么用lua来写UI逻辑

//立钻哥哥:展现怎么用lua来写UI逻辑(\Examples\03_UIEvent\ButtonInteraction.lua.txt)

function start()

    print(立钻哥哥:lua start ...)

 

    self:GetComponent(Button).onClick:AddListener(function()

        print(立钻哥哥:clicked, you input is  ..input:GetComponent(InputField).text .. ”’ );

    end)

end

 

 

 

++2.8.四、04_LuaObjectOrented:展现lua面向对象和C#的配合

//立钻哥哥:展现lua面向对象和C#的配合(\04_LuaObjectOriented\InvokeLua.cs)

using System;

using UnityEngine;

using XLua;

 

public class PropertyChangedEventArgs : EventArgs{

    public string name;

    public object value;

}    //立钻哥哥:public class PropertyChangedEventArgs : EventArgs{}

 

public class InvokeLua : MonoBehaviour{

    [CSharpCallLua]

    public interface ICalc{

        event EventHandler<PropertyChangedEventArgs> PropertyChanged;

    

        int Add(int a, int b);

        int Mult{  get;  set;  };

 

        object this[int index]{  get;  set;  }

    }

 

    [CSharpCallLua]

    public delegate ICalc CalcNew(int mult, params string[] args);

 

    private string scrpit = @

        local calc_mt = {

            __index = {

                Add = function(self, a, b)

                    return (a + b) * self.Mult

                end,

            

                get_Item = function(self, index)

                    return self.list[index + 1]

                end,

 

                set_Item = function(self, index, value)

                    self.list[index + 1] = value

                    self:notify({  name = index, value = value })

                end,

 

                add_PropertyChanged = function(self, delegate)

                    if self.notifyList == nil then

                        self.notifylist = {}

                    end

                    table.insert(self.notifylist, delegate)

                    print(add, delegate)

                end,

 

                remove_PropertyChanged = function(self, delegate)

                    for i = 1, #self.notifylist do

                        if CS.System.Object.Equals(self.notifylist[i], delegate) then

                            table.remove(self.notifylist, i)

                            break

                        end

                    end

                    print(remove, delegate)

                end,

 

                notify = function(self, evt)

                    if self.notifylist ~= nil then

                        for i = 1, #self.notifylist do

                            self.notifylist[i](self, evt)

                        end

                    end

                end,

            }    //立钻哥哥:__index = {}

        }    //立钻哥哥:local calc_mt = {}

 

        Calc = {

            New = functon(mult, ...)

                print(...)

                return setmetatable({Mult = mult, list = {aaaa, bbbb, cccc}}, calc_mt)

            end

        }

    ”;    //立钻哥哥:private string script = @ ;

 

    //Use this for initialization

    void Start(){

        LuaEnv luaenv = new LuaEnv();

 

        //立钻哥哥:调用了带可变参数的delegate,函数结束都不会释放delegate,即便置空并调用GC

        Test(luaenv);

 

        luaenv.Dispose();

    }

 

    void Test(LuaEnv luaenv){

        luaenv.DoString(script);

        CalcNew calc_new = luaenv.Global.GetInPath<CalcNew>(Calc.New);

 

        ICalc calc = calc_new(10, hi, john);    //立钻哥哥:constructor

        Debug.Log(立钻哥哥:sum(*10)= + calc.Add(1, 2));

 

        calc.Mult = 100;

        Debug.Log(立钻哥哥:sum(*100)= + calc.Add(1, 2));

 

        Debug.Log(立钻哥哥:list[0]= + calc[0]);

        Debug.Log(立钻哥哥:list[1]= + calc[1]);

    

        calc.PropertyChanged += Notify;

        calc[1] = dddd;

        Debug.Log(立钻哥哥:list[1]= + calc[1]);

 

        calc.PropertyChanged -= Notify;

    

        calc[1] = eeee;

        Debug.Log(立钻哥哥:list[1]= + calc[1]);

    }

 

    void Notify(object sender, PropertyChangedEventArgs e){

        Debug.Log(string.Format({0} has property changed {1}={2}, sender, e.name, e.value));

    }

 

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

 

 

 

++2.8.五、05_NoGc:展现怎么去避免值类型的GC

//立钻哥哥:展现怎么去避免值类型的GC(\Assets\XLua\Examples\05_NoGc\NoGc.cs)

using UnityEngine;

using System;

using XLua;

 

namespace XLuaTest{

    [GCOptimize]

    [LuaCallCSharp]

    public struct Pedding{

        public byte c;

    }    //立钻哥哥:public struct Pedding{}

 

    [GCOptimize]

    [LuaCallCSharp]

    public struct MyStruct{

        public MyStruct(int p1, int p2){

            a = p1;

            b = p2;

            c = p2;

            e.c = (byte)p1;

        }

        public int a;

        public int b;

        public decimal c;

        public Pedding e;

    }    //立钻哥哥:public struct MyStruct{}

 

    [LuaCallCSharp]

    public enum MyEnum{

        E1,

        E2

    }

 

    [CSharpCallLua]

    public delegate int IntParam(int p);

 

    [CSharpCallLua]

    public delegate Vector3 Vector3Param(Vector3 p);

 

    [CSharpCallLua]

    public delegate MyStruct CustomValueTypeParam(MyStruct p);

 

    [CSharpCallLua]

    public delegate MyEnum EnumParam(MyEnum p);

 

    [CSharpCallLua]

    public delegate decimal DecimalParam(decimal p);

 

    [CSharpCallLua]

    Public delegate void ArrayAccess(Array arr);

 

    [CSharpCallLua]

    public interface IExchanger{

        void exchange(Array arr);

    }

 

    [LuaCallCSharp]

    public class NoGc : MonoBehaviour{

        LuaEnv luaenv = new LuaEnv();

 

        IntParam f1;

        Vector3Param f2;

        CustomValueTypeParam f3;

        EnumParam f4;

        DecimalParam f5;

 

        ArrayAccess farr;

        Action flua;

        IExchanger ie;

        LuaFunction add;

 

        [NonSerialized]

        public double[] a1 = new double[]{ 1, 2 };

        [NonSerialized]

        public Vector3[] a2 = new Vector3[]{  new Vector3(1,2,3), new Vector3(4,5,6) };

        [NonSerialized]

        public MyStruct[] a3 = new MyStruct[]{  new MyStruct(1,2), new MyStruct(3,4) };

        [NonSerialized]

        public MyEnum[] a4 = new MyEnum[]{  MyEnum.E1, MyEnum.E2 };

        [NonSerialized]

        public decimal[] a5 = new decimal[]{  1.00001M, 2.00002M };

 

        public float FloatParamMethod(float p){

            return p;

        }

 

        public Vector3 Vector3ParamMethod(Vector3 p){

            return p;

        }

 

        public MyStruct StructParamMethod(MyStruct p){

            return p;

        }

 

        public MyEnum EnumParamMethod(MyEnum p){

            return p;

        }

 

        public decimal DecimalParamMethod(decimal p){

            return p;

        }

 

        //Use this for initialization

        void Start(){

            luaenv.DoString(@

                function id(...)

                    return ...

                end

 

                function add(a,b) return a + b end

 

                function array_exchange(arr)

                    arr[0], arr[1] = arr[1], arr[0]

                end

 

                local v3 = CS.UnityEngine.Vector3(7, 8, 9)

                local vt = CS.XLuaTest.MyStruct(5, 6)

 

                function lua_access_csharp()

                    monoBehaviour:FloatParamMethod(123)    --primitive

                    monoBehaviour:Vector3ParamMethod(v3)    --vector3

 

                    local rnd = math.random(1, 100)

                    local r = monoBehaviour:Vector3ParamMethod({x=1, y=2, z=rnd})

                    assert(r.x==1 and r.y==2 and r.z==rnd)

                    monoBehaviour:StructParamMethod(vt)    --custom struct

                    r = monoBehaviour:StructParamMethod({a=1, b=rnd, e={c=rnd}})

                    assert(r.b==rnd and r.e.c==rnd)

                    monoBehaviour:EnumParamMethod(CS.XLuaTest.MyEnum.E2) --enum

                    monoBehaviour:DecimalParamMethod(monoBehaviour.a5[0])

                    monoBehaviour.a1[0], monoBehaviour.a1[1]=monoBehaviour.a1[1],monoBehaviour.a1[0]    --field

                end

 

                exchanger = {

                    exchange = function(self, arr)

                       array_exchange(arr)

                    end

                }

 

                A = { B={ C=789}}

                GDATA = 1234;

            ”);

 

            luaenv.Global.Set(monoBehaviour, this);

            luaenv.Global.Get(id, out f1);

            luaenv.Global.Get(id, out f2);

            luaenv.Global.Get(id, out f3);

            luaenv.Global.Get(id, out f4);

            luaenv.Global.Get(id, out f5);

 

            luaenv.Global.Get(array_exchange, out farr);

            luaenv.Global.Get(lua_access_csharp, out flua);

            luaenv.Global.Get(exchanger, out ie);

            luaenv.Global.Get(add, out add);

 

            luaenv.Global.Set(g_int, 123);

            luaenv.Global.Set(123, 456);

 

            int i;

            luaenv.Global.Get(g_int, out i);

            Debug.Log(立钻哥哥:g_int:  + i);

 

            luaenv.Global.Get(123, out i);

            Debug.Log(立钻哥哥:123:  + i);

 

        }    //立钻哥哥:void Start(){}

 

        //Update is called once per frame

        void Update(){

            //立钻哥哥:C# call lua function with value type but no gc (using delegate)

            f1(1);    //立钻哥哥:primitive type

            f2(new Vector3(1, 2, 3));    //立钻哥哥:vector3

            MyStruct mystruct1 = new MyStruct(5, 6);

            f3(mystruct1);    //立钻哥哥:custom complex value type

            f4(MyEnum.E1);    //立钻哥哥:enum

            decimal dec1 = -32132143143100109.00010001010M;

            f5(dec1);    //立钻哥哥:decimal

 

            add.Func<int, int, int>();    //立钻哥哥:LuaFunction.Func<T1, T2, TResult>

 

            //立钻哥哥:lua access C# value type array no gc

            farr(a1);   //立钻哥哥:primitive value type array

            farr(a2);    //立钻哥哥:vector3 array

            farr(a3);    //立钻哥哥:custom struct array

            farr(a4);    //立钻哥哥:enum array

            farr(a5);    //立钻哥哥:decimal array

 

            //立钻哥哥:lua call C# no gc with value type

            flua();

 

            //立钻哥哥:C# call lua using interface

            ie.exchange(a2);

 

            //立钻哥哥:no gc LuaTable use

            luaenv.Global.Set(g_int, 456);

            int i;

            luaenv.Global.Get(g_int, out i);

 

            luaenv.Global.Set(123.0001, mystruct1);

            MyStruct mystruct2;

            luaenv.Global.Get(123.0002, out mystruct2);

 

            decimal dec2 = 0.0000001M;

            luaenv.Global.Set((byte)12, dec1);

            luaenv.Global.Get((byte)12, out dec2);

 

            int gdata = luaenv.Global.Get<int>(GDATA);

            luaenv.Global.SetInPath(GDATA, gdata + 1);

 

            int abc = luaenv.Global.GetInPath<int>(A.B.C);

            luaenv.Global.SetInPath(A.B.C, abc + 1);

 

            luaenv.Tick();

  

        }    //立钻哥哥:void Update(){}

 

        void OnDestroy(){

            f1 = null;

            f2 = null;

            f3 = null;

            f4 = null;

            f5 = null;

            farr = null;

            flua = null;

            ie = null;

            add = null;

            luaenv.Dispose();

        }    //立钻哥哥:void OnDestroy(){}

 

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

 

}    //立钻哥哥:namespace XLuaTest{}

 

 

 

++2.8.六、06_Coroutine:展现lua协程怎么和Unity协程相配合

++2.8.六、06_Coroutine:展现lua协程怎么和Unity协程相配合

++2.8.六、06_Coroutine:展现lua协程怎么和Unity协程相配合

++2.8.六、06_Coroutine:展现lua协程怎么和Unity协程相配合

//立钻哥哥:展现lua协程怎么和Unity协程相配合

//Runner(xLua-master\Assets\XLua\Examples\06_Coroutine\Coroutine_Runner.cs)

using UnityEngine;

using XLua;

using System.Collections.Generic;

using System.Collections;

using System;

 

[LuaCallCSharp]

public class Coroutine_Runner : MonoBehaviour{

    public void YieldAndCallback(object to_yield, Action callback){

        StartCoroutine(CoBody(to_yield, callback));

    }

 

    private IEnumerator CoBody(object to_yield, Action callback){

        if(to_yield is IEnumerator){

            yield return StartCoroutine((IEnumerator)to_yield);

        }else{

            yield return to_yield;

        }

 

        callback();

    }

 

    public static class CoroutineConfig{

        [LuaCallCSharp]

        public static List<Type> LuaCallCSharp{

            get{

                return new List<Type>(){

                    typeof(WaitForSeconds),

                    typeof(WWW)

                };

            }

        }

    }

 

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

 

//立钻哥哥:CoroutineTest(xLua-master\Assets\XLua\Examples\06_Coroutine\CoroutineTest.cs)

using UnityEngine;

using XLua;

 

public class CoroutineTest : MonoBehaviour{

    LuaEnv luaenv = null;

 

    //Use this for initialization

    void Start(){

        luaenv = new LuaEnv();

        luaenv.DoString(require coroutine_test’”);

    }

 

    //Update is called once per frame

    void Update(){

        if(luaenv != null){

            luaenv.Tick();

        }

    }

 

    void OnDestroy(){

        luaenv.Dispose();

    }

 

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

 

//立钻哥哥:coruntine_test.lua(\Examples\06_Coroutine\Resources\coruntine_test.lua.txt)

local util = require xlua.util

local yield_return = (require cs_coroutine).yield_return

 

local co = coroutine.create(function()

    print(coroutine start!)

    local s = os.time()

    yield_return(CS.UnityEngine.WaitForSeconds(3))

    print(wait interval:, os.time() - s)

 

    local www = CS.UnityEngine.WWW(http://www.lovezuanzuan.com)

    yield_return(www)

    if not www.error then

         print(www.bytes)

    else

        print(error:, www.error)

    end

end)

 

assert(coroutine.resume(co))

 

//立钻哥哥:cs_coroutine.lua(\Examples\06_Coroutine\Resources\cs_coroutine.lua.txt)

local util = require xlua.util

 

local gameobject = CS.UnityEngine.GameObject(Coroutine_Runner)

CS.UnityEngine.Object.DontDestroyOnLoad(gameobject)

local cs_coroutine_runner = gameobject:AddComponent(typeof(CS.Coroutine_Runner))

 

local function async_yield_return(to_yield, cb)

    cs_coroutine_runner:YieldAndCallback(to_yield, cb)

end

 

return{

    yield_return = util.async_to_sync(async_yield_return)

}

 

 

 

 

++2.8.七、07_AsyncTest:展现怎么用lua协程来把异步逻辑同步化

++2.8.七、07_AsyncTest:展现怎么用lua协程来把异步逻辑同步化

//立钻哥哥:展现怎么用lua协程来把异步逻辑同步化

//(xLua-master\Assets\XLua\Examples\07_AsyncTest\AsyncTest.cs)

using UnityEngine;

using XLua;

using System.Collection.Generic;

using System;

 

public class AsyncTest : MonoBehaviour{

    LuaEnv luaenv = null;

 

    void Start(){

        luaenv = new LuaEnv();

        luaenv.DoString(require async_test’”);

    }

 

    //Update is called once per frame

    void Update(){

        if(luaenv != null){

            luaenv.Tick();

        }

    }

 

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

 

//立钻哥哥:MessageBox(xLua-master\Assets\XLua\Examples\07_AsyncTest\MessageBox.cs)

using UnityEngine;

using UnityEngine.UI;

using XLua;

using System.Collections.Generic;

using System;

using UnityEngine.Events;

 

public class MessageBox : MonoBehaviour{

    public static void ShowAlertBox(string message, string title, Action onFinished = null){

        var alertPanel = GameObject.Find(Canvas).transform.Find(AlertBox);

        if(alertPanel == null){

            alertPanel = (Instantiate(Resources.Load(AlertBox)) as GameObject).transform;

            alertPanel.gameObject.name = AlertBox;

            alertPanel.SetParent(GameObject.Find(Canvas).transform);

            alertPanel.localPosition = new Vector3(-6f, -6f, 0f);

        }

 

        alertPanel.Find(title).GetComponent<Text>().text = title;

        alertPanel.Find(message).GetComponent<Text>().text = message;

 

        var button = alertPanel.Find(alertBtn).GetComponent<Button>();

        UnityAction onclick = ()=>{

            if(onFinished != null){

                onFinished();

            }

            button.onClick.RemoveAllListeners();

            alertPanel.gameObject.SetActive(false);

        };

 

        //立钻哥哥:防止消息框未关闭时屡次被调用

        button.onClick.RemoveAllListeners();

        button.onClick.AddListener(onclick);

        alertPanel.gameObject.SetActive(true);

    }    //立钻哥哥:public static void ShowAlertBox(){}

 

    public static void ShowConfirmBox(string message, string title, Action<bool> onFinished = null){

        var confirmPanel = GameObject.Find(Canvas).transform.Find(ConfirmBox);

        if(confirmPanel == null){

            confirmPanel = (Instantiate(Resources.Load(ConfirmBox)) as GameObject).transform;

            confirmPanel.gameObject.name = ConfirmBox;

            confirmPanel.SetParent(GameObject.Find(Canvas).transform);

            confirmPanel.localPosition = new Vector3(-8f, -18f, 0f);

        }

 

        confirmPanel.Find(confirmTitle).GetComponent<Text>().text = title;

        confirmPanel.Find(conmessage).GetComponent<Text>().text = message;

 

        var confirmBtn = confirmPanel.Find(confirmBtn).GetComponent<Button>();

        var cancelBtn = confirmPanel.Find(cancleBtn).GetComponent<Button>();

        Action cleanup = ()=>{

            confirmBtn.onClick.RemoveAllListeners();

            cancelBtn.onClick.RemoveAllListeners();

            confirmPanel.gameObject.SetActive(false);

        };

 

        UnityAction onconfirm = ()=>{

            if(onFinished != null){

                onFinished(true);

            }

            cleanup();

        };

 

        UnityAction oncancel = ()=>{

             if(onFinished != null){

                onFinished(false);

            }

            cleanup();

        };

 

        //立钻哥哥:防止消息框未关闭屡次被调用

        confirmBtn.onClick.RemoveAllListeners();

        confirmBtn.onClick.AddListener(onconfirm);

        cancelBtn.onClick.RemoveAllListeners();

        cancelBtn.onClick.AddListener(oncancel);

        confirmPanel.gameobject.SetActive(true);

 

    }    //立钻哥哥:public static void ShowConfirmBox(){}

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

 

public static class MessageBoxConfig{

    [CSharpCallLua]

    public static List<Type> CSharpCallLua = new List<Type>(){

        typepf(Action),

        typeof(Action<bool>),

        typeof(UnityAction),

    };

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

 

//立钻哥哥:aync_test.lua(\Assets\XLua\Examples\07_AsyncTest\Resources\async_test.lua.txt)

local util = require xlua.util

local message_box = require message_box

 

---------------------------async_recharge--------------------------------------

//立钻哥哥:模拟异步充值

local function async_recharge(num, cb)

print(立钻哥哥:request server ....)

cb(true, num);

end

 

local recharge = util.async_to_sync(async_recharge)

---------------------------async_recharge end--------------------------------------

 

local buy = function()

    message_box.alert(立钻哥哥:您余额不足,请充值!, 余额提醒)

 

    if message_box.confirm(确认充值10元吗?, 确认框) then

        local r1, r2 = recharge(10)

        print(立钻哥哥:recharge result:, r1, r2);

        message_box.alert(充值成功, 提示)

    else

        print(立钻哥哥:cancel)

        message_box.alert(取消充值!, 提示)

    end

 

    print(立钻哥哥:recharge finished!);

end

 

//立钻哥哥:将按钮监听点击事件,绑定buy方法

CS.UnityEngine.GameObject.Find(Button):GetComponent(Button).onClick:AddListener(util.coroutine_call(buy))

 

//立钻哥哥:message_box.lua(\XLua\Examples\07_AsyncTest\Resources\message_box.lua.txt)

local util = require xlua.util

 

local sync_alert = util.async_to_sync(CS.MessageBox.ShowAlertBox)

local sync_confirm = util.async_to_sync(CS.MessageBox.ShowConfirmBox)

 

//立钻哥哥:构造alert和confirm函数

return{

     alert = function(message, title)

        sync_alert(message, title)

    end;

 

    confirm = function(message, title)

        local ret = sync_confirm(message, title)

        return ret == true

    end;

}

 

 

 

 

 

###2.九、xLua拓展总结

###2.九、xLua拓展总结

 

 

 

 

 

 

 

 

 

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

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

++++Lua快速入门篇(XLua教程):http://www.javashuo.com/article/p-pduvmusb-ho.html

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

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

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

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

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

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

++++UML类图http://www.javashuo.com/article/p-sxberuew-bm.html

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

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

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

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

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

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

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

++++UGUI基础http://www.javashuo.com/article/p-rukxwckw-mc.html

++++UGUI进阶http://www.javashuo.com/article/p-wcatruhq-gt.html

++++UGUI综合http://www.javashuo.com/article/p-dkccmqii-gg.html

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

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

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

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

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

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

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

++++Unity网络http://www.javashuo.com/article/p-sqrlntgh-dw.html

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

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

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

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

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

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

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

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

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

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

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

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