找回密码
 立即注册
查看: 333|回复: 0

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

[复制链接]
发表于 2023-4-10 10:16 | 显示全部楼层 |阅读模式
(下面的代码块中是c#的代码,引用块中的是lua中的代码)

如何创建自定义的loader

    最关键一点在:return new LuaResLoader()LuaResLoader继承自LuaFileUtils可以设置是否加载LuaBundle开关:
  1. public LuaResLoader()
  2.     {
  3.         instance = this;
  4.         beZip = false;
  5.     }
复制代码
    重载拦截到读取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);
  1. public IEnumerator LoadBundles()
  2.     {
  3.         string streamingPath = Application.streamingAssetsPath.Replace('\\', '/');
  4. #if UNITY_5 || UNITY_2017 || UNITY_2018
  5. #if UNITY_ANDROID && !UNITY_EDITOR
  6.         string main = streamingPath + "/" + LuaConst.osDir + "/" + LuaConst.osDir;
  7. #else
  8.         string main = "file:///" + streamingPath + "/" + LuaConst.osDir + "/" + LuaConst.osDir;
  9. #endif
  10.         WWW www = new WWW(main);
  11.         yield return www;
  12.         AssetBundleManifest manifest = (AssetBundleManifest)www.assetBundle.LoadAsset("AssetBundleManifest");
  13.         List<string> list = new List<string>(manifest.GetAllAssetBundles());        
  14. #else
  15.         //此处应该配表获取
  16.         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" };
  17. #endif
  18.         bundleCount = list.Count;
  19.         for (int i = 0; i < list.Count; i++)
  20.         {
  21.             string str = list[i];
  22. #if UNITY_ANDROID && !UNITY_EDITOR
  23.             string path = streamingPath + "/" + LuaConst.osDir + "/" + str;
  24. #else
  25.             string path = "file:///" + streamingPath + "/" + LuaConst.osDir + "/" + str;
  26. #endif
  27.             string name = Path.GetFileNameWithoutExtension(str);
  28.             StartCoroutine(CoLoadBundle(name, path));            
  29.         }
  30.         yield return StartCoroutine(LoadFinished());
  31.     }
复制代码
cjson

    打开cjson的库支持
  1. protected overlay void OpenLibs()
  2.     {
  3.         base.OpenLibs() ;
  4.         OpenCJson();                  
  5.     }
复制代码
    这个开关在LuaClient.cs里面
  1. protected void OpenCJson()
  2.     {
  3.         luaState.LuaGetField(LuaIndexes.LUA_REGISTRYINDEX,“ _LOADED”);
  4.         luaState.OpenLibs(LuaDLL.luaopen_cjson);
  5.         luaState.LuaSetField(-2,“ cjson”);
  6.         luaState.OpenLibs(LuaDLL.luaopen_cjson_safe);
  7.         luaState.LuaSetField(-2,“ cjson.safe”);
  8.     }
复制代码
    修改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对结构支持的操作,具体的函数可以在样例中查看。
  1.         StackTraits<Rect>.Init(PushRect, CheckRectValue, ToRectValue);           //支持压入lua以及从lua栈读取
  2.         TypeTraits<Rect>.Init(CheckRectType);                                    //支持重载函数TypeCheck.CheckTypes
  3.         TypeTraits<Nullable<Rect>>.Init(CheckNullRectType);                      //支持重载函数TypeCheck.CheckTypes
  4.         LuaValueTypeName.names[LuaValueType.Rect] = "Rect";                      //CheckType失败提示的名字
  5.         TypeChecker.LuaValueTypeMap[LuaValueType.Rect] = typeof(Rect);           //用于支持类型匹配检查操作
  6.         ToLua.ToVarMap[LuaValueType.Rect] = ToRectTable;                         //Rect作为object读取
  7.         ToLua.VarPushMap[typeof(Rect)] = (L, o) => { PushRect(L, (Rect)o); };    //Rect作为object压入
复制代码
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-23 08:15 , Processed in 0.090610 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表