加密:
在自定义的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就可以了。