5

ちょっと怖いですね。

背景情報として、いくつかの lua モジュールを含む tar アーカイブを、LuaInterface を使用して C# アプリケーションにロードしたいと考えています。最も簡単な方法は、これらのファイルを一時フォルダーに抽出し、lua モジュールの検索パスを変更して、require で通常どおり読み取ることです。しかし、これらのスクリプトをファイル システムのどこかに置きたくありません。

だから私は#ziplibで tar アーカイブをロードできるはずだと思った。しかし、#zlib はすでにプロジェクトの一部です。

アーカイブからファイルを文字列 (ストリーム) として正常にロードした後、LuaInterface 経由で C# の lua.DoString(...) に渡すことができるはずです。

しかし、モジュールに「module(..., package.seeall)」のような行がある場合、dostring または dofile によってモジュールをロードするだけでは機能しません。

もう 1 つの問題は、モジュールが tar アーカイブにある他のモジュールに依存している可能性があることです。

考えられる解決策の 1 つは、ここで説明されているようにカスタム ローダーを定義することです。

私の考えは、#ziplib を使用して C# でそのようなローダーを実装し、このローダーを C# アプリケーションの lua スタックにマップすることです。

これと同じような仕事をした人はいますか?このような問題にすでに対処している、すぐに使用できるソリューションはありますか?

tar ファイルは必須ではありませんが、あると便利なパッケージ形式です。

このアイデアは実現可能ですか、それとも完全に不可能ですか?

アーカイブから lua ファイルを抽出するクラスの例をいくつか書きました。このメソッドはローダーとして機能し、lua 関数を返します。

namespace LuaInterfaceTest
{
 class LuaTarModuleLoader
 {
    private LuaTarModuleLoader() { }
    ~LuaTarModuleLoader()
    {
        in_stream_.Close();
    }
    public LuaTarModuleLoader(Stream in_stream,Lua lua )
    {
        in_stream_ = in_stream;
        lua_ = lua;
    }

    public LuaFunction load(string modulename, out string error_message)
    {
        string lua_chunk = "test=hello";
        string filename = modulename + ".lua";
        error_message = "Unable to locate the file";
        in_stream_.Position = 0; // rewind
        Stream gzipStream = new BZip2InputStream(in_stream_);
        TarInputStream tar = new TarInputStream(gzipStream);
        TarEntry tarEntry;
        LuaFunction func = null;
        while ((tarEntry = tar.GetNextEntry()) != null)
        {
            if (tarEntry.IsDirectory)
            {
                continue;
            }
            if (filename == tarEntry.Name)
            {
                MemoryStream out_stream = new MemoryStream();
                tar.CopyEntryContents(out_stream);
                out_stream.Position = 0; // rewind
                StreamReader stream_reader = new StreamReader(out_stream);
                lua_chunk = stream_reader.ReadToEnd();
                func = lua_.LoadString(lua_chunk, filename);
                string dum = func.ToString();
                error_message = "No Error!";
                break;
            }
        }
        return func;
    }
    private Stream in_stream_;
    private Lua lua_;
}

}

LuaInterface にこのような load メソッドを登録してみる

        Lua lua = new Lua();
        GC.Collect();
        Stream inStream = File.OpenRead("c:\\tmp\\lua_scripts.tar.bz2");
        LuaTarModuleLoader tar_loader = new LuaTarModuleLoader(inStream, lua);
        lua.DoString("require 'CLRPackage'");
        lua.DoString("import \"ICSharpCode.SharpZipLib.dll\"");
        lua.DoString("import \"System\"");
        lua["container_module_loader"] = tar_loader;
        lua.DoString("table.insert(package.loaders, 2, container_module_loader.load)");
        lua.DoString("require 'def_sensor'");

この方法で試してみると、 require の呼び出し中に例外が発生します。

「インスタンス メソッド 'load' には、null 以外のターゲット オブジェクトが必要です」

load メソッドを直接呼び出そうとしましたが、ここでは ":" 表記を使用する必要があります。

lua.DoString("container_module_loader:load('def_sensor')");

そのようなメソッドを呼び出すと、メソッドの上にあるデバッガーのブレークポイントにヒットするため、すべてが期待どおりに機能します。

しかし、「:」表記でメソッドを登録しようとすると、メソッドの登録中に例外が発生します。

lua.DoString("table.insert(package.loaders, 2, container_module_loader:load)");

"[string "chunk"]:1: ')' の近くに関数の引数が必要です"

4

2 に答える 2

3

LÖVE では、それが機能しています。すべての Lua ファイルは 1 つの zip ファイル内にあり、...使用されていても機能します。彼らが使用するライブラリはPhysicsFSです。

ソースを見てください。おそらく /modules/filesystem から始めることができます。

于 2011-04-06T22:42:42.093 に答える
3

私はついにトリックを手に入れました;-)

私が現在よく理解していない問題の 1 つは、ローダーが文字列を返してはならないということです。これが私の解決策です:

ローダー クラス自体:

namespace LuaInterfaceTest
{
class LuaTarModuleLoader
{
    private LuaTarModuleLoader() { }
    ~LuaTarModuleLoader()
    {
        in_stream_.Close();
    }
    public LuaTarModuleLoader(Stream in_stream,Lua lua )
    {
        in_stream_ = in_stream;
        lua_ = lua;
    }

    public LuaFunction load(string modulename)
    {
        string lua_chunk = "";
        string filename = modulename + ".lua";
        in_stream_.Position = 0; // rewind
        Stream gzipStream = new BZip2InputStream(in_stream_);
        TarInputStream tar = new TarInputStream(gzipStream);
        TarEntry tarEntry;
        LuaFunction func = null;
        while ((tarEntry = tar.GetNextEntry()) != null)
        {
            if (tarEntry.IsDirectory)
            {
                continue;
            }
            if (filename == tarEntry.Name)
            {
                MemoryStream out_stream = new MemoryStream();
                tar.CopyEntryContents(out_stream);
                out_stream.Position = 0; // rewind
                StreamReader stream_reader = new StreamReader(out_stream);
                lua_chunk = stream_reader.ReadToEnd();
                func = lua_.LoadString(lua_chunk, modulename);
                string dum = func.ToString();
                break;
            }
        }
        return func;
    }
    private Stream in_stream_;
    private Lua lua_;
}

}

そして、ローダーの使い方、すべてのパッケージが本当に必要かどうかはわかりません。しかし、呼び出しを「:」表記でまとめて、「load_wrapper」関数の背後に隠す必要がありました。

        string load_wrapper = "local function load_wrapper(modname)\n return container_module_loader:load(modname)\n end";
        Lua lua = new Lua();
        GC.Collect();
        Stream inStream = File.OpenRead("c:\\tmp\\lua_scripts.tar.bz2");
        LuaTarModuleLoader tar_loader = new LuaTarModuleLoader(inStream, lua);
        lua.DoString("require 'CLRPackage'");
        lua.DoString("import \"System\"");
        lua["container_module_loader"] = tar_loader;
        lua.DoString(load_wrapper);

        string loader_package = "module('my_loader', package.seeall) \n";
        loader_package += load_wrapper + "\n";
        loader_package += "table.insert(package.loaders, 2, load_wrapper)";
        lua.DoString(loader_package);
        lua.DoFile("./load_modules.lua");

これが他の人にも役立つことを願っています

于 2011-04-07T08:24:09.863 に答える