4

さて、コードから実行されている抽象仮想マシン (「PAWN」) があり、スクリプトは関数を実行できます。これらの関数は、C++ コードによって実行される C コードからスクリプトに登録されます。

C++ コードは、次の形式で配列を提供する必要があります。

{ "name_i_want_the_function_to_have_in_the_script" , function_in_my_cpp_code }

関数が配列にない場合、実行できません。(「存在しない」ため)

したがって、これにより次のことがわかります。

私の関数は次のようになります。

//Pawn Functions
#define PWNFUNC(a) static cell AMX_NATIVE_CALL a(AMX *amx, cell *params)

namespace PawnFunc
{
    PWNFUNC(GGV)
    {
        return pGameInterface->FindGameVersion();
    }
};//namespace PawnFunc

スクリプト関数情報を含む配列は、次のように別のファイルにあります。

AMX_NATIVE_INFO custom_Natives[] =
{
    {   "GetGameVersion", PawnFunc::GGV   },
    {   0,0   }
};

問題は次のとおりです。

そのアレイを自動更新することは可能ですか? (コンパイル時またはコード初期化時前/時)

今のところ、各機能を手動で追加する必要があります。これは時々面倒で、エラーが発生しやすくなります。

次のように変更したいと思います。

//Pawn Functions
#define PWNFUNC(a,b) ...?...

namespace PawnFunc
{
    PWNFUNC(GGV,GetGameVersion)//{ "GetGameVersion", PawnFunc::GGV }, is now added to "custom_Natives" array
    {
        return pGameInterface->FindGameVersion();
    }
};//namespace PawnFunc

これはまったく可能ですか?はいの場合、どうすればこれを達成できますか?

名前空間をループすることは可能ですか?

編集:ここにいくつかの擬似コードがあります:http://ideone.com/btG2lx

また、メモ: 実行時に実行できますが、DLLMain で実行する必要があります (私のプログラムは DLL です)。

4

4 に答える 4

1

スクリプト情報のストレージとして#definea を使用する場合、これで問題ありません。std::vector

(標準では、 から C スタイルの配列を取得できることが保証されていることに注意してください&custom_Natives[0])

std::vector<AMX_NATIVE_INFO> custom_Natives;

#define PWNFUNC(NAME, FUNC) \
 struct IMPL_ ## FUNC { \
   IMPL_ ## FUNC() { \
     AMX_NATIVE_INFO entry = { NAME, PawnFunc::FUNC }; \
     custom_Natives.push_back( entry ); \
   } \
 } INSTANCE_ ## FUNC; \
 static cell AMX_NATIVE_CALL FUNC(AMX *amx, cell *params)

このようなコードは、関数定義し、スクリプト エントリを に追加しますcustom_Natives

PWNFUNC("GetGameVersion", GGV)
{
    return pGameInterface->FindGameVersion();
}
于 2013-01-19T19:22:28.517 に答える
0

このようなことを行いますが、配列を使用する代わりにリンク リストを使用します。だからあなたの例は

namespace PawnFunc
{
    PWNFUNC(GGV)
    {
        return pGameInterface->FindGameVersion();
    }
    PawnRegister GGVfunc( "GetGameVersion", GGV );
};//namespace PawnFunc

PawnRegister のコンストラクターは、すべてのオブジェクト (GVVfunc など) をリンク リストに追加します。スクリプト エンジンが関数を検索する場合、配列をスキャンする代わりにリストをトラバースします。代わりに、配列にエントリを追加するように PawnRegister を設定できると思います。

于 2013-01-19T18:10:04.173 に答える
0

私が思いついたもの(Cスタイルの配列とCリンケージ関数を想定):

AMX_NATIVE_INFO custom_natives[] =
{
    { "GetGameVersion", TheGGVFunc },
    { 0, 0 }
};

// here a function call named `GetGameVersion` was encountered,
// so let's look it up using a naive linear search
const char *toBeCalled = "GetGameVersion"; // obtain this somehow
void (*fptr)(void) = NULL;
for (int i = 0; i < sizeof(custom_natives) / sizeof(*custom_natives) - 1; i++) {
    const char *name = custom_natives[i].name;
    if (strcmp(toBeCalled, name) == 0) {
        fptr = custom_natives[i].func;
        break;
    }
}

if (fptr != NULL) {
    fptr();
}
于 2012-12-24T21:10:16.040 に答える
0

概算できます。アイデアはstd::vector、C 配列の代わりにグローバルを使用し、グローバル オブジェクトのコンストラクターを使用してベクトルを拡張することです。main()そうすれば、実行が開始されるまでに配列が初期化されます。したがって、custom_Natives配列の代わりに

std::vector<MethodArrayElementType> custom_Natives;

vector (MethodArrayElementType文字列を保持する構造体の名前に置き換えます -> 関数ポインタのマッピング)。を使用すると、このベクトルを単純な C 配列のように扱うことができます&custom_Natives[0]

次に、定義するすべての関数のすぐ隣にRegistrar、メソッドを登録するための小さなクラスを追加します。

PWNFUNC(GGV) {
    // Your implementation goes here...
}

struct GGV_Registrar {
    GGV_Registrar() {
         MethodArrayElementType e = { "GetGameVersion", GGV };
        custom_Natives.push_back( e );
    };
} GGV_Registrar_instance;

グローバルGGV_Registrar_instanceコンストラクターのコンストラクターは、呼び出される前に呼び出され、ベクターmain()を更新します。custom_Natives

于 2012-12-24T21:19:31.827 に答える