lua5.1 - function env

注意:只在lua 5.1才支持,后面的lua版本做了改动不再兼容

 

myEnv.lua

local myEnv = {}

myEnv.a = 1
myEnv.b = "one"
myEnv.log = print

return myEnv

 

Test.lua

复制代码
local myEnv= require("myEnv")

setfenv(1, myEnv)
--调用上面的函数后, print将没法使用因为那是在全局env下,
--现在切换为自定义的env了, 只能访问到自定env提供的值
--print("123")
--_G.print("123")

function Test1()
    log(a)
    log(b)
end

Test1()
复制代码

 

关于setfenv(func or number,tbl)

1) 第1个参数为数字时,1表示修改当前作用域的env,2表示修改上层作用域的,以此类推。特殊情况是0,表示修改当前运行线程的。

2) 第2个参数为新env的table

 

 

一些用法

1) 参考xlua的LuaBehaviour:向C#脚本关联的lua脚本注入c#对象

复制代码
[System.Serializable]
public class BindObject
{
    public string Name;
    public UnityEngine.Object Obj;
}


public class MyLuaBehaviour : MonoBehaviour
{
    [SerializeField]
    internal BindObject[] m_BindObjects;
    [SerializeField]
    internal string m_ScriptPath;

    private Dictionary<string, UnityEngine.Object> m_BindObjDict;

    private LuaTable m_MonoTable;

    private Action m_LuaOnEnable;
    private Action m_LuaStart;
    private Action m_LuaOnDisable;
    private Action m_LuaOnDestroy;
    private Action m_LuaUpdate;
    private Action m_LuaLateUpdate;

    void Awake()
    {
        OnAwake();
    }

    protected virtual void OnAwake()
    {
        var luaEnv = LuaManager.Instance.LuaEnv;
        if (null == luaEnv) return;

        m_MonoTable = luaEnv.NewTable();

        var mt = luaEnv.NewTable();
        mt.Set("__index", luaEnv.Global); //mt上找不到的, 去global找
        m_MonoTable.SetMetaTable(mt);
        mt.Dispose();

        m_MonoTable.Set("self", this);

        //注入lua Table
        foreach (var item in m_BindObjects)
        {
            if (string.IsNullOrEmpty(item.Name) || null == item.Obj) continue;
            m_MonoTable.Set(item.Name, item.Obj);
        }

        if (string.IsNullOrEmpty(m_ScriptPath)) return;

        var txtAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(m_ScriptPath);
        if (null == txtAsset || string.IsNullOrEmpty(txtAsset.text)) return;

        luaEnv.DoString(txtAsset.text, m_ScriptPath, m_MonoTable); //脚本中不存在的字段, 会先在env对象上找, 没找到再去_Global对象上找

        Action luaAwake = null;
        m_MonoTable.Get("Awake", out luaAwake);
        m_MonoTable.Get("OnEnable", out m_LuaOnEnable);
        m_MonoTable.Get("Start", out m_LuaStart);
        m_MonoTable.Get("OnDisable", out m_LuaOnDisable);
        m_MonoTable.Get("OnDestroy", out m_LuaOnDestroy);
        m_MonoTable.Get("Update", out m_LuaUpdate);
        m_MonoTable.Get("LateUpdate", out m_LuaLateUpdate);

        SafeInvoke(luaAwake);
    }

    void OnEnable()
    {
        SafeInvoke(m_LuaOnEnable);
    }

    void Start()
    {
        SafeInvoke(m_LuaStart);
    }

    void OnDisable()
    {
        SafeInvoke(m_LuaOnDisable);
    }

    void OnDestroy()
    {
        SafeInvoke(m_LuaOnDestroy);
        if (null != m_MonoTable)
            m_MonoTable.Dispose();

        m_MonoTable = null;
        m_LuaOnDestroy = null;
        m_LuaOnDisable = null;
        m_LuaStart = null;
        m_LuaOnEnable = null;
    }

    public void OnUpdate()
    {
        SafeInvoke(m_LuaUpdate);
    }

    public void OnLateUpdate()
    {
        SafeInvoke(m_LuaLateUpdate);
    }

    public UnityEngine.Object GetObject(string name)
    {
        if (null == m_BindObjDict)
        {
            m_BindObjDict = new Dictionary<string, UnityEngine.Object>();
            for (var i = 0; i< m_BindObjects.Length; ++i)
            {
                var item = m_BindObjects[i];
                if (null == item.Obj || string.IsNullOrEmpty(item.Name)) continue;

                m_BindObjDict.Add(item.Name, item.Obj);
            }
        }

        m_BindObjDict.TryGetValue(name, out var obj);
        return obj;
    }

    private void SafeInvoke(Action func)
    {
        if (null == func) return;
        try
        {
            func();
        }
        catch (Exception ex)
        {
            Debug.LogError($"{ex.GetType().Name}: {ex.Message}");
        }
    }

}
复制代码

 

posted @   yanghui01  阅读(33)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
历史上的今天:
2021-03-03 错误处理 pcall, xpcall
点击右上角即可分享
微信分享提示