Hi,
For scripting of my game I need some way to delay certain calls for some amount of seconds (no bigger precision needed for now). It seems that closures would greatly simplify this, but as far as I know they're not available yet? I will write down what I plan:
- A global function int call_out(string func_decl, int time_in_seconds, <params>)
- <params> part is a bit problematic as sadly Angelscript doesn't allow variadic arguments. I have two ideas on this:
- Use some array<variant> or dictionary to store all function arguments
- Register call_out function as as_CALL_GENERIC for 0, 1, 2 ... n arguments like void call_out(string, int, ?&in), void call_out(string, int, ?&in, ?&in) and so on, then insepct asIScriptGeneric object for parameters based on what I retrieve from called function declaration (I could even verify if the correct amount and type of arguments is provided I suppose)
- As this won't work as closure, it probably will have to be limited to 2 cases:
- call_out happens in object's method, func_decl has to be either global function or that object's method (of course it will be executed on the same object instance as the one that called the call_out)
- call_out happens in function, func_decl has to be global function only (as the caller is not an object)
Before I dig into some implementation details here are few usage examples:
### Example 1 ###
class Object
{
string str;
void foo()
{
print("Foo!\n");
call_out("void bar()", 5);
}
void bar()
{
print("Bar is " + str + "!\n");
}
}
Object obj;
obj.str = "baz";
obj.foo();
results in:
Foo!
# 5 seconds delay
Bar is baz!
### Example 2 ###
int main()
{
call_out("void print(string)", 10, "Foo\n");
}
results in:
# 10 seconds delay
Foo!
So what I got now, in some pseudo code as it's not yet working (plus doesn't even cover all possible paths):
engine->RegisterGlobalFunction("void call_out(const string &in, int &in, ?&in)",
asFUNCTION(CallOut), asCALL_GENERIC);
void CallOut(asIScriptGeneric* gen)
{
std::string* decl = *(std::string**)gen->GetAddressOfArg(0);
int32_t seconds = *(int32_t*)gen->GetAddressOfArg(1);
asIScriptContext* ctx = asGetActiveContext();
asIScriptFunction* func = ctx->GetFunction(0); // retrieve the caller
void* obj = ctx->GetThisPointer(0);
if (obj)
{
// this is the case where caller is object
type = ctx->GetThisTypeId(0);
asIScriptEngine* engine = ctx->GetEngine();
asITypeInfo* typeInfo = engine->GetTypeInfoById(type);
asIScriptFunction* method = typeInfo->GetMethodByDecl(decl->c_str());
// ^ this gives the object's method that we want to call, or null if it wasn't found
// after this we need to collect arguments from asIScriptGeneric and push the call_out
// struct into a queue
}
}
Maybe someone already figured this out and have some working code? If not, is my approach even slightly on track or completly off, will result in undefined behavior or will be terribly slow?
Best regards,
noizex