|
(下面的代码块中是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
- protected overlay void OpenLibs()
- {
- base.OpenLibs() ;
- OpenCJson();
- }
复制代码- 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 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
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压入
复制代码 |
|