2012-04-06 10 views
4

私は、ロボットプレイヤーのLuaスクリプトを扱う方法を改善するために、Bitfighterに取り組んでいます。現在、各ロボットは独自のLインスタンスを取得しており、環境テーブルを交換することにより、それらをすべて共有するようにしています。ボットはまったく別のスクリプトかもしれないことに注意してください。ルアとメタテーブルとグローバル変数

この方法は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インスタンスで複数のスクリプトを実行する根本的に良い方法はありますか?

答えて

3

あなたのコードが正しいに近いですが、いくつかの問題が含まれています - あなたは動作しません何かをしようとしている、とあなたの試みは間違った方法で間違ったことをした。..

あなたは機能を設定していますこのように見えるテーブルへの関数の環境:

当然
{__index = _G} 

、あなたがprintにアクセスしようとすると、それはこの表には見られません。

あなたのコメントから、実際に__indexフィールドのの環境テーブルののフィールドを設定したかったと推測します。 (これのC++変換は非常に簡単です)

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

:それはあなたが環境表は以下の例ではtようなものにしたかったです。

これを行わないでください。それはすぐに問題を解決しますが、十分なサンドボックス化を提供しません。

table.sort = 10 

"table"メタテーブルイベントハンドラによって_G中で発見される。このようなスクリプトは、例えば、考えてみましょう。 sorttableテーブルの単なる要素なので、無断で置き換えることができます。今、他のスクリプトはtable.sortでテーブルをソートすることができません。分離のこの種を実行するには


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

もう1つの方法は、スクリプトごとに環境テーブルを作成し、グローバルテーブルのセーフ/サンドボックス要素をこの環境テーブルにコピーすることです(各スクリプトには、グローバルテーブル)。

ご迷惑をおかけして申し訳ございませんが、私の提案する解決方法を問題に適切に説明する時間がありません。私はあなたがどこかに出発することをあなたに与えてくれることを願っています。あなたが最終的に使用するソリューションを含めるようにこれを編集して戻ってきてください。

+0

ありがとうございました! "別の方法は、各スクリプトの環境テーブルを作成することです..."これは私がしようとしているものですが、私は各スクリプトにグローバルテーブルのコピーを提供することは考えていませんでした。あなたの例から、これがスクリプトのセキュリティと分離を改善する理由がわかりますが、これを実装する方法がわかりませんし、かなりの研究にもかかわらず実装の良い例は見つかりませんでした。 – Watusimoto

+0

@魂本:実際はかなりシンプルです。ホワイトリストに登録された各要素をグローバルテーブルから環境テーブルにコピーするだけです(変更可能な要素になると、参照だけでなく要素も正しくコピーされます)。私は数日後に戻っていくつかの適切な例を挙げます。 (私に忘れないで、私に思い出させてください!) – Mankarse

+0

ありがとうございました。これは、私のグローバルテーブルが既にスクリプトにアクセスできるようにする関数と値に限定されているので、比較的単純であるはずです。だから、卸売コピー操作になるでしょう。 – Watusimoto