【学习笔记】从零开始学ToLua(三)样例续

(下面的代码块中是c#的代码,引用块中的是lua中的代码)

如何创建自定义的loader

  • 最关键一点在:return new LuaResLoader()
  • LuaResLoader继承自LuaFileUtils
  • 可以设置是否加载LuaBundle开关:
 public LuaResLoader()
    {
        instance = this;
        beZip = false;
    }

 

  • 重载拦截到读取Lua文件的override byte[] ReadFile(string fileName)函数,可以在里面做自己的解密、读取顺序优先级(先读取沙盒目录、再读取Resource)等操作等,返回lua虚拟机认可的byte[]即可。 

out

  • 要使用到out参数的地方我们直接使用nil作为参数,输出的时候就是我们的out参数类型了

protocol buffers

  • protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。可以类比于XML,JSON。
  • XML、JSON 更注重数据结构化,关注人类可读性和语义表达能力。ProtoBuf 更注重数据序列化,关注效率、空间、速度,人类可读性差,语义表达能力不足(为保证极致的效率,会舍弃一部分元信息)
  • 使用命名空间 using ProtoBuf;
  • msg:ParseFromString(TestProtol.data) 有个变量data,它是TestProtol类中一个LuaByteBuffer类型(使用[LuaByteBufferAttribute])的变量,就是为了传递c#与lua间的序列化后的数据,不光是protobuf-lua-gen数据,pbc跟sproto数据都是通过LuaByteBuffer来传递数据。
  • 实际应用如Socket.Send(LuaStringBuffer buffer)函数发送协议, 在lua中调用Socket.Send(pb_data)
  • 读取协议 Socket.PeekMsgPacket() {return MsgPacket}; lua 中,取协议字节流 MsgPack.data 为 LuaStringBuffer类型
  • msg = Socket.PeekMsgPacket() 
  • pb_data = msg.data 

 

int64

  • ToLua实现了对int64的支持,我们还可以将int64转换成两个int32 l, h = uint64.tonum2(x)   

继承

  • lua是没有类的概念的,但是通过合理的使用lua的元表,可以模拟类的一些相关特性。
  •  这个样例中,在lua片段中,创建一个空表LuaTransform,在这个表中设置一个方法Extend。该方法的参数是transform对象,方法中使用tolua.setpeer扩展包装transform。
  • tolua.setpeer,本质上是将变量t设置成transform的替身,在获取transform的属性时,会通过在t中查找,找不到就回去虚拟栈中查找。这里的继承,并非通常意义上使用lua模拟类来实现继承的方法,会更复杂一些。
  • 关于peer表,lua与其他语言的交互均以表的操作为基础,当我们想扩展某个对象时,把扩展内容放在metatable中显然不太合适,因为metatable中的内容是所有对象都具备的,为了解决这个问题,lua中引入了一个专门的表来存放我们在lua中对其他语言的对象的扩展内容,这个表在tolua中就叫做peer表。
  • 关于setPeer更详细的内容在后面的博客讨论。
  • 设置索引

t.__index = t  --__index元方法(index元方法是本身,会在自身进行查找)

  • 重写同名属性获取,设置方法。
  • local get = tolua.initget(t)  --初始化访问器

    local set = tolua.initset(t) 

    --重写同名属性获取        

                get.position = function(self)                              

                    return _position                

                end            

     

    --重写同名属性设置

                set.position = function(self, v)                                                                

                    if _position ~= v then         

                        _position = v                    

                        _base.position = v                                                                                      

                    end

                end

  • 重写同名函数 

--重写同名函数

            function t:Translate(...)            

                print('child Translate')

                _base:Translate(...)                   

            end  

Bundle 

  • 如何加载打包进assetbundle中的lua代码
  • 1,LuaBundle的开关打开file.beZip = true; 这个通过我们之前提到过的LuaFileUtils来实现。
  • 2,将"Lua.unity3d", "Lua_math.unity3d", "Lua_system.unity3d", "Lua_u3d.unity3d", "Lua_protobuf.unity3d" 等核心lua代码库都加载了。
  • 3,将加载的AssetBundle对象添加LuaFileUtils.Instance.AddSearchBundle(name, www.assetBundle);
public IEnumerator LoadBundles()
    {
        string streamingPath = Application.streamingAssetsPath.Replace('\\', '/');

#if UNITY_5 || UNITY_2017 || UNITY_2018
#if UNITY_ANDROID && !UNITY_EDITOR
        string main = streamingPath + "/" + LuaConst.osDir + "/" + LuaConst.osDir;
#else
        string main = "file:///" + streamingPath + "/" + LuaConst.osDir + "/" + LuaConst.osDir;
#endif
        WWW www = new WWW(main);
        yield return www;

        AssetBundleManifest manifest = (AssetBundleManifest)www.assetBundle.LoadAsset("AssetBundleManifest");
        List<string> list = new List<string>(manifest.GetAllAssetBundles());        
#else
        //此处应该配表获取
        List<string> list = new List<string>() { "lua.unity3d", "lua_cjson.unity3d", "lua_system.unity3d", "lua_unityengine.unity3d", "lua_protobuf.unity3d", "lua_misc.unity3d", "lua_socket.unity3d", "lua_system_reflection.unity3d" };
#endif
        bundleCount = list.Count;

        for (int i = 0; i < list.Count; i++)
        {
            string str = list[i];

#if UNITY_ANDROID && !UNITY_EDITOR
            string path = streamingPath + "/" + LuaConst.osDir + "/" + str;
#else
            string path = "file:///" + streamingPath + "/" + LuaConst.osDir + "/" + str;
#endif
            string name = Path.GetFileNameWithoutExtension(str);
            StartCoroutine(CoLoadBundle(name, path));            
        }

        yield return StartCoroutine(LoadFinished());
    }

cjson

  • 打开cjson的库支持
 protected overlay void OpenLibs()
    {
        base.OpenLibs() ;
        OpenCJson();                  
    }
  • 这个开关在LuaClient.cs里面
 protected void OpenCJson()
    {
        luaState.LuaGetField(LuaIndexes.LUA_REGISTRYINDEX,“ _LOADED”);
        luaState.OpenLibs(LuaDLL.luaopen_cjson);
        luaState.LuaSetField(-2,“ cjson”);

        luaState.OpenLibs(LuaDLL.luaopen_cjson_safe);
        luaState.LuaSetField(-2,“ cjson.safe”);
    }
  •  修改lua虚拟机的植入,打开cjson,将cjson表名设置进去。然后加载json文件TextAsset text =(TextAsset)Resources.Load(“ jsonexample”,typeof(TextAsset));
  • 并使其传递给lua,直接解析:本地数据= json.decode(str)。当然你可以可以将解析出来的表,再次编码成字符串:s = json.encode(data)

 UTF8

  •  local utf8 = utf8
  • 遍历字符串

local s = '遍历字符串'                                        

        for i in utf8.byte_indices(s) do            
            local next = utf8.next(s, i)                  
            print(s:sub(i, next and next -1))
        end 

 local len = utf8.len(s)                              

        for i = 2, len + 1 do
            print(utf8.sub(s, 1, i)..'...')        
        end

  • count

local s1 = '天下风云出我辈'        
        print('风云 count is: '..utf8.count(s1, '风云'))

  • 替换 

s1 = s1:gsub('风云', '風雲')

        local function replace(s, i, j, repl_char)            
            if s:sub(i, j) == '辈' then
                return repl_char            
            end
        end

        print(utf8.replace(s1, replace, '輩'))

string

 

 function Test()

        local str = System.String.New('男儿当自强')

        local index = str:IndexOfAny('儿自')

        print('and index is: '..index)

        local buffer = str:ToCharArray()

        print('str type is: '..type(str)..' buffer[0] is ' .. buffer[0])

        local luastr = tolua.tolstring(buffer)

        print('lua string is: '..luastr..' type is: '..type(luastr))

        luastr = tolua.tolstring(str)

        print('lua string is: '..luastr)                    

    end

反射

  • tolua#说明: tolua#不支持动态反射,因为il2cpp之后,很多未用到的属性并不一定会发布到运行包中,这样即使有动态反射也很基类,因为你想动态获取的属性不一定有。tolua#提供的替换方法是 preloading, 把你未来可能需要的类型添加到导出列表customTypeList,同时也添加到dynamicList列表中,这样导出后该类型并不会注册到lua中,你可以通过 require "namespace.classname" 这样的方式把其动态注册到lua中,对于非枚举类型tolua#系统可以在第一次push该类型时动态载入,也可在登录场景加载或者某个你需要的函数中require这个类型
  • 下面是实例代码

function Test()  

        local t = typeof('TestExport')        

        local func = tolua.getmethod(t, 'TestReflection')           

        func:Call()        

        func:Destroy()

        func = nil

        

        local objs = {Vector3.one, Vector3.zero}

        local array = tolua.toarray(objs, typeof(Vector3))

        local obj = tolua.createinstance(t, array)

        --local constructor = tolua.getconstructor(t, typeof(Vector3):MakeArrayType())

        --local obj = constructor:Call(array)        

        --constructor:Destroy()

 

        func = tolua.getmethod(t, 'Test', typeof('System.Int32'):MakeByRefType())        

        local r, o = func:Call(obj, 123)

        print(r..':'..o)

        func:Destroy()

 

        local property = tolua.getproperty(t, 'Number')

        local num = property:Get(obj, null)

        print('object Number: '..num)

        property:Set(obj, 456, null)

        num = property:Get(obj, null)

        property:Destroy()

        print('object Number: '..num)

 

        local field = tolua.getfield(t, 'field')

        num = field:Get(obj)

        print('object field: '.. num)

        field:Set(obj, 2048)

        num = field:Get(obj)

        field:Destroy()

        print('object field: '.. num)       

        

        field = tolua.getfield(t, 'OnClick')

        local onClick = field:Get(obj)        

        onClick = onClick + DoClick        

        field:Set(obj, onClick)        

        local click = field:Get(obj)

        click:DynamicInvoke()

        field:Destroy()

        click:Destroy()

    end  

List

  • 具体使用方法看代码即可
  • 值得的是注意推导后的委托声明必须注册, 这里是System.Predicate<int>
  • local index = list:FindIndex(System.Predicate_int(Exist2))

struct

  • Rect是我们创建的一个结构,下面是toLua对结构支持的操作,具体的函数可以在样例中查看。

        StackTraits<Rect>.Init(PushRect, CheckRectValue, ToRectValue);           //支持压入lua以及从lua栈读取
        TypeTraits<Rect>.Init(CheckRectType);                                    //支持重载函数TypeCheck.CheckTypes
        TypeTraits<Nullable<Rect>>.Init(CheckNullRectType);                      //支持重载函数TypeCheck.CheckTypes
        LuaValueTypeName.names[LuaValueType.Rect] = "Rect";                      //CheckType失败提示的名字
        TypeChecker.LuaValueTypeMap[LuaValueType.Rect] = typeof(Rect);           //用于支持类型匹配检查操作
        ToLua.ToVarMap[LuaValueType.Rect] = ToRectTable;                         //Rect作为object读取
        ToLua.VarPushMap[typeof(Rect)] = (L, o) => { PushRect(L, (Rect)o); };    //Rect作为object压入

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值