Unity+SLua的一些小零碎(1)

解决package.path问题

Unity版本:2019.3.4f1
SLua版本:1.7.0
.NET : 4.7.1

初始化
  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约束。

你可能感兴趣的:(Unity+SLua的一些小零碎(1))