1

私はluaをc++と統合しようとしている小さなプロジェクトに取り組んでいます。しかし、私の問題は次のとおりです。

複数のluaスクリプトがあります。それらをs1.luas2.luaおよびs3.luaと呼びましょう。これらのそれぞれには、setVars()およびexecuteResults()という関数があります。

これで、LuaL_dofileを介して、setVars()やexecuteResults()を使用した直後にluaファイルを呼び出すことができます。ただし、ここでの問題は、s2.luaをロードした後、s1.luaの関数を呼び出すことができなくなることです。これは、関数へのアクセスを回復するためにs1.luaでLuaL_dofileをやり直す必要があることを意味します。そうすることで、s2.luaの関数にアクセスできなくなります。

すべてのluaファイルを連続してロードし、その後、それらの関数を自由に呼び出し始める方法はありますか?s1-> executeResults()s5-> executeResults()s3-> setVars()などのようなもの。

私は現在、boost :: filesystemを使用してフォルダー内のすべてのluaファイルを検出するシステムをすでに導入しています。次に、これらのファイル名をベクターに保存し、ベクターを繰り返し処理して、各luaファイルを連続してロードします。

ベクトルをluaファイル名で埋める前に、プラグインのロード関数は現時点では次のようになっています。

void Lua_plugin::load_Plugins(){
 std::vector<std::string>::const_iterator it;
 for (it=Lua_PluginList.begin(); it!=Lua_PluginList.end(); it++){
  std::cout<<"File loading: " << *it << std::endl;
  std::string filename =  *it;
  std::string filepath = scriptdir+filename;
  if (luaL_loadfile(L, filepath.c_str()) || lua_pcall(L, 0, 0, 0)) {
   std::cout << "ScriptEngine: error loading script. Error returned was: " << lua_tostring(L, -1) << std::endl;
  }
 }
}

もう少し明確にするために、.luaにあるのは次のようなものだけです。

-- s1.lua

setVars()
--do stuff
end

executeResults()
--dostuff
end

などですが、両方を続けてロードした後、s1.luaのsetVars()とs2.luaのsetVars()を呼び出せるようにしたいと思います。

4

3 に答える 3

6

これは事実上、gwellがCAPIを使用して提案したものです。

#include <stdio.h>

#include "lua.h"

static void
executescript(lua_State *L, const char *filename, const char *function)
{
    /* retrieve the environment from the resgistry */
    lua_getfield(L, LUA_REGISTRYINDEX, filename);

    /* get the desired function from the environment */
    lua_getfield(L, -1, function);

    return lua_call(L, 0, 0);
}

static void
loadscript(lua_State *L, const char *filename)
{
    /* load the lua script into memory */
    luaL_loadfile(L, filename);

    /* create a new function environment and store it in the registry */
    lua_createtable(L, 0, 1);
    lua_getglobal(L, "print");
    lua_setfield(L, -2, "print");
    lua_pushvalue(L, -1);
    lua_setfield(L, LUA_REGISTRYINDEX, filename);

    /* set the environment for the loaded script and execute it */
    lua_setfenv(L, -2);
    lua_call(L, 0, 0);

    /* run the script initialization function */
    executescript(L, filename, "init");
}

int
main(int argc, char *argv[])
{
    lua_State *L;
    int env1, env2;

    L = (lua_State *) luaL_newstate();
    luaL_openlibs(L);

    loadscript(L, "test1.lua");
    loadscript(L, "test2.lua");

    executescript(L, "test1.lua", "run");
    executescript(L, "test2.lua", "run");
    executescript(L, "test2.lua", "run");
    executescript(L, "test1.lua", "run");

    return 0;
}

テストスクリプト:

-- test1.lua
function init() output = 'test1' end
function run() print(output) end

-- test2.lua
function init() output = 'test2' end
function run() print(output) end

出力:

test1
test2
test2
test1

簡潔にするためにすべてのエラー処理を省略しましたが、の戻り値を確認して、の代わりにluaL_loadfile使用することをお勧めします。lua_pcalllua_call

于 2010-08-09T14:39:36.990 に答える
1

lua_newstate()ファイルごとに新しい状態を作成できます。これは私の前の答えよりも簡単でしょう。ただし、パフォーマンスが低下する可能性があります。

于 2010-08-09T02:54:34.053 に答える
1

このsetfenv()関数を使用して、ロードされたファイルごとにサンドボックスまたは環境を作成できます。

この例は、3つのファイルすべてに競合する関数がロードされる可能性があり、関数を任意の順序で呼び出すことができることを示しています。同様のコードをC++で記述できます。この例では、印刷機能を各環境にエクスポートするだけです。シナリオではさらに多くの機能が必要になる場合があります。

function newEnv()
  -- creates a simple environment
  return {["print"]=print}
end

local e={} -- environment table
local c    -- chunk variable

-- first instance
c = loadstring([[function f() print("1") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e]) -- set the loaded chunk's environment
pcall(c) -- process the chunk (places the function into the enviroment)

-- second instance
c = loadstring([[function f() print("2") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e])
pcall(c)

-- third instance
c = loadstring([[function f() print("3") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e])
pcall(c)

pcall(e[3].f) --> 3
pcall(e[2].f) --> 2
pcall(e[1].f) --> 1
pcall(e[1].f) --> 1
pcall(e[2].f) --> 2
pcall(e[3].f) --> 3

于 2010-08-08T02:58:20.700 に答える