链接里包含:lua-protobuf、lua-rapidjson、luasocket、luajit等

本文不介绍luasocket、FFI等库的使用
在你项目初始化lua虚拟机的地方引入下方代码
- _luaEnv = new LuaEnv();
- _luaEnv.AddLoader(CustomLoaderMethod);
- _luaEnv.AddBuildin("rapidjson", XLua.LuaDLL.Lua.LoadRapidJson);
- _luaEnv.AddBuildin("lpeg", XLua.LuaDLL.Lua.LoadLpeg);
- _luaEnv.AddBuildin("pb", XLua.LuaDLL.Lua.LoadLuaProfobuf);
第三方库的引用方式就上面几句代码
如果你不想自己写Demo,可以看一下官方自己写的Unity Demo
https://github.com/chexiongsheng/build_xlua_with_libs/tree/master/LibsTestProj
Xlua官网的Unity工程,使用第三方库无法加载!!!
用 GitHub chengxiongsheng的Demo可以加载,我怀疑是官网Xlua Unity工程的Plugins里的dll没有生成带有第三方库的版本。
build_xlua_with_libs/build这个源码可以使用cmake自己生成库,然后扔到Unity中使用
Json和ProtoBuffer是我们开发中常见的工具,还有一个不是很常见的lpeg,找了几篇文章,大家自行跳转
https://www.jianshu.com/p/e8e1c5abfdbb
https://www.jianshu.com/p/e8e1c5abfdbbLPEG库简介_suzuiyue的博客-CSDN博客_lpegLPEG库简介LPEG是一个供lua使用的基于 Parsing Expression Grammars 的模式匹配库,这篇文章只是讲其如何使用,并不涉及底层如何实现。LPEG 的函数主要分为三类,第一类是创建Pattern的构造函数,第二类是 Capture 函数, 第三类则是 match 等函数。 Capture 就是指一个Pattern,当前匹配时会产生某些捕获的值。Match 等函数lpeg.https://blog.csdn.net/suzuiyue/article/details/52905372
在lua当中如何使用这三个库呢,下面挨个介绍
1:Json的使用
引用rapidjson有几种方式
- --调用方式1,声明一个全局变量RapidJson,代码执行后,可以在其他.lua文件中直接调用RapidJson 而不需要再次require('rapidjson')
- RapidJson = require('rapidjson')
-
- --调用方式2,脚本内局部使用
- local rapidJson = require('rapidjson')
-
- --调用方式3,方法内局部使用
- function XXX()
- local rapidJson = require('rapidjson')
- end
rapidjson具体使用,在调用encode和decode方法前,要先require('rapidjson')
- --反序列化
- local t = rapidjson.decode('{"a":123}')
- print(t.a)
- t.a = 456
- --序列化
- local s = rapidjson.encode(t)
- print('json', s)
2:ProtoBuf的使用
xLua官方源码:
https://github.com/Tencent/xLua
lua-protobuf源码:
https://github.com/starwing/lua-protobuf
protoc.lua在 https://github.com/starwing/lua-protobuf 源码里
提示:Xlua的PB库支持proto2和proto3,需要在协议里标明是2还是3
第一步:准备proto协议协议文件。
使用pb的前提肯定得让lua层的pb加载协议,协议才是序列化、反序列化的前提。
我准备了一个战斗协议,命名为Fight.proto,里面还引用了NetStruct_Fight.proto文件
- syntax="proto2";
- import "NetStruct_Fight.proto";
-
- message CSEnterBattle
- {
- optional int32 battleSid = 1; // 战役配置id
- optional int32 isFixedArray = 2; // 是否固定阵容0不是 1是
- }
-
- //[返回][游戏服]进入战斗结果
- message SCEnterBattle
- {
- optional int64 battleId = 1; //服务器战斗序号
- repeated CampData camps = 2; // 战斗阵营数据 (仅站位和card_sid)
- }
第一种加载proto方式:
1、先通过ResourceManager框架加载协议文本文件,
2、然后获取文本的string,
3、调用 assert(pcNew:load(A,B)),其中,A变量是string,B变量是文件名带扩展名
- local pcNew = nil
-
- function StartLoadProto()
- --protoc是一个lua文件,一般是lua库里带着的此处需要引用一下
- protoc = require "Framework/protoc"
- pcNew= protoc.new()
-
- --由于我的Fight.proto里引用了另一个proto,因此先加载引用
- LoadProto("NetStruct_Fight")
- --加载完引用后,再加载proto才不会报错
- LoadProto("Fight")
- end
-
- function LoadProto(fileName)
- --C#资源加载器
- local AssetsData = CS.MoAssetText()
- AssetsData:Load("Battle/Proto/"..fileName..".txt")
- --不管你怎么加载,一定是从Unity里把协议文本取出来
- local protoString = AssetsData:GetText()
- --这一句是核心语句,协议文本加载入pb库,现在pb就知道该如何解析bytes数据啦
- assert(pcNew:load(protoString,fileName..".proto"))
-
- end
-
CS.MoAssetText()是我们项目的文本文件加载,你可以根据自己项目选择如何加载,反正最后一定要拿到文本文件的string。
下面开始介绍第二种加载proto方式
- assert(
- ProtocLib:load
- [[
- syntax = "proto3";
- message CSEnterBattle
- {
- int32 battleSid = 1; // 战役配置id
- int32 isFixedArray = 2; // 是否固定阵容0不是 1是
- }
- //[返回][游戏服]进入战斗结果
- message SCEnterBattle
- {
- int64 battleId = 1; //服务器战斗序号
- CampData camps = 2; // 战斗阵营数据
- }
- //阵营数据
- message CampData
- {
- int32 id = 1; //阵营id
- int32 UnitId = 2; //阵营类型
- }
- ]]
- )
仔细看上面代码你会发现,其实就是把proto协议里的内容全部都写到一个lua脚本里去,这个lua脚本包括了所有引用和非引用的proto数据结构,我这里的文件叫protoDefine.lua.txt文件,我们可以写一个批处理工具,把协议全都按行写入到一个文件中。如果你的协议非常多,那么会生成一个几千行甚至几万行的lua文件。项目启动的时候,在合适的位置调用 require "Net/ProtoDefine"加载这个脚本即可把协议加载到库。
上面介绍了两种加载proto协议的方式
加载完proto协议,我们当然要使用它呀,也就是序列化和反序列化数据
- function UsePB()
- --第一步,加载bytes,请注意,EnterBattleMsg是我本地已经序列化出来的二进制数据文件测试用
- --将来肯定是从服务器获取二进制数据
- local bytes = LoadBytes("EnterBattleMsg")
-
- --反序列化,使用proto库里的SCEnterBattle结构体序列化该bytes数据
- local SCEnterBattleTab = assert(pb.decode('SCEnterBattle', bytes))
-
- --请注意,反序列化后得到SCEnterBattleTab,它是个table
-
- --获取数据如下
- print("战役Id: ".. SCEnterBattleTab.battleId)
-
- --序列化语句
- local bytes = pb.encode('SCEnterBattle', SCEnterBattleTab)
-
- --此时我们又得到了一个最初的bytes二进制数据
- print(pb.tohex(bytes))--打印数据
- end
-
- function LoadBytes(fileName)
- --C#资源加载器
- local AssetsData = CS.MoAssetText()
- --同步加载文件
- AssetsData:Load("Battle/Proto/"..fileName..".bytes")
- --不管你怎么加载,一定是从Unity里把二进制数据读出来
- return AssetsData:GetBytes()
-
- end
-
3:lpeg的使用
lpeg的功能非常多,建议直接去看上面分享的链接,详细看一下使用
- local lpeg = require "lpeg"
-
- local match = lpeg.match
- local P = lpeg.P
-
- -- value是string的情况
- local ps = P'ab'
- print(match(ps, "a")) ---> nil
- print(match(ps, "abcd")) ---> 3 注:只匹配"ab"