- A+
在原来写Maniac的时候,为了模拟服务端和客户端的交换,写了个临时的NetManager,模拟发送和接收协议数组,也是是延迟一下触发逻辑,没有经过任何的数据协议处理。所以我就想写个,自个客户端起个socket服务器然后和客户端进行交互了。原来的触发逻辑,哈哈哈:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function M:SendToServer(net) net.uid = self.uid InvokeDelay(0.025,self.DelaySendToServer,self,net) end function M:DelaySendToServer(net) if self.serverHandler then self.serverHandler(net) end end function M:SendToClient(net) InvokeDelay(0.025,self.DelaySendToClient,self,net) end function M:DelaySendToClient(net) if self.clientHandler then self.clientHandler(net) end end |
ToLua引入proto3
ToLua中更新protobuf库使用proto3,原来的库用的是proto2。
一、准备工作
二、将lua-protobuf的pb.h和pb.c替换tolua_runtime根目录的pb.c
三、打开pb.c替换luaop_pb函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
UALIB_API int luaopen_pb(lua_State *L) { luaL_Reg libs[] = { { "pack", Lbuf_pack }, { "unpack", Lslice_unpack }, #define ENTRY(name) { #name, Lpb_##name } ENTRY(clear), ENTRY(load), ENTRY(loadfile), ENTRY(encode), ENTRY(decode), ENTRY(types), ENTRY(fields), ENTRY(type), ENTRY(field), ENTRY(typefmt), ENTRY(enum), ENTRY(defaults), ENTRY(hook), ENTRY(tohex), ENTRY(result), ENTRY(option), ENTRY(state), #undef ENTRY { NULL, NULL } }; luaL_Reg meta[] = { { "__gc", Lpb_delete }, { "setdefault", Lpb_state }, { NULL, NULL } }; if (luaL_newmetatable(L, PB_STATE)) { luaL_setfuncs(L, meta, 0); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); } #if LUA_VERSION_NUM < 502 luaL_register(L, "pb", libs); #else luaL_newlib(L, libs); #endif return 1; } |
四、编译tolua库
- 打开msys2 32编译环境 cd到tolua_runtime位置
- ./build_win32.sh 编译win的tolua.dll,目录在Plugins/x86下
- 打开编辑android相关的(build_arm.sh、build_x86.sh、link_arm64.bat),把NDK路径改为本电脑路径,我用的版本是android-ndk-r10e-windows-x86_64,然后在msys2 的32位下执行 ./build_arm.sh,执行./build_x86.sh。编译后的tolua.so在Plugins/Android下
- arm64的参考上面步骤,使用msys2 64编译环境
- os和mac没试,需要MAC系统,没条件的可以搞虚拟机弄弄,用终端直接执行相关脚本。
五、库的使用
1.在Unity中找到LuaDLL.cs,找到lua_open_pb位置,替换代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* ** third party library */ [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] public static extern int luaopen_pb(IntPtr L); [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] public static extern int luaopen_pb_io(IntPtr L); [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] public static extern int luaopen_pb_conv(IntPtr L); [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] public static extern int luaopen_pb_buffer(IntPtr L); [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] public static extern int luaopen_pb_slice(IntPtr L); |
2.在你创建虚拟机的地方添加打开Lib
1 2 3 4 5 |
// m_LuaState 为 LuaState 对象 m_LuaState.OpenLibs(LuaDLL.luaopen_pb_io); m_LuaState.OpenLibs(LuaDLL.luaopen_pb_conv); m_LuaState.OpenLibs(LuaDLL.luaopen_pb_buffer); m_LuaState.OpenLibs(LuaDLL.luaopen_pb_slice); |
3.复制lua-protobuf的protoc.lua和serpent.lua到你的lua脚本目录
ToLua更换为Xlua
ToLua中用的luajit用的lua版本是5.1的,有些新的lua特性和方法都无法使用。当时想的是升级一下lua的版本,后面想到有很多人原来用ToLua,后面为了Xlua的Hotfix又加入了Xlua,混合使用。而Xlua的build库里早就有lua5.4了,更新非常积极,而我的项目目前的代码也不算太多,所以就有了换成Xlua的想法和行动。
一、创建虚拟机
Tolua是LuaState,Xlua是LuaEnv;Tolua有DoFile,而Xlua需要使用DoString去require先;Tolua可以通过LuaState使用索引的方式获取全局方法,而Xlua的全局在Global里面通过Get的方式获取;Tolua通过OpenLib添加库,Xlua通过AddBuildin添加库;ToLua使用LuaLoop.cs去驱动lua层的Update、FixUpdate,Xlua可以沿用这种方式去驱动;Tolua加载lua文件通过在new LuaResLoader里面定义逻辑,Xlua通过AddLoader传一个方法定义逻辑返回byte数组。
1.ToLua启动脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
using UnityEngine; using LuaInterface; using System; using System.IO; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; using System.Collections.Generic; using System.Linq; using Manager; using MiniJSON; using UnityEngine.SceneManagement; public class Main : MonoBehaviour { public LuaState luaState = null; public static Main Instance = null; private LuaFunction onEventCall = null; private LuaLooper loop = null; private string tips = ""; private void Awake() { Main.Instance = this; Screen.sleepTimeout = SleepTimeout.NeverSleep; Init(); } private async void Init() { AssetBundleManager.GetInstance().Init(); await Addressables.InitializeAsync().Task; AddressableManager.GetInstance().LoadObjectAsync("Common/Configs/Config.txt", true, LoadConfigComplete); } private void LoadConfigComplete(object asset) { var txtAsset = asset as TextAsset; var dict = Json.Deserialize(txtAsset.text) as Dictionary<string, object>; List<object> preloadArray = dict["CommonLuaPreLoad"] as List<object>; List<string> preLoadStrArray = new List<string>(16); for (int i = 0; i < preloadArray.Count; i++) { preLoadStrArray.Add(preloadArray[i] as string); } AddressableManager.GetInstance().PreLoadFrameLua(preLoadStrArray, LoadFrameLuaComplete); } private void LoadFrameLuaComplete(object count) { new LuaResLoader(); InitLuaEvn(); StartUpLua(); StartUpUnity2LuaCallback(); } void StartUpLua() { luaState.DoFile("Frame/Main"); LuaFunction init = luaState["Init"] as LuaFunction; init.BeginPCall(); init.PCall(); init.EndPCall(); init = null; } void StartUpUnity2LuaCallback() { Unity2LuaCallback.Instance.Init(); } void OnApplicationQuit() { onEventCall.Dispose(); luaState.Dispose(); luaState = null; if (loop != null) { loop.Destroy(); loop = null; } } private void InitLuaEvn() { luaState = new LuaState(); luaState.Start(); luaState.LogGC = false; DelegateFactory.Init(); LuaBinder.Bind(luaState); loop = gameObject.AddComponent<LuaLooper>(); loop.luaState = luaState; OpenLibs(); OpenCJson(); } protected void OpenLibs() { luaState.OpenLibs(LuaDLL.luaopen_pb); luaState.OpenLibs(LuaDLL.luaopen_pb_io); luaState.OpenLibs(LuaDLL.luaopen_pb_conv); luaState.OpenLibs(LuaDLL.luaopen_pb_buffer); luaState.OpenLibs(LuaDLL.luaopen_pb_slice); luaState.OpenLibs(LuaDLL.luaopen_struct); luaState.OpenLibs(LuaDLL.luaopen_lpeg); #if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX luaState.OpenLibs(LuaDLL.luaopen_bit); #endif if (LuaConst.openLuaSocket) { OpenLuaSocket(); } } protected void OpenLuaSocket() { LuaConst.openLuaSocket = true; luaState.BeginPreLoad(); luaState.RegFunction("socket.core", LuaOpen_Socket_Core); luaState.RegFunction("mime.core", LuaOpen_Mime_Core); luaState.EndPreLoad(); } 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"); } [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))] static int LuaOpen_Socket_Core(IntPtr L) { return LuaDLL.luaopen_socket_core(L); } [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))] static int LuaOpen_Mime_Core(IntPtr L) { return LuaDLL.luaopen_mime_core(L); } public void RegistEventCall(LuaFunction func) { this.onEventCall = func; } public void InvokeEventCall(GameObject go,string type,object o) { if (this.onEventCall != null) { this.onEventCall.BeginPCall(); this.onEventCall.Push(go); this.onEventCall.Push(type); this.onEventCall.Push(o); this.onEventCall.PCall(); this.onEventCall.EndPCall(); } } } |
2.Xlua启动脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
using UnityEngine; using System; using System.IO; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; using System.Collections.Generic; using System.Linq; using System.Text; using Manager; using MiniJSON; using UnityEngine.SceneManagement; using XLua; public class Main : MonoBehaviour { public LuaEnv luaState = null; public static Main Instance = null; private LuaFunction onEventCall = null; private XLuaMono loop = null; private string tips = ""; private void Awake() { Main.Instance = this; Screen.sleepTimeout = SleepTimeout.NeverSleep; Init(); } private async void Init() { AssetBundleManager.GetInstance().Init(); await Addressables.InitializeAsync().Task; AddressableManager.GetInstance().LoadObjectAsync("Common/Configs/Config.txt", true, LoadConfigComplete); } private void LoadConfigComplete(object asset) { var txtAsset = asset as TextAsset; var dict = Json.Deserialize(txtAsset.text) as Dictionary<string, object>; List<object> preloadArray = dict["CommonLuaPreLoad"] as List<object>; List<string> preLoadStrArray = new List<string>(16); for (int i = 0; i < preloadArray.Count; i++) { preLoadStrArray.Add(preloadArray[i] as string); } AddressableManager.GetInstance().PreLoadFrameLua(preLoadStrArray, LoadFrameLuaComplete); } private void LoadFrameLuaComplete(object count) { RestartLuaEnv(); } public void RestartLuaEnv() { Dispose(); InitLuaEvn(); StartUpLua(); StartUpUnity2LuaCallback(); } void StartUpLua() { luaState.DoString(string.Format("require('{0}')", "Frame/Main")); LuaFunction init = luaState.Global.Get<LuaFunction>("Init"); init.Call(); init = null; loop = gameObject.AddComponent<XLuaMono>(); loop.OnInit(luaState); } void StartUpUnity2LuaCallback() { Unity2LuaCallback.Instance.Init(); } public void Dispose() { if (luaState != null) { luaState.Dispose(); luaState = null; } if (loop != null) { loop.OnDispose(); loop = null; } } private void InitLuaEvn() { luaState = new LuaEnv(); luaState.AddLoader(CustomLoader); luaState.AddBuildin("cjson", XLua.LuaDLL.Lua.LoadRapidJson); luaState.AddBuildin("pb", XLua.LuaDLL.Lua.LoadLuaProfobuf); } public static byte[] CustomLoader(ref string filepath) { StringBuilder scriptPath = new StringBuilder(); scriptPath.Append(filepath.Replace(".", "/")); scriptPath.Append(".lua"); #if UNITY_EDITOR var scriptDir = Path.Combine(Application.dataPath, "..", "Src"); var luaPath = Path.Combine(scriptDir, scriptPath.ToString()); return File.ReadAllBytes(luaPath); #endif var txtAddress = scriptPath.Append(".bytes").ToString(); var asset = AddressableManager.GetInstance().GetLuaScript(txtAddress); if (asset != null) { return asset; } return null; } public void RegistEventCall(LuaFunction func) { this.onEventCall = func; } public void InvokeEventCall(GameObject go,string type,object o) { if (this.onEventCall != null) { onEventCall.Call(go, type, o); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
using System; using System.Collections.Generic; using System.Diagnostics; using UnityEngine; using XLua; public class XLuaMono : MonoBehaviour { Action<float, float> monoUe = null; Action monoLateUe = null; Action<float> monoFixedUe = null; public void OnInit(LuaEnv luaEnv) { Restart(luaEnv); } public void Restart(LuaEnv luaEnv) { monoUe = luaEnv.Global.Get<Action<float, float>>("Update"); monoLateUe = luaEnv.Global.Get<Action>("LateUpdate"); monoFixedUe = luaEnv.Global.Get<Action<float>>("FixedUpdate"); } void Update() { if (monoUe != null) { try { monoUe(Time.deltaTime, Time.unscaledDeltaTime); } catch (Exception ex) { Logger.LogError("monoUe err : " + ex.Message + "\n" + ex.StackTrace); } } } void LateUpdate() { if (monoLateUe != null) { try { monoLateUe(); } catch (Exception ex) { Logger.LogError("monoLateUe err : " + ex.Message + "\n" + ex.StackTrace); } } } void FixedUpdate() { if (monoFixedUe != null) { try { monoFixedUe(Time.fixedDeltaTime); } catch (Exception ex) { Logger.LogError("luaFixedUpdate err : " + ex.Message + "\n" + ex.StackTrace); } } } public void OnDispose() { monoUe = null; monoLateUe = null; monoFixedUe = null; } void OnDestroy() { OnDispose(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
namespace XLua.LuaDLL { using System.Runtime.InteropServices; public partial class Lua { [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] public static extern int luaopen_rapidjson(System.IntPtr L); [MonoPInvokeCallback(typeof(LuaDLL.lua_CSFunction))] public static int LoadRapidJson(System.IntPtr L) { return luaopen_rapidjson(L); } [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] public static extern int luaopen_pb(System.IntPtr L); [MonoPInvokeCallback(typeof(LuaDLL.lua_CSFunction))] public static int LoadLuaProfobuf(System.IntPtr L) { return luaopen_pb(L); } } } |
二、Wrap生成
Xlua中通过特性[LuaCallCSharp]需要导出的内容,然后反射获取需要导出的类型,新建一个静态类放在Editor中,打包后是不需要再用到额,声明一个静态列表,把ToLua中需要导出的类型都添加到里面。这里只列了一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
using System.Collections.Generic; using System; using UnityEngine; using XLua; using System.Reflection; using System.IO; using System.Collections; using Manager; using UnityEngine.Networking; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.ResourceManagement.ResourceProviders; public static class CustomGenConfig { //lua中要使用到C#库的配置,比如C#标准库,或者Unity API,第三方库等。 [LuaCallCSharp] public static List<Type> LuaCallCSharp = new List<Type>() { //3D typeof(Physics), typeof(Collider), //2D typeof(Rigidbody2D), typeof(Physics2D), typeof(Collider2D), typeof(Ray2D), //自定义 typeof(AddressableManager), typeof(Addressable.OperationData), typeof(Main), typeof(EventTriggerListener), typeof(UnityExtends), typeof(OnTrigger2DComponent), typeof(AnimationEventComponent), typeof(SdkManager), typeof(MusicBridge), }; //C#静态调用Lua的配置(包括事件的原型),仅可以配delegate,interface [CSharpCallLua] public static List<Type> CSharpCallLua = new List<Type>() { // unity typeof(Action), }; //黑名单 [BlackList] public static List<List<string>> BlackList = new List<List<string>>() { #if !UNITY_WEBPLAYER new List<string>(){"UnityEngine.Application", "ExternalEval"}, #endif }; #if UNITY_2018_1_OR_NEWER [BlackList] public static Func<MemberInfo, bool> MethodFilter = (memberInfo) => { if (memberInfo.DeclaringType.IsGenericType && memberInfo.DeclaringType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) { if (memberInfo.MemberType == MemberTypes.Constructor) { ConstructorInfo constructorInfo = memberInfo as ConstructorInfo; var parameterInfos = constructorInfo.GetParameters(); if (parameterInfos.Length > 0) { if (typeof(System.Collections.IEnumerable).IsAssignableFrom(parameterInfos[0].ParameterType)) { return true; } } } else if (memberInfo.MemberType == MemberTypes.Method) { var methodInfo = memberInfo as MethodInfo; if (methodInfo.Name == "TryAdd" || methodInfo.Name == "Remove" && methodInfo.GetParameters().Length == 2) { return true; } } } return false; }; #endif //================================================================================================================== //打一个LuaCallCSharp标签的方法很方便,但在il2cpp下会增加不少的代码量,不建议使用 //统一在下面通过静态列表方式添加管理 //=================================================================================================================== [LuaCallCSharp] public static List<Type> MyLuaCallCSharp = new List<Type>() { //SuperSuperScrollView typeof(SuperScrollView.LoopListViewItem2), typeof(SuperScrollView.LoopListView2), typeof(SuperScrollView.LoopGridView), typeof(SuperScrollView.LoopGridViewItem), typeof(SuperScrollView.LoopStaggeredGridView), typeof(SuperScrollView.LoopStaggeredGridViewItem), }; /// <summary> /// xlua 不导出的类 /// </summary> public static List<string> NotExportClass = new List<string>() { }; } |
最后在lua脚本中,把使用到Cs脚本类型的前面都加上CS.,原来ToLua直接都是命名空间加类名调用额,Xlua的调用方式不一样,前面直接加CS.就行。例如CS.UnityEngine.GameObject。
Xlua引入lua-protobuf库
一、准备工作
二、配置
- 把lua-protobuf放到xlua的build文件夹里面
- 修改CMakeLists.txt,添加
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#begin lua-profobuf set (LPB_SRC lua-protobuf/pb.c ) set_property( SOURCE ${LPB_SRC} APPEND PROPERTY COMPILE_DEFINITIONS LUA_LIB ) list(APPEND THIRDPART_INC lua-protobuf) set (THIRDPART_SRC ${THIRDPART_SRC} ${LPB_SRC}) #end lua-protobuf |
三、编译xlua库
- Window
双击make_win_lua54.bat运行,一次成功,没有遇到任何问题,首先我电脑装的是vs2017,该有的库都有了。如果报错,可以根据报错补充环境。dll文件在:
2. Android
- 安装git,我需要下载我的工程文件,sudo apt install git
- 安装cmake3.6.0或以上版本 百度安装方法,我直接执行了sudo apt install cmake是5.1版本的
- 下载NDK15版本,配置环境变量,在/etc/profile 最后加入(注意权限问题)
1 2 |
export ANDROID_NDK=/home/*** ndk路径 export PATH=$ANDROID_NDK:$PATH |
- 下载工程,在xlua的build目录下,执行./make_android_lua54.sh
一般不会出现什么问题,我是cmake版本不对,换版本折腾了一下,也只是权限问题多点。Windows编译反正我是没成功,不建议Windows搞。编译后的so文件在:
3.其他平台,没试
好了,我可以去写我的网络模块了。