Hey, first time poster here.
Love your library, it's just what I needed for my game engine project and it's been mostly pretty smooth sailing so far (Except for that bug with the handle-types and template objects, but I came here to check and found you'd fixed that, so good on ya).
Now, however, I've been attempting to implement a script class that my c++-coded screens (part of a GUI system, child class of a generic GUI object) can use to implement scripted behaviour. What I have script-wise is one base class:
class screen
{
screen()
{}
~screen()
{}
void OnKey(string name, SL_KEY key)
{}
void OnClick(string name, uint8 button, uint x, uint y, bool down)
{}
void OnMouseOver(string name, uint x, uint y, bool over)
{}
void OnMouseMove(uint x, uint y)
{}
void OnTick(uint time)
{}
void OnOpen()
{}
void OnClose()
{}
}
... with each screen object in c++-side loading the main part of the child class (the functions) from an xml file and prepending/appending automatically generated script code onto the ends to produce a working class named after the screen itself, for example:
#include "scripts\stdlib\screen.as"
class test_class : screen
{
test_class()
{
}
~test_class()
{
}
//Stuff from xml file here
void OnClick(string name, uint8 button, uint x, uint y, bool down)
{
if(name == "button1")
{
print("YAY FOR THE FIRST BUTTON!\n");
}
if(name == "button2")
{
print("YAY FOR THE SECOND BUTTON!\n");
}
if(name == "button3")
{
print("YAY FOR THE THIRD BUTTON!\n");
}
if(name == "button4")
{
print("YAY FOR THE FOURTH BUTTON!\n");
}
if(name == "tbutton1")
{
print("YAY FOR THE TEXT BUTTON!\n");
print("Closing the screen!!\n");
close_screen("test");
open_screen("test2");
}
}
void OnMouseOver(string name, uint x, uint y, bool over)
{}
void OnMouseMove(uint x, uint y)
{
print("MOVING!");
}
void OnTick(uint time)
{}
void OnOpen()
{}
void OnClose()
{}
//Stuff from XML ends
}
This is then added to the script builder (the most recent version with the ultra-handy include callback, which I use to disallow files with identical names) along with all other generated screen scripts, and it all seems to compile sucessfully. I then get the type and so on of the object I want instanciate, with a method based on the tutorial on the angelcode website:
asIObjectType* SLAScriptEngine::SLGetObjTypeByID (const char* decl, asIScriptModule* module)
{
SL_LOG("Declaration: %s", decl);
static int ID = 0;
ID = module->GetTypeIdByDecl(decl);
if( ID <= 0)
{
SL_WARN(false, "Out of %i functions, ", module->GetFunctionCount());
SLAScriptEngine::ctx->Release();
SLAScriptEngine::engine->Release();
SL_ASSERT(ID != asINVALID_TYPE , "The type '%s' is not valid", decl);
return 0;
}
SL_LOG("Type ID: %i", ID);
asIObjectType* obj = NULL;
obj = SLAScriptEngine::engine->GetObjectTypeById(ID);
SL_ASSERT(obj != NULL,"Obj undefined!");
return obj;
}
int SLAScriptEngine::SLGetDecFactID (asIObjectType* t, const char* decl, asIScriptModule* module)
{
int ID = t->GetFactoryIdByDecl(decl);
if( ID < 0)
{
SL_WARN(false, "Out of %i functions, ", module->GetFunctionCount());
SL_ASSERT(ID != asERROR, "The module '%s' did not compile sucessfully", module->GetName());
SL_ASSERT(ID != asINVALID_DECLARATION, "The constructor declaration '%s' is not valid.", decl);
SL_ASSERT(ID != asNO_FUNCTION , "No constructor with the declaration '%s' was found.", decl);
SLAScriptEngine::ctx->Release();
SLAScriptEngine::engine->Release();
return 0;
}
return ID;
}
void SLAScriptEngine::SLExecFunc ()
{
int r = SLAScriptEngine::ctx->Execute();
SL_LOG("Executed");
SL_ASSERT(r != asEXECUTION_ERROR, "Execution failed!");
SL_ASSERT(r != asEXECUTION_ABORTED , "Execution aborted!");
SL_ASSERT(r != asEXECUTION_SUSPENDED , "Execution suspended!");
SL_ASSERT(r != asEXECUTION_EXCEPTION , "Execution excepted!");
SL_ASSERT(r == asEXECUTION_FINISHED, "Unknown Error!");
}
void* SLAScriptEngine::SLExecFuncAndReturnAdress ()
{
void* ret = NULL;
SLAScriptEngine::SLExecFunc();
ret = SLAScriptEngine::ctx->GetReturnAddress();
SL_ASSERT(ret != NULL, "GetReturnAdress failed!");
return ret;
}
void* SLAScriptEngine::SLExecFuncAndReturnObject ()
{
void* ret = NULL;
SLAScriptEngine::SLExecFunc();
ret = SLAScriptEngine::ctx->GetReturnObject();
SL_ASSERT(ret != NULL, "GetReturnObject failed!");
return ret;
}
void SLAScriptEngine::SLPrepFunc (int ScriptID)
{
int r = SLAScriptEngine::ctx->Prepare(ScriptID);
if( r < 0 )
{
SL_ASSERT(r != asCONTEXT_ACTIVE, "Failed to prepare the context: Context still active.");
SL_ASSERT(r != asNO_FUNCTION , "Failed to prepare the context: Function ID invalid.");
SLAScriptEngine::ctx->Release();
SLAScriptEngine::engine->Release();
}
return;
}
int SLAScriptEngine::SLGetDecMethID (asIObjectType* t, const char* decl, asIScriptModule* module)
{
int ID = t->GetMethodIdByDecl(decl);
if( ID < 0 and ID != asNO_FUNCTION)
{
SL_WARN(false, "Out of %i functions, ", module->GetFunctionCount());
SL_ASSERT(ID != asERROR, "The module '%s' did not compile sucessfully", module->GetName());
SL_ASSERT(ID != asINVALID_DECLARATION, "The method declaration '%s' is not valid.", decl);
SL_ASSERT(ID != asMULTIPLE_FUNCTIONS, "Multiple method with the declaration '%s' were found.", decl);
SLAScriptEngine::ctx->Release();
SLAScriptEngine::engine->Release();
return 0;
}
SL_WARN(ID != asNO_FUNCTION, "The method '%s' was not found.", decl);
return ID;
}
void SLScreen::initialise()
{
string t_name(name+"_class");
asIObjectType* type = SLAScriptEngine::SLGetObjTypeByID(t_name.c_str());
SL_LOG("AS Object Type: %s", type->GetName());
asIObjectType* b_type = type->GetBaseType();
SL_LOG("AS Object Base Type: %s", b_type->GetName());
string screen_dec(name+"_class @"+name+"_class()");
SL_LOG("Screen declaration: %s", screen_dec.c_str());
int factory_id = SLAScriptEngine::SLGetDecFactID(type, screen_dec.c_str());
SL_LOG("Factory function ID is: %i", factory_id);
SLAScriptEngine::SLPrepFunc(factory_id);
script_class = SLAScriptEngine::SLExecFuncAndReturnObject();
SL_LOG("Setting up click func ID for Screen %s", name.c_str());
string funcDef("void OnClick(string name, uint8 button, uint x, uint y, bool down)");
ClickFuncID = SLAScriptEngine::SLGetDecMethID(type, funcDef.c_str());
SL_LOG("Func ID is: %i", ClickFuncID);
SL_LOG("Setting up mouse-over ID for Screen %s", name.c_str());
funcDef = "void OnMouseOver(string name, uint x, uint y, bool over)";
MOFuncID = SLAScriptEngine::SLGetDecMethID(type, funcDef.c_str());
SL_LOG("Func ID is: %i", MOFuncID);
SL_LOG("Setting up mouse-move ID for Screen %s ", name.c_str());
funcDef = "void OnMouseMove(uint x, uint y)";
MMFuncID = SLAScriptEngine::SLGetDecMethID(type, funcDef.c_str());
SL_LOG("Func ID is: %i", MMFuncID);
SL_LOG("Setting up key-press ID for Screen %s ", name.c_str());
funcDef = "void OnKey(string name, SL_KEY key)";
KeyFuncID = SLAScriptEngine::SLGetDecMethID(type, funcDef.c_str());
SL_LOG("Func ID is: %i", KeyFuncID);
}
Which, when run, logs:
LOG: Declaration: test_class
LOG: Type ID: 134217744
LOG: AS Object Type: test_class
LOG: AS Object Base Type: screen
LOG: Screen declaration: test_class @test_class()
LOG: Factory function ID is: 122
LOG: Executed
LOG: Setting up click func ID for Screen test
LOG: Func ID is: 157
LOG: Setting up mouse-over ID for Screen test
LOG: Func ID is: 158
LOG: Setting up mouse-move ID for Screen test
LOG: Func ID is: 159
LOG: Setting up key-press ID for Screen test
LOG: Func ID is: 156
So that seems to be fine. However, when I get into the actual function calling (which pretty much happens as soon as I move the mouse and send a mouse-move check through the input system), which uses this code:
SLGUIObject* SLScreen::mouseMove (int x, int y)
{
static SLGUIObject* ret;
ret = NULL;
foreach(SLGUIObject* child, children)
{
ret = child->mouseMove(x, y);
if(ret != NULL)
{break;}
}
if(ret != NULL and last_mouse_mov_ptr != NULL and ret != last_mouse_mov_ptr and MOFuncID > 0)
{
//call mouseOver with an out for last_mouse_mov_ptr
SL_LOG("Executing MouseOver function for an out %i", MOFuncID);
SLAScriptEngine::SLPrepFunc(MOFuncID);
SLAScriptEngine::SLSetObject(script_class);
SLAScriptEngine::SLSetArgObject(0, ret->getName());
SLAScriptEngine::SLSetArgDWord(1, x);
SLAScriptEngine::SLSetArgDWord(2, y);
SLAScriptEngine::SLSetArgByte(3, true);
SLAScriptEngine::SLExecFunc();
}
//call mouse-in script function for ret
if(ret != NULL and MOFuncID > 0)
{
//call mouseOver with an in for ret
SL_LOG("Executing MouseOver function for an in %i", MOFuncID);
SLAScriptEngine::SLPrepFunc(MOFuncID);
SLAScriptEngine::SLSetObject(script_class);
SLAScriptEngine::SLSetArgObject(0, ret->getName());
SLAScriptEngine::SLSetArgDWord(1, x);
SLAScriptEngine::SLSetArgDWord(2, y);
SLAScriptEngine::SLSetArgByte(3, false);
SLAScriptEngine::SLExecFunc();
}
if(MMFuncID > 0)
{
//call mouseMove with an in for ret
SL_LOG("Executing MouseMove function for an in %i", MMFuncID);
SLAScriptEngine::SLPrepFunc(MMFuncID);
SL_LOG("Prepared");
SLAScriptEngine::SLSetObject(script_class);
SL_LOG("Obj Set");
SLAScriptEngine::SLSetArgDWord(0, x);
SL_LOG("Arg 1");
SLAScriptEngine::SLSetArgDWord(1, y);
SL_LOG("Arg 2");
SLAScriptEngine::SLExecFunc();
SL_LOG("Executed");
}
last_mouse_mov_ptr = ret;
return ret;
}
.. it crashes, without any sort of message apart from a generic Windows "this program crashed unexpectedly" message. The log file:
LOG: Executing MouseMove function for an in 159
LOG: Prepared
LOG: Obj Set
LOG: Arg 1
LOG: Arg 2
... shows it gets to calling the execfunc function, shown far above, but it seems to crash upon calling the function, without even returning anything to assert against, as it never gets to logging "Executed". I note that executing normal global functions from within the engine works fine - there's an "OnStart" function and an "OnTick" function that execute without any trouble.
For the record, I'm running Angelscript from the SVN with a revison number of 477, compiling using Code::blocks and the latest MinGW. Am I doing something wrong, or is this an Angelscript bug? Should I be defining a single instance of the child script class in the script instead of instanciating one in the engine, perhaps, and attempting to get a reference to that instance instead? Have I majorly failed to understand something?