Advertisement

Proper registration for this type?

Started by January 16, 2009 03:55 AM
9 comments, last by Wavesonics 15 years, 9 months ago
I have a type I want to register that I want to be used as such: - I should be able to pass an application instance of it to a script, and I want the script to be able to directly modify the application's instance. - I also don't want the object to be controlled by the scripts GC or reference counting. The life time of the object should be completely controlled by the application, and the script should not hold references to it. Now I've tried to register it as both of these:

r = m_engine->RegisterObjectType("Creep", sizeof(Creep), asOBJ_VALUE | asOBJ_APP_CLASS | asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR ); assert( r >= 0 );

r = m_engine->RegisterObjectType("Creep", sizeof(Creep), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS ); assert( r >= 0 );


The first isn't ideal, because I don't really want to be able to construct or destruct these objects in scripts. On this note, if I only have a non-default constructor, how do I pass arguments to it via the method described here:

void Constructor(void *memory)
{
  // Initialize the pre-allocated memory by calling the
  // object constructor with the placement-new operator
  new(memory) Object();
}

void Destructor(void *memory)
{
  // Uninitialize the memory by calling the object destructor
  ((Object*)memory)->~Object();
}

// Register the behaviours
r = engine->RegisterObjectBehaviour("val", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Constructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("val", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Destructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );


Anyway, with both of these methods, I manage to run and even compile the script, but when I attempt to use it here, things go bad:

// The Script:
void fire( Creep@ c ) {
    int h = c.health();
	c.health( h - 5 );
	print( "The creeps health is now: " );
	print( c.health() );
	print( "\n" );
}

// The point of call:
asIScriptContext* ctx = gScriptEngine.prepare( description->script, "void fire( Creep@ )" );
ctx->SetArgObject( 0, &c );
gScriptEngine.execute( ctx );


If I'm not mistaken, the @ symbol is what I want for passing things as references right? Now it prints "The creeps health is now: 5" which is perfect, but then I get a random crash in the next few lines of code. It changes what line each time I run. Clearly, the memory for the object has been corrupted. Any ideas?
==============================
A Developers Blog | Dark Rock Studios - My Site
If you don't want the script to be able to instanciate the type, then you should register the type as a reference type without any factory function. All value types must be instanciable by AngelScript.

If you also do not want the script to be able to hold any extra references to the type then you can register the type with the asOBJ_NOHANDLE flag, in which case the ADDREF and RELEASE behaviours shouldn't be registered.

If you want to allow the script to store reference to the type, but don't care about reference counting, then you can register dummy functions for ADDREF and RELEASE that doesn't do anything. In this case the application will be responsible for making sure the instance outlives all references that the script may store (for example global variables).

---

Non-default constructors are implemented as such:

void constructor(int arg, void *memory){   new(memory) Object(arg);}r = engine->RegisterObjectBehaviour("val", asBEHAVE_CONSTRUCT, "void f(int)", asFUNCTIONPR(Constructor, (int, void*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 );


You can also use asCALL_CDECL_OBJFIRST, in which case the memory pointer should be placed as the first argument.

---

The @ symbol (means 'object handle') is only available for reference types.

In fact the script you compiled should have given a compilation error when you declared the parameter as a handle to Creep, since you registered the Creep type as a value type. I'll have to look into why this didn't happen.

EDIT: This was indeed a bug. I've already found and fixed it. The fix should be available in the SVN this weekend.

[Edited by - WitchLord on January 16, 2009 7:25:12 AM]

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
Awesome, this is why I like working with a library that is so actively and personally maintained :)

Ok, I registered it as such:
    // Register our Creep    r = m_engine->RegisterObjectType("Creep", sizeof(Creep), asOBJ_REF ); assert( r >= 0 );    r = m_engine->RegisterObjectBehaviour("Creep", asBEHAVE_ADDREF, "void f()", asMETHOD(Creep, dummy), asCALL_THISCALL); assert( r >= 0 );    r = m_engine->RegisterObjectBehaviour("Creep", asBEHAVE_RELEASE, "void f()", asMETHOD(Creep, dummy), asCALL_THISCALL); assert( r >= 0 );


And everything works just fine. Pretty cool to see things happening due to scripts in my game now :)

One little nag though. I like the keep the public interface to my classes concise. So I tried using: asFunction() instead of asMETHOD(), so I could redirect to a dummy global function and keep my class clean. But it throws at the assert().

Would it be possible to support none reference counted objects in a more natural way for future versions? Maybe a flag in the type register that would automatically register dummy functions or something?
==============================
A Developers Blog | Dark Rock Studios - My Site
When you register a non-member function for object behavior, you should register the function as asCALL_CDECL_OBJFIRST or asCALL_CDECL_OBJLAST. This also requires that the function use the cdecl calling convention (rather than, for example, fastcall or stdcall).
Quote: Original post by Wavesonics
One little nag though. I like the keep the public interface to my classes concise. So I tried using: asFunction() instead of asMETHOD(), so I could redirect to a dummy global function and keep my class clean. But it throws at the assert().


Follow SiCrane's advice and you won't have to modify your classes. :)

Quote: Original post by Wavesonics
Would it be possible to support none reference counted objects in a more natural way for future versions? Maybe a flag in the type register that would automatically register dummy functions or something?


Yes, I have plans to allow this in a future version. It's a low priority though.

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

Great, thanks!

Btw, I'm not clear on the difference between:
cdecl, fastcall, or stdcall.

Though I think stdcall had to do with the MSVC++ compiler?
==============================
A Developers Blog | Dark Rock Studios - My Site
Advertisement
These are different calling conventions. The basic difference is this:

- cdecl: the arguments are pushed on the stack by the caller, and removed by the caller after the callee returns
- stdcall: the arguments are pushed on the stack by the caller, and removed by the callee before it returns
- fastcall: the arguments are placed in the registers


The default calling convention is cdecl, unless you have changed this in the project settings.

stdcall is the standard calling convention used by Microsoft's Platform SDK. Though I believe they originally inherited this calling convention from the Pascal language. stdcall is not exclusive to MSVC++, though it's less commonly used on platforms that aren't Windows based.

fastcall is as the name suggests, a faster calling convention, as there are less memory operations involved with a function call. Though it is rarely used nowadays, as the modern compilers more than enough make up for most human made optimizations.

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

Ah, great, thanks for the info!

I actually may get much deeper into this. I'm currently implementing AngelScript in a small hobby project which I am using to research new libs and techniques.

Most of which I will be implementing in my next project at work. So I may be porting AngelScript's native calling to the Wii when I use it at work.

I already wrote our Font rendering system based around your BMFont format, thanks again for that, it was a breeze!
==============================
A Developers Blog | Dark Rock Studios - My Site
Hi Wavesonics. Have you had any progress with native calling on the Wii? I'm assuming you are using CodeWarrior since you are doing this at work.

Hi Andreas. Long time no speak. It's not a coincidence that two people are asking about CodeWarrior at the same time. CliffCawley is on my team. :)
Steve 'Sly' Williams  Monkey Wrangler  Krome Studios
turbo game development with Borland compilers
Hi Sly. It has indeed been a while. So CliffCawley is with you? Now I've had the honor of getting in touch with quite a few from Krome Studios, 4 to be exact. :) I'm happy to hear that interest in AngelScript is still high over there.

I have a feeling that Wii support isn't too far away. There has been quite a lot of interest in this lately, and hopefully someone will be able to get this going soon.

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

This topic is closed to new replies.

Advertisement