Advertisement

Beginner question

Started by August 18, 2005 07:56 AM
7 comments, last by DaesDemon 19 years, 3 months ago
Hello community and thanks for this Script API :) I am a beginner in AngelScript so please forgive my basic Questions. I would like to access some of my App C++ Object in AngelScript. Basically i don't have to create new objects by script, just use some already created. For example, i try that: mLog is a Log* object.
mEngine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
if( mEngine == 0 )
{
	mlog->logMessage("Failed to create script engine.");
	return;
}
RegisterScriptString(mEngine);
mEngine->RegisterObjectType("Log",sizeof(Log),asOBJ_CLASS);
mEngine->RegisterObjectMethod("Log","logMessage(const string& str)",asMETHOD(Log, logMessage),asCALL_THISCALL);
mEngine->RegisterGlobalProperty("Log* log",mLog);
int r= mEngine->ExecuteString(0,"log->logMessage(\"KooKoo from angels\")");
if( r < 0 ) mLog->logMessage("Invalid script statement. ");
else if( r == asEXECUTION_EXCEPTION ) mLog->logMessage("A script exception was raised.");

When i use it, i get an Invalid Script Statement. Could someone give me an idea about what i am doing wrong? [edit] I forgot to say that Log::logMessage is define like that:
void Log::logMessage(const std::string&, enum = 2, bool=false);
Perhaps the problem come from this default params I try that instead:
mEngine->RegisterObjectMethod("Log","logMessage(const string& str,int level,bool mask)",asMETHOD(Ogre::Log, logMessage),asCALL_THISCALL);
...
int r= mEngine->ExecuteString(0,"log->logMessage(\"KooKoo from angels\",2,false)");
but i get the same result! [/edit] [Edited by - DaesDemon on August 19, 2005 7:04:48 AM]
Hi DaesDemon,

Two problems:

The first one is that pointers are not supported in the AngelScript language. When you registered the "Log* log" property you received an error message, that would have told you that if you had verified it. I suggest you add an assert() after each call to a Register function that verifies the return code. You can register your log pointer directly without telling AngelScript that it is a pointer. Like this:

r = engine->RegisterGlobalProperty("Log log", mLog); assert( r >= 0 );


Note how I use the assert to validate the return code.

The second problem is that default parameters doesn't work. Even with the default parameters the function signature is void logMessage(const std::string&, enum, bool); So you have to register all those parameters, or you'll get some strange and difficult to find bugs. Alternatively you could write a simple wrapper that fills in the default parameters for you. Example:

void wrap_logMessage(const std::string &str, Log *log){  log->logMessage(str);}e = engine->RegisterObjectMethod("Log", "logMessage(const string& in)",asFUNCTION(wrap_logMessage),asCALL_CDECL_OBJLAST); assert( r >= 0 );


Hope this helps.

Regards,
Andreas

[edit]Added the in keyword to the parameter reference.[/edit]

[Edited by - WitchLord on August 18, 2005 1:50:13 PM]

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement
Thanks WitchLord for the explanation.

I add the assert after each of my AngelScript Api Call.
So now i can see that my RegisterObjectMethod don't works.

I hide you a bit of truth in my first post ( to make it easier to understand )
So now i tell you the truth ( all the truth ;) )

My classes are declared like that:
	namespace Ogre{Log::logMessage(const String&message,LogMessageLevel lml=LML_NORMAL,bool maskDebug=false);enum LogMessageLevel{...};typedef _StringBase String;typedef std::string _StringBase;}


and mLog is a property of an Editor::Class

So i tried that:
	void wrap_logMessage(const std::string& str,Ogre::Log* log){	log->logMessage(str);}ASEngine::ASEngine(void){	Ogre::Log* mLog = Editor::getSingleton().getLog();	int r;	mEngine = asCreateScriptEngine(ANGELSCRIPT_VERSION);	if( mEngine == 0 )	{		mLog->logMessage("Failed to create script engine.");		return;	}	RegisterScriptString(mEngine);	r = mEngine->RegisterObjectType("Log",sizeof(Ogre::Log),asOBJ_CLASS);assert( r >= 0 );	r = mEngine->RegisterObjectMethod("Log","logMessage(const string& str)",asFUNCTION(wrap_logMessage),asCALL_CDECL_OBJLAST); assert( r >= 0 );	r = mEngine->RegisterGlobalProperty("Log log",mLog);assert( r >= 0 );	r = mEngine->ExecuteString(0,"log->logMessage(\"KooKoo from angels\")");	if( r < 0 ) mLog->logMessage("Invalid script statement. ");	else if( r == asEXECUTION_EXCEPTION ) mLog->logMessage("A script exception was raised.");}

