加密:
在自定义的PostProcessBundles方法中,对复制到ServerData的bundle进行读取,然后加密后写入覆盖。
//加密 byte[] datas = File.ReadAllBytes(targetPath); File.WriteAllBytes(targetPath, AES.AESEncrypt(datas, KEY));
解密:
在自定义的AssetBundleProvider中的BeginOperation,所有的bundle的加载都先拿到byte数组先,不能直接用AssetBundle.LoadFromFile什么的了。
第三个网络下载的,后面会走第二个缓存bundle的逻辑。
private void BeginOperation() { string path = m_ProvideHandle.Location.InternalId; var url = m_ProvideHandle.ResourceManager.TransformInternalId(m_ProvideHandle.Location); string bundleName = Path.GetFileName(url); // if a path starts with jar:file, it is an android embeded resource. The resource is a local file but cannot be accessed by // FileStream(called in LoadWithDataProc) directly // Need to use webrequest's async call to get the content. if (AssetBundleManager.Instance.buildInData != null && AssetBundleManager.Instance.buildInData.BuildInBundleNames.Contains(bundleName))//本地资源 { string streamPath = UnityEngine.AddressableAssets.Addressables.RuntimePath + "/" + PlatformMappingService.GetPlatformPathSubFolder() + "/" + bundleName; Debug.Log("LoadOne:" + streamPath); var crc = m_Options == null ? 0 : m_Options.Crc; var req = CreateWebRequest(streamPath); req.disposeDownloadHandlerOnDispose = false; m_WebRequestQueueOperation = WebRequestQueue.QueueRequest(req); if (m_WebRequestQueueOperation.IsDone) { m_RequestOperation = m_WebRequestQueueOperation.Result; m_RequestOperation.completed += StreamWebRequestOperationCompleted; } else { m_WebRequestQueueOperation.OnComplete += asyncOp => { m_RequestOperation = asyncOp; m_RequestOperation.completed += StreamWebRequestOperationCompleted; }; } } else if (AssetBundleManager.Instance.IsCache(bundleName)) { string cachePath = Path.Combine(AssetBundleManager.Instance.GetBundleCachePath(), bundleName); Debug.Log("LoadTwo:" + cachePath); var crc = m_Options == null ? 0 : m_Options.Crc; m_RequestOperation = AssetBundle.LoadFromMemoryAsync(AES.AESDecrypt(File.ReadAllBytes(cachePath), AES.GenBundleKey())); m_RequestOperation.completed += LocalRequestOperationCompleted; } else if (ResourceManagerConfig.ShouldPathUseWebRequest(path)) { Debug.Log("DownloadThree:" + url); var req = CreateWebRequest(m_ProvideHandle.Location); req.disposeDownloadHandlerOnDispose = false; m_WebRequestQueueOperation = WebRequestQueue.QueueRequest(req); if (m_WebRequestQueueOperation.IsDone) { m_RequestOperation = m_WebRequestQueueOperation.Result; m_RequestOperation.completed += WebRequestOperationCompleted; } else { m_WebRequestQueueOperation.OnComplete += asyncOp => { m_RequestOperation = asyncOp; m_RequestOperation.completed += WebRequestOperationCompleted; }; } } else { m_RequestOperation = null; m_ProvideHandle.Complete<MyAssetBundleResource>(null, false, new Exception(string.Format("Invalid path in AssetBundleProvider: '{0}'.", path))); } } private void StreamWebRequestOperationCompleted(AsyncOperation op) { UnityWebRequestAsyncOperation remoteReq = op as UnityWebRequestAsyncOperation; var webReq = remoteReq.webRequest; if (!UnityWebRequestUtilities.RequestHasErrors(webReq, out UnityWebRequestResult uwrResult)) { m_downloadHandler = webReq.downloadHandler; CompleteBundleLoad(AssetBundle.LoadFromMemory(AES.AESDecrypt(m_downloadHandler.data, KEY))); } webReq.Dispose(); }
需要准备:
一、将lua-protobuf的pb.h和pb.c替换tolua_runtime根目录的pb.c
二、打开pb.c替换luaop_pb函数
LUALIB_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; }
三、编译
打开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编译环境
ios和mac没试,需要MAC系统,没条件的可以搞虚拟机弄弄,用终端直接执行相关脚本。
四、库的使用
1.在Unity中找到LuaDLL.cs,找到lua_open_pb位置,替换代码
/* ** 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
// 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脚本目录
今天遇到一个让人哭笑不得的问题,就是我在lua中调用Physics.OverlapSphereNonAlloc一直都检测不到范围内的Collider物体,缓冲的数组也有10的大小,不可能说获取不到的。后面想了想,那应该就是生成Wrap有问题了,结果一看
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))] static int OverlapSphereNonAlloc(IntPtr L) { try { int count = LuaDLL.lua_gettop(L); if (count == 3) { UnityEngine.Vector3 arg0 = ToLua.ToVector3(L, 1); float arg1 = (float)LuaDLL.luaL_checknumber(L, 2); UnityEngine.Collider[] arg2 = null; int o = UnityEngine.Physics.OverlapSphereNonAlloc(arg0, arg1, arg2); LuaDLL.lua_pushinteger(L, o); return 1; } else { return LuaDLL.luaL_throw(L, "invalid arguments to method: UnityEngine.Physics.OverlapSphereNonAlloc"); } } catch (Exception e) { return LuaDLL.toluaL_exception(L, e); } }
哈哈哈,它把缓冲数组直接传null了,并不是我传过来的数组,改成这样就好了
UnityEngine.Collider[] arg2 = ToLua.CheckObjectArray<UnityEngine.Collider>(L, 3);
function Exist2(v) return v == 2 end function IsEven(v) return v % 2 == 0 end function NotExist(v) return false end function Compare(a, b) if a > b then return 1 elseif a == b then return 0 else return -1 end end function Test(list, list1) list为List<int>,数据1,2,4 list:Add(123) print('Add result: list[0] is '..list[0]) --123 list:AddRange(list1) print(string.format('AddRange result: list[1] is %d, list[2] is %d', list[1], list[2])) local const = list:AsReadOnly() print('AsReadOnley:'..const[0]) --123 index = const:IndexOf(123) --0 if index == 0 then print('const IndexOf is ok') end local pos = list:BinarySearch(1) --1 print('BinarySearch 1 result is: '..pos) if list:Contains(123) then print('list Contain 123') else error('list Contains result fail') end if list:Exists(Exist2) then print('list exists 2') else error('list exists result fail') end if list:Find(Exist2) then print('list Find is ok') else print('list Find error') end local fa = list:FindAll(IsEven) if fa.Count == 2 then print('FindAll is ok') end --注意推导后的委托声明必须注册, 这里是System.Predicate<int> local index = list:FindIndex(System.Predicate_int(Exist2)) if index == 2 then print('FindIndex is ok') end index = list:FindLastIndex(System.Predicate_int(Exist2)) if index == 2 then print('FindLastIndex is ok') end index = list:IndexOf(123) if index == 0 then print('IndexOf is ok') end index = list:LastIndexOf(123) if index == 0 then print('LastIndexOf is ok') end list:Remove(123) if list[0] ~= 123 then print('Remove is ok') end list:Insert(0, 123) if list[0] == 123 then print('Insert is ok') end list:RemoveAt(0) if list[0] ~= 123 then print('RemoveAt is ok') end list:Insert(0, 123) list:ForEach(function(v) print('foreach: '..v) end) local count = list.Count list:Sort(System.Comparison_int(Compare)) print('--------------sort list over----------------------') for i = 0, count - 1 do print('for:'..list[i]) end list:Clear() print('list Clear not count is '..list.Count) end
function Test() local str = System.String.New('男儿当自强A') local index = str:IndexOfAny('儿自') print('and index is: '..index) --1 local buffer = str:ToCharArray() print('str type is: '..type(str)..' buffer[5] is ' .. buffer[5]) --65 local luastr = tolua.tolstring(buffer) print('lua string is: '..luastr..' type is: '..type(luastr)) --string luastr = tolua.tolstring(str) print('lua string is: '..luastr) --男儿当自强A end
local utf8 = utf8 function Test() local l1 = utf8.len('你好') --计算长度 print('chinese string len is: '..l1) local s = '遍历s字符串' --i为每个字符的开始位置 next为下一个字符的开始位置 for i in utf8.byte_indices(s) do local next = utf8.next(s, i) print(s:sub(i, next and next - 1)) --截取出来就是当前的字符 end local s1 = '天下风云出我辈风云' print('风云 count is: '..utf8.count(s1, '风云')) --计算风云在字符串中的个数 s1 = s1:gsub('风云', '風雲') --替换并返回整个串 print(s1) end
local json = require 'cjson' --用cjson库 function Test(str) local data = json.decode(str) --解析json print(data.glossary.title) s = json.encode(data) --序列化为json print(s) end
local num1 = int64.new('789545665421245') local num = int64.new(201,1) --第一个参数为低32位,第二个参数为高32位 local l,h = int64.tonum2(num1) --转化为低高位的表达方式 local n = int64.new(123,0) --123 local m = int64.new(123,0) --123 if int64.equals(n,123) then --int64和数值对比 print(tostring(n)) end if n==m then --int64和int64对比 print(tostring(m)) end
using UnityEngine; using LuaInterface; public class TestOutArg : MonoBehaviour { string script = @" function TestPick(pos) local camera = UnityEngine.Camera.main local ray = camera:ScreenPointToRay(pos) local _layer = 2 ^ LayerMask.NameToLayer('Default') local flag, hit = UnityEngine.Physics.Raycast(ray, nil, 5000, _layer) if flag then print('pick from lua, point: '..tostring(hit.point)) end end "; LuaState state = null; LuaFunction func = null; void Start () { new LuaResLoader(); state = new LuaState(); LuaBinder.Bind(state); state.Start(); state.DoString(script, "TestOutArg.cs"); func = state.GetFunction("TestPick"); } void Update() { if (Input.GetMouseButtonDown(0)) { func.BeginPCall(); func.Push(Input.mousePosition); func.PCall(); func.EndPCall(); } state.CheckTop(); state.Collect(); } void OnDestroy() { func.Dispose(); func = null; state.Dispose(); state = null; } }
涉及out参数的,直接传nil,它会以返回值的形式返回,注意第一个返回值为状态,第二个开始才是out的返回值
ToLua中有一个LuaFileUtils.cs负责去哪里寻找lua文件,然后读取里面的bytes内容。当出现一些不同的加载方式想自定义,就可以创建一个Loader然后继承LuaFileUtils,重写里面的方法。
using UnityEngine; using System.Collections; using System.IO; using LuaInterface; public class LuaLoader : LuaFileUtils { // Use this for initialization public LuaLoader(bool isZip = false) { instance = this;//外面只要new就好了,单例模式的实例为当前实例了 beZip = isZip; } public void AddBundle(string bundleName) { string url = ""; #if !UNITY_EDITOR url = LuaConst.luaResDir + "/" + bundleName.ToLower(); #else url = LuaConst.luaWinTestResDir + "/" + bundleName.ToLower(); #endif if (File.Exists(url)) { AssetBundle bundle = AssetBundle.LoadFromFile(url); if (bundle != null) { bundleName = bundleName.Replace("lua/", "").Replace(".mp", ""); base.AddSearchBundle(bundleName.ToLower(), bundle); } } } public override byte[] ReadFile(string fileName) { //怎么读取,可以自己重写 return base.ReadFile(fileName); } }
使用方法就是在你的LuaManager中,初始化new一个自定义的LuaLoder就可以了。