Sign in to follow this  
Maega

Class registration problem

Recommended Posts

I have registered a C++ class successfully (according to return codes), but when I try to use it in a script, I get an "Expected Identifier" error.
engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	int r = engine->SetMessageCallback(asMETHOD(CLoad, GetScriptError), this, asCALL_THISCALL); assert( r >= 0 );


	RegisterScriptString(engine);

	r = engine->RegisterObjectType("CEngine", sizeof(CEngine), asOBJ_VALUE | asOBJ_APP_CLASS_CDA); assert( r >= 0 );

	r = engine->RegisterObjectBehaviour("CEngine", asBEHAVE_CONSTRUCT, "void f()", asMETHOD(CLoad, Constructor), asCALL_THISCALL); assert(r >= 0);
	
	r = engine->RegisterObjectBehaviour("CEngine", asBEHAVE_DESTRUCT, "void f()", asMETHOD(CLoad, Destructor), asCALL_THISCALL); assert(r >= 0);

	r = engine->RegisterObjectMethod("CEngine", "void ShowMessage(string &in)", asMETHOD(CEngine, ShowMessage), asCALL_THISCALL); assert( r >= 0 );

	r = engine->RegisterObjectMethod("CEngine", "void Find(string &in)", asMETHOD(CEngine, FindGame), asCALL_THISCALL); assert( r >= 0 );

	r = engine->RegisterObjectMethod("CEngine", "void LoadExtension(string &in)", asMETHOD(CEngine, Extension), asCALL_THISCALL); assert( r >= 0 );



Script
void main()
{

CEngine blah;

}


Am I doing something wrong? Also, is it a bad idea to have the registered construction and destruction functions in another class? I'm trying not to put Angelscript code inside the C++ class. Finally, if I leave the body of the void main function empty, asserts are raised. Why is that?

Share this post


Link to post
Share on other sites
I don't see any error in your code. I'll have to look into this.

What version of AngelScript are you using? What compiler and OS are you running on?


The CLoad::Constructor and CLoad::Destructor must not try to access any members of CLoad because the this pointer will actually point to a CEngine object (uninitialized, in case of the constructor). If you follow that, it should work ok. Though I think it may be a bit confusing having it like this, and wouldn't recommend it.

Share this post


Link to post
Share on other sites
Hello,

I am using the current stable release, not the WIP.

As for the CLoad part, all I'm doing is calling the constructor and destructor of the object. I don't do anything else.

Share this post


Link to post
Share on other sites
Hello,

I built revision 338 of the trunk and tried that. I still have the same problems.

For some reason I have a feeling it's something I'm doing wrong or people would have reported similar problems before.

Share this post


Link to post
Share on other sites
I wrote the following test for 2.15.0:


class CEngine
{
public:
CEngine() {};
~CEngine() {};
void ShowMessage(std::string &) {}
void Find(std::string &) {}
void LoadExtension(std::string &) {}
void Constructor(void *p) {}
void Destructor(void *p) {}
};

bool Test2()
{
bool fail = false;

COutStream out;
asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
int r = engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); assert( r >= 0 );
RegisterScriptString(engine);

r = engine->RegisterObjectType("CEngine", sizeof(CEngine), asOBJ_VALUE | asOBJ_APP_CLASS_CDA); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("CEngine", asBEHAVE_CONSTRUCT, "void f()", asMETHOD(CEngine, Constructor), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectBehaviour("CEngine", asBEHAVE_DESTRUCT, "void f()", asMETHOD(CEngine, Destructor), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("CEngine", "void ShowMessage(string &in)", asMETHOD(CEngine, ShowMessage), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("CEngine", "void Find(string &in)", asMETHOD(CEngine, Find), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("CEngine", "void LoadExtension(string &in)", asMETHOD(CEngine, LoadExtension), asCALL_THISCALL); assert( r >= 0 );

const char * script =
"void main() \n"
"{ \n"
"CEngine blah; \n"
"} \n";

asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
mod->AddScriptSection("script", script);
r = mod->Build();
if( r < 0 )
{
fail = true;
}

engine->Release();

return fail;
}




Running it doesn't show any of the problems you're reporting. Could you check to see if you're doing something different from what I have done above?

Share this post


Link to post
Share on other sites
I moved the constructor and destructor into the CEngine class.

Now I'm just crashing. The asserts also happen with an empty void main and when I have CEngine blah; inside the main.

Share this post


Link to post
Share on other sites
I think the problem is with the constructor/destructor behaviour. Since my test only compiled the script, but didn't execute it I didn't notice an error that I made.

Since the constructor/destructor behaviours are implemented as class methods, the object pointer to work on is stored in the this pointer, not in any of the method arguments as I had implemented in my test. I changed this in my test, and also added a CEngine as global variable in the script to test this.


class CEngine
{
public:
CEngine() {};
~CEngine() {};
void ShowMessage(std::string &) {}
void Find(std::string &) {}
void LoadExtension(std::string &) {}
void Constructor()
{
new(this) CEngine();
}
void Destructor()
{
this->~CEngine();
}
};

bool Test2()
{
bool fail = false;

COutStream out;
asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
int r = engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); assert( r >= 0 );
RegisterScriptString(engine);

r = engine->RegisterObjectType("CEngine", sizeof(CEngine), asOBJ_VALUE | asOBJ_APP_CLASS_CDA); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("CEngine", asBEHAVE_CONSTRUCT, "void f()", asMETHOD(CEngine, Constructor), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectBehaviour("CEngine", asBEHAVE_DESTRUCT, "void f()", asMETHOD(CEngine, Destructor), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("CEngine", "void ShowMessage(string &in)", asMETHOD(CEngine, ShowMessage), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("CEngine", "void Find(string &in)", asMETHOD(CEngine, Find), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("CEngine", "void LoadExtension(string &in)", asMETHOD(CEngine, LoadExtension), asCALL_THISCALL); assert( r >= 0 );

const char * script =
"CEngine g; \n"
"void main() \n"
"{ \n"
"CEngine blah; \n"
"} \n";

asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
mod->AddScriptSection("script", script);
r = mod->Build();
if( r < 0 )
{
fail = true;
}

engine->Release();

return fail;
}



The above works, without presenting any of the problems you mentioned.


How have you implemented the constructor and destructor behaviour methods? I recommend you implement them as global functions, or static member methods, in which case they would look like this:


class CLoad
{
static Constructor(void *p)
{
new(p) CEngine();
}

static Destructor(CEngine *p)
{
p->~CEngine();
}
}

r = engine->RegisterObjectBehaviour("CEngine", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CLoad::Constructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("CEngine", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CLoad::Destructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );


Share this post


Link to post
Share on other sites
While the asserts still happen, moving the constructor and destructor to global functions seems to have fixed the other problem.

Edit: Actually, I'm getting Unexpected Token '<unrecognized token>' with the line number beyond the end of the script when I try to call a registered function. Might be a different problem.

Share this post


Link to post
Share on other sites
That last error is probably due to opening the script file in text mode, instead of binary mode. If opening the script file in text mode, the line endings may get translated from CRLF to just LF, thus producing a shorted script buffer than the file size.

Share this post


Link to post
Share on other sites
Quote:
Original post by WitchLord
That last error is probably due to opening the script file in text mode, instead of binary mode. If opening the script file in text mode, the line endings may get translated from CRLF to just LF, thus producing a shorted script buffer than the file size.


I'm passing the script text to Angelscript via a std::string. I'm using Angelscript inside of a browser plugin, so the script text comes from a text file on a web server. If I output it to a message box, it looks right. Would you suggest I do it another way?

Share this post


Link to post
Share on other sites
Does the script length correspond with strlen(scrípt.c_str())?

Obviously the parser is trying to find more tokens beyond the end of the script, and the only way it will do that is if your telling AngelScript in AddScriptSection that the script is longer than it really is.

Share this post


Link to post
Share on other sites
Quote:
Original post by WitchLord
Does the script length correspond with strlen(scrípt.c_str())?

Obviously the parser is trying to find more tokens beyond the end of the script, and the only way it will do that is if your telling AngelScript in AddScriptSection that the script is longer than it really is.


That's what it was. I messed up a memcpy which made me miss the null terminator. I was getting junk at the end and didn't notice. It was intermittent which made it fun to find.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this