and then i get an INVALID DECLARATION(-10) assert on RegisterObjectMethod.
Do the fact that i get a namespace cause some problems?
Sorry to be so asking :(

Thanks anyway.

[Edited by - DaesDemon on August 19, 2005 7:20:03 AM]
I'm sorry. I should have noticed this in your first post. When registering parameter references, the AngelScript language requires that you add one of 'in', 'out', or 'inout' to define the intended use of the parameter. Example:

e = engine->RegisterObjectMethod("Log", "logMessage(const string& in)",asFUNCTION(wrap_logMessage),asCALL_CDECL_OBJLAST); assert( r >= 0 );


Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Also, you CAN register log* as a type. In fact, I recommend registering it with zero size, so that scripts can't create instances of it. Then you would bind a member function that accepts a log* and does the logging, and bind a global property that you tell AS is of type log but is really a log*. One of the most important things to remember when working with AS is that scripts can have a very different interface to the same objects as the application - a function doesn't have to actually be a member in C++ to be bound as a member in AS, nor does an object in AS need to be the type it looks like. In my system, I have some functions that look like member functions to AS - except that the objects they are on aren't really objects but smart pointers, and the bound member function is just a wrapper that derefrences the pointer and makes the call. WL could certainly expand a great deal on this technigue.
Thanks WitchLord and Deyja for quick answering.

@WitchLord:
I spot about the in,out and inout for the reference passed as parameters as you explain to me.
So i tried:
r = mEngine->RegisterObjectMethod("Log", "logMessage(const string& in)",asFUNCTION(wrap_logMessage),asCALL_CDECL_OBJLAST); assert( r >= 0 );

but i get the same assert
I tried also:
	r = mEngine->RegisterObjectMethod("Log","logMessage(const string& in,int e,bool b)",asMETHOD(Ogre::Log, logMessage),asCALL_THISCALL);assert( r >= 0 );...	r = mEngine->ExecuteString(0,"log.logMessage(\"KooKoo from angels\",2,false)");

Assert again in registering the method.
This one works:
	r = mEngine->RegisterObjectType("Log",sizeof(Ogre::Log),asOBJ_CLASS);	r = mEngine->RegisterGlobalProperty("Log log",mLog);assert (r >= 0);	r = mEngine->RegisterGlobalFunction("void logMessage(string &in,Log &in)",asFUNCTION(wrap_logMessage),asCALL_CDECL);assert( r >= 0 );	r = mEngine->ExecuteString(0,"logMessage(\"KooKoo from angels\",log)");
but as soon as i try to register it as a Class Method, it asserts.

@Deyja:
Do you mean i should register Log AND Log*,
like that:
r = mEngine->RegisterObjectType("Log",sizeof(Ogre::Log),asOBJ_CLASS);assert( r >= 0 );r = mEngine->RegisterObjectType("Log*",0,asOBJ_PRIMITIVE);assert( r >= 0 );... What should i register there ...r = mEngine->RegisterGlobalProperty("Log log",mLog);assert( r >= 0 );r = mEngine->ExecuteString(0,"log.logMessage(\"KooKoo from angels\")");

Could you explain that:
Quote:
Then you would bind a member function that accepts a log* and does the logging


I understand:
Quote: a function doesn't have to actually be a member in C++ to be bound as a member in AS
as WitchLord Explain to me with the wrapper function registered as a member but i am hurt by:
Quote: nor does an object in AS need to be the type it looks like
Do you mean as the scriptstring which can be used as std::string as the std:string buffer is the first Property in the class?

[Edited by - DaesDemon on August 19, 2005 8:56:20 AM]
Advertisement
Oh i get it, i forget to put the return type in my declaration function in the Registering Method.

I have something working now :D
Thanks to put me in the starting block mates.
Yeah, I too just noticed that you didn't have the return type in the declaration. I really should have noticed this before, but I'm a bit distracted by other issues here at work. ;)

Quote:
Quote:nor does an object in AS need to be the type it looks like

Do you mean as the scriptstring which can be used as std::string as the std::string buffer is the first Property in the class?


He meant that as AngelScript only knows what the application tells it, the application could tell AngelScript to treat an C++ type as a completely different type. You could for example register a type like this:

engine->RegisterObjectType("LogPtr", 0, asOBJ_PRIMITIVE);engine->RegisterObjectMethod("LogPtr", "void DoSomething()", asFUNCTION(DoSomething), asCALL_CDECL_OBJLAST);void DoSomething(Log **log){  (*log)->DoSomething();}


This would allow you to treat the actual pointer, as if it where an object in the scripts. You would register a global property of this type like this:

Log *log;engine->RegisterGlobalProperty("LogPtr log", &log);


Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Oki i think i get it .
And then i could use in AngelScript

log.doSomething() like this.

log would looks like it would be a Log& but in fact it is a Log** in angelscript.

Thanks ,
Now i will try to incorporate all that in my interface.
Just for information, i would like to use AngelScript to be able to create my interface completly from script.

This topic is closed to new replies.

Advertisement