解决package.path问题
Unity版本:2019.3.4f1
SLua版本:1.7.0
.NET : 4.7.1
初始化
- 解压SLua源码,把Assets的Plugins和Slua两个文件夹拷贝到Unity工程的Assets下即可,然后执行Slua->All->Make,即可生成Slua导出的C#文件。
这里会提示checkParams错误,原因是缺少了Vector4[]的checkParams函数,又无法通过模板函数转换,所以只需要在 LuaObject_overload.cs 里拷贝以下Vector2[]的checkParams代码,改成了Vector4[]就好了。
package.path问题
1.SLua默认是从Resources加载lua文件的,而且lua文件后缀必须是txt,这样约束太大。作者的回答
2.作者提供了LoaderDelegate,以方便定制lua加载策略。
方案:
1.指定初始化的package.path,指向main.lua目录即可。
2.定义一个FileUtils工具类,主要负责:1.处理文件的读取 2.判断文件是否存在
3.定义一个LoaderDelegate,赋值给LuaSvr.mainState.loaderDelegate
步骤1
在LuaState.cs init()中添加,至于getSearchPath就因工程目录设计而异了,反正指向main.lua就好了
LuaDLL.lua_getglobal(L, "package");
LuaDLL.lua_pushstring(L, getSearchPath());
LuaDLL.lua_setfield(L, -2, "path");
LuaDLL.lua_pop(L, 1);
步骤2
FilUtils:(主要处理Win、安卓和iOS,安卓是利用AndroidJNI(未在真机验证)
参考: unity3d 在安卓平台通过Native接口直接读取apk中assets目录下的文件
]
using UnityEngine;
using System.IO;
using System;
using SLua;
public class FileUtils
{
private static FileUtils Instance;
#if UNITY_ANDROID
AndroidJavaObject assetManager
#endif
private FileUtils()
{
#if UNITY_ANDROID
var activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic("currentActivity");
//从Activity取得AssetManager实例
assetManager = activity.Call("getAssets");
#endif
}
public static FileUtils GetInstance()
{
if (Instance == null)
{
Instance = new FileUtils();
}
return Instance;
}
public bool isFileExist(string filePath)
{
#if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_IPHONE
return File.Exists(filePath);
#elif UNITY_ANDROID
var stream = assetManager.Call("open", filePath);
if(stream)
{
stream.Call("close");
stream.Dispose();
return true;
}
return false;
#endif
}
public bool getContents(string filePath, out byte[] bytes, out int len)
{
#if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_IPHONE
FileStream stream = new FileStream(filePath, FileMode.Open);
bool ret = false;
bytes = null;
len = 0;
if (null != stream)
{
len = (int)stream.Length;
bytes = new byte[len];
int readLend = stream.Read(bytes, 0, len);
stream.Flush();
stream.Close();
ret = readLend == len;
}
return ret;
#elif UNITY_ANDROID
//打开文件流
var stream = assetManager.Call("open", filePath);
if(stream == null)
return fasle;
//获取文件长度
var availableBytes = stream.Call("available");
//取得InputStream.read的MethodID
var clsPtr = AndroidJNI.FindClass("java.io.InputStream");
var METHOD_read = AndroidJNIHelper.GetMethodID(clsPtr, "read", "([B)I");
//申请一个Java ByteArray对象句柄
var byteArray = AndroidJNI.NewByteArray(availableBytes);
//调用方法
int readCount = AndroidJNI.CallIntMethod(stream.GetRawObject(), METHOD_read, new[] { new jvalue() { l = byteArray } });
//从Java ByteArray中得到C# byte数组
var bytes = AndroidJNI.FromByteArray(byteArray);
//删除Java ByteArray对象句柄
AndroidJNI.DeleteLocalRef(byteArray);
//关闭文件流
stream.Call("close");
stream.Dispose();
//返回结果
return bytes;
#endif
}
public bool getLuaFileFullPath(IntPtr L, string fileName, out string fullPath)
{
LuaDLL.lua_getglobal(L, "package");
LuaDLL.lua_getfield(L, -1, "path");
string searchpath = LuaDLL.lua_tostring(L, -1);
LuaDLL.lua_pop(L, 2);
int begin = 0;
int next = 0;
bool found = false;
fullPath = string.Empty;
do
{
next = searchpath.IndexOf(";", begin);
if (next == -1)
next = searchpath.Length;
string prefix = searchpath.Substring(begin, next - begin);
if (!string.IsNullOrEmpty(prefix))
{
fullPath = prefix.Replace("?", fileName);
if (isFileExist(fullPath))
{
found = true;
break;
}
}
begin = next + 1;
} while (begin < searchpath.Length);
return found;
}
}
步骤3
在初始化脚本里,设置一下Loader
public class Init : MonoBehaviour
{
LuaSvr l;
// Use this for initialization
void Start()
{
l = new LuaSvr();
setLoader(LuaSvr.mainState);
l.init(null, () =>
{
l.start("main");
});
}
void setLoader(LuaState state)
{
state.loaderDelegate = (string fn, ref string absoluteFn) =>
{
string strFullPath;
bool found = FileUtils.GetInstance().getLuaFileFullPath(state.L, fn, out strFullPath);
if(found)
{
byte[] bytes = null;
int len = 0;
if (FileUtils.GetInstance().getContents(strFullPath, out bytes, out len))
return bytes;
}
return null;
};
}
}
总结:
至此,就可以往packaget.path里添加多个搜索路径,而不受Resource约束。