4

Bitfighterでロボット プレイヤーの Lua スクリプトを処理する方法の改善に取り組んでいます。現在、各ロボットは独自の L インスタンスを取得しており、環境テーブルを交換することで、すべてのロボットが 1 つを共有できるようにしようとしています。ボットは完全に異なるスクリプトである可能性があることに注意してください。

このメソッドは Lua 5.2 で非推奨になっていることは認識していますが、現在はまだ Lua 5.1 を使用している lua-vec を使用しています。ゲームは C++ で書かれています。

そう...

最初に環境を作成し、それを呼び出します:

// Create a table with room for 0 array and 1 non-array elements
lua_createtable(L, 0, 1);                 // -- tab

// Set the globals table to handle any requests that the 
// script's environment can't
lua_pushstring(L, "__index");             // -- tab, "__index"
lua_pushvalue(L, LUA_GLOBALSINDEX);       // -- tab, "__index", _G

// Set table["__index"] = _G, pops top two items from stack
lua_settable(L, -3);                      // -- tab

// Store the new table in the retistry for future use
lua_setfield(L, LUA_REGISTRYINDEX, name); // -- <<empty stack>>

その後、いくつかの Lua コードをロードし、環境テーブルを呼び出します。

luaL_loadfile(L, "luascripts.lua");

lua_getfield(L, LUA_REGISTRYINDEX, name); // -- function, table 
lua_setfenv(L, -2);                       // -- function

次に、ロードされたコードを実行します。

lua_pcall(L, 0, 0, 0);

読み込まれた Lua が印刷などの基本的な機能を使用しようとすると、次のエラーで失敗します。

attempt to call global 'print' (a nil value) 

ただし、スクリプトは次のことを実行できます。

__index["print"](12)

では、なぜ印刷に直接アクセスできないのでしょうか。何が欠けていますか?または、同じ Lua インスタンスで複数のスクリプトを実行する根本的に優れた方法はありますか?

4

1 に答える 1

3

あなたのコードはほぼ正しいですが、いくつかの問題があります - うまくいかないことをしようとしていますが、あなたの試みは間違った方法で間違ったことをしました..

関数の関数環境を次のようなテーブルに設定しています。

{__index = _G}

当然、 にアクセスしようとするとprint、この表には見つかりません。

あなたのコメントから、実際には環境テーブルのメタ__indexテーブルのフィールドを設定したかったと推測します。つまり、環境テーブルを次の例のようにしたいと考えていました。t

t = {}
setmetatable(t, {__index = _G})

(これの C++ への翻訳はかなり簡単です)。

これをしないでください。当面の問題は解決しますが、十分なサンドボックスは提供されません。たとえば、次のようなスクリプトを考えてみましょう。

table.sort = 10

"table"_Gメタテーブル イベント ハンドラによって検出されます。sorttableテーブルの単なる要素であるため、免責に置き換えることができます。これで、他のスクリプトは でテーブルをソートできなくなりますtable.sort


この種の分離を実行する 1 つの方法は、関連するメタテーブル イベントの手書きのハンドラーを使用して、ある種の (おそらく再帰的な) ユーザーデータを介してすべてのグローバル値へのアクセスを仲介することです。(この方法はおそらくパフォーマンスと制御の可能性が最も高いですが、実装が難しい場合があります)。

もう 1 つの方法は、スクリプトごとに環境テーブルを作成し、安全な/サンドボックス化された要素をグローバル テーブルからこの環境テーブルにコピーすることです (各スクリプトがグローバル テーブルのすべての変更可能な要素の完全に個別のバージョンを持つようにするため)。

申し訳ありませんが、あなたの問題に対する提案された解決策を適切に説明する時間がありません. 私があなたに出発点を与えたことを願っています。自由に戻ってこれを編集し、最終的に使用するソリューションを含めてください。

于 2012-04-06T14:21:36.563 に答える