ok, so, i have another question about angelscript.
initially, when i was first presented with the idea of using a context to execute scripts, i thought i could bind an context to each object that needs to store some local script variables. essentially, i want the script to hold variables for the object, since the object in my game can take on many diffrent forms of attacks, think of the object in the application as a generic handler, and the script defines it.
however, in some testing i've been doing, it seems variables declared in the global space of a script, carry across diffrent context's, and don't get released when i release the context.
basically, what i'm asking, is how can i approach storing local variable's on a per context basis.
the approach i'm thinking of is to create a small multi-variable container in my object's, similar to what i did when i used lua before i changed over to angelscript, but this present's me with one last problem if i were to take this approach, that i want to contain pointers to handle's in the script which represent's class's. i do this by containing a void * in my container, and push the pointer to that, but i don't know how to register a function which can take a handle and act as void *, basically i need to register a function like this:
Engine->RegisterObjectMethod("ScriptDataObject", "void PushPointer(string &, void*)", asMethod(ScriptDataObject, PushPointer), asCALL_THISCALL);
//The above's first parameter is a name for the variable, and the second is the pointer to the handle being passed from angelscript to the object.
essentially the script would look like this:
...
NVPath @Path = NVPath(null, 5.0); //Path object created in the application as a reference object.
BattleAction.GetDataObject().PushPointer("Path", Path);
...//Later:
NVPath @Path = BattleAction.GetDataObject().GetPointer("Path"); //Needs to be cast as a NVPath object?
hopefully i've made this clear enough. i'd much prefer to use diffrent context's to hold the local context variables, but if that isn't possible, implementing this second method as a multi-purpose variable container would be prefered.
(i suppose one option would to write a wrapper for every possible class to be pushed to the dataObject, but that can be pretty tedious.)
First of all. I highly recommend you not to use one context for each of your objects. You'll waste a lot memory without any additional benefit.
The asIScriptContext is just holding a callstack with local variables and nothing else. Unless you have scripts that execute over several frames (i.e. are suspended and resumed) there is absolutely no need to use multple contexts.
Yes, global variables in the script modules are shared by all contexts and live on until the module is discarded.
What you really want is to have an instance of a script class for each of your objects. Your application object should instanciate the script class and keep a reference to it as long as needed.
As for your question on creating generic containers I suggest you take a look at the following add-ons: script handle, script any, script dictionary. In case neither of those add-ons solve what you're looking for, then you may want to read the following article on implementing methods that take variable arguments: Manual: The variable argument type.
I believe the dictionary is probably an exact fit for what you wanted to implement.
ok, so, hopefully this well be the last question i will need to ask to get on my way.
essentially, i'm calling a function which needs to return several pieces of information's, so i pass refrence arguments to the function, as an example of it's implementation i did:
void Add(float a, float b, float &out c){
c = a+b;
return;
}
and am using an extrapolated multi-argument function caller/executer in c++ like so:
void ScriptManager::ExecuteFunction(asIScriptFunction *Func, const char *FmtTxt, ...){
va_list lst;
va_start(lst, FmtTxt);
m_Context->Prepare(Func);
unsigned int i=0;
for(;FmtTxt && FmtTxt!='\0';i++){
unsigned int f=0;
switch(FmtTxt){
case 's':
m_Context->SetArgObject(i, &std::string(va_arg(lst, const char*)));
break;
case 'c':
m_Context->SetArgByte(i, va_arg(lst, char));
break;
case 'i':
m_Context->SetArgWord(i, va_arg(lst, int));
break;
case 'f':
m_Context->SetArgFloat(i, (float)va_arg(lst, double));
break;
case 'd':
m_Context->SetArgDouble(i, va_arg(lst, double));
break;
case 'P':
m_Context->SetArgAddress(i, va_arg(lst, void*));
case 'p':
m_Context->SetArgObject(i, va_arg(lst, void*));
break;
case '>':
i++;
f++;
break;
default:
break;
}
if(f) break;
}
printf("%d\n", m_Context->Execute());
if(FmtTxt){
switch(FmtTxt){
case 'd':
*va_arg(lst, double*) = m_Context->GetReturnDouble();
break;
case 'f':
*va_arg(lst, float*) = m_Context->GetReturnFloat();
break;
case 'i':
*va_arg(lst, int*) = m_Context->GetReturnWord();
break;
case 'c':
*va_arg(lst, char*) = m_Context->GetReturnByte();
case 'p':
*va_arg(lst, void**) = m_Context->GetReturnObject();
break;
default:
break;
}
}
va_end(lst);
}
the problem is i don't know exactly what to use to set the refrence value being passed out by the add function, i've tried this:
The correct function is the SetArgAddress() function which you are calling. However, I believe your problem is that you're missing a 'break' so the code falls through the 'p' option that is incorrectly calling the SetArgObject(), thus you end up with the error.
I suggest checking the return codes from the SetArg.. functions, at least in debug mode. I think it would have helped you catch the error yourself.