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

#define如果您使用 astd::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

我能想出什么(假设 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;

向量(替换MethodArrayElementType为保存字符串的结构的名称 -> 函数指针映射)。您可以使用&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 回答
0

我们做这样的事情,但是我们使用链表而不是使用数组。所以你的例子会变成

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

PawnRegister 的构造函数将所有对象(如 GVVfunc)添加到链表中。当您的脚本引擎想要查找函数时,它会遍历列表而不是扫描数组。我想您可以设置 PawnRegister 以将条目添加到数组中。

于 2013-01-19T18:10:04.173 回答