Sign in to follow this  
benishor

Returning and assigning object references

Recommended Posts

I was looking for a lightweight scripting system to implement in a 2d space shooter arcade that I'm trying to build in my spare time and after taking a look at lua + derivatives ) and squirrel I came across angel script. The are some reasons I've chosen angel script over squirrel. I love it's syntax and the way registering works, allowing me to register already existent classes whilst not forcing me to write methods aware of the virtual machine state, stack and such. I did happen to get to a problem though. I don't know if this is possible. What I'm trying to do is to export an already created object's reference into the script. Sample script follows ( sorry for the length )

// c++

class aManager
{
    public:

        aManager();
        ~aManager();

        void Print();
        void SetProperty( int aValue );


        aManager GetNew()
        {
            return aManager();
        }

        int GetProperty();
        int m_Property;
};


aManager::aManager()
{
    m_Property = 10;
    printf( "constructing new object with pointer %p\n", this );
}

aManager::~aManager()
{
}


void aManager::Print()
{
    printf( "%p says : %d\n", this, m_Property );
}

void aManager::SetProperty( int aValue )
{
    m_Property = aValue;
}

int aManager::GetProperty()
{
    return m_Property;
}


void aManager_Constructor( aManager *obj )
{
    new( obj ) aManager();
}

void aManager_Destructor( aManager *obj )
{
    obj->~aManager();
}

int main()
{
    asIScriptEngine *engine = asCreateScriptEngine( ANGELSCRIPT_VERSION );

    engine->RegisterObjectType( "aManager", sizeof( aManager ), asOBJ_CLASS | asOBJ_CLASS_CONSTRUCTOR | asOBJ_CLASS_DESTRUCTOR );

    engine->RegisterObjectBehaviour( "aManager", asBEHAVE_CONSTRUCT, "void aManager()", asFUNCTION(aManager_Constructor), asCALL_CDECL_OBJLAST );
    engine->RegisterObjectBehaviour( "aManager", asBEHAVE_DESTRUCT, "void aManager()", asFUNCTION(aManager_Destructor), asCALL_CDECL_OBJLAST );

    engine->RegisterObjectProperty( "aManager" , "int m_Property", offsetof( aManager, m_Property ) );

    engine->RegisterObjectMethod( "aManager", "void SetProperty( int )", asMETHOD(aManager,SetProperty), asCALL_THISCALL );
    engine->RegisterObjectMethod( "aManager", "int GetProperty()", asMETHOD(aManager,GetProperty), asCALL_THISCALL );
    engine->RegisterObjectMethod( "aManager", "void Print()", asMETHOD(aManager,Print), asCALL_THISCALL );
    engine->RegisterObjectMethod( "aManager", "aManager GetNew()", asMETHOD(aManager,GetNew), asCALL_THISCALL );

    // load and compile script

    char  theFilename[] = "test.as";
    char *theBuffer;
    int   theLength;

    GetFileContent( theFilename, &theBuffer, &theLength );

    engine->AddScriptSection( "module", "section", theBuffer, theLength, 0 );
    delete( theBuffer );

    engine->Build( "module" );

    // create context

    asIScriptContext *theContext;
    engine->CreateContext( &theContext );

    // get function and run it

    char theFunctionDeclaration[] = "void main()";

    int theFunctionID = engine->GetFunctionIDByDecl( "module", theFunctionDeclaration );
    theContext->Prepare( theFunctionID );

    theContext->Execute();

    // clean up

    theContext->Release();

    return ( 0 );
}


and here's the script file :

// test.as file

void main()
{
    aManager obj1;

    obj1.Print();
    obj1.SetProperty( obj1.GetProperty() + 10 );
    obj1.Print();

    aManager obj2 = obj1.GetNew();
}

If we look to "aManager obj2 = obj1.GetNew();" we notice the system creates two objects instead of one. I understand this is because when declaring the type of obj2 "aManager obj2", the constructor is called automatically and I'm forced to do that because it needs to have variables declared. I was wondering though if there's any way of returning and assigning a reference of an object created in c++ to an undeclared script var. or perhaps a workaround. thank you and keep on the great work ! benishor.

Share this post


Link to post
Share on other sites
If you register the asBEHAVE_ADDREF and asBEHAVE_RELEASE behaviours, you can use object handles to hold references to the manager objects, instead of keeping unique copies in each variable.

Some changes needed:


// C++
class aManager
{
aManager() {refCount = 1; ... any other initializations needed}

int refCount;
void AddRef() {refCount++;}
void Release() {int r = --refCount; if( refCount == 0 ) delete this; return r; }

aManager *GetNew()
{
// The constructor already initializes refCount to 1
return new aManager();
}

... leave the rest as is
}

int main()
{
...

engine->RegisterObjectBehaviour("aManager", asBEHAVE_ADDREF, "void f()", asMETHOD(aManager, AddRef), asCALL_THISCALL);
engine->RegisterObjectBehaviour("aManager", asBEHAVE_RELEASE, "void f()", asMETHOD(aManager, Release), asCALL_THISCALL);

engine->RegisterObjectMethod("aManager", "aManager @GetNew()", asMETHOD(aManager,GetNew), asCALL_THISCALL);


}




// Script
void main()
{
aManager obj1;

obj1.Print();
obj1.SetProperty( obj1.GetProperty() + 10 );
obj1.Print();

aManager @obj2 = @obj1.GetNew();
obj2.Print();
obj2.SetProperty( obj2.GetProperty() + 10 );
obj2.Print();
}




Share this post


Link to post
Share on other sites
thank you it works just as intended. I guess I would have figured it out had I encountered any references to the addref and release behaviours in the "Registering a C++ class" tutorial. I guess object references would make a good tutorial subject for beginners ( like me ). I'll even write one once I get all things straight if nobody more experienced offers to.

thank you for the quick support !

Share this post


Link to post
Share on other sites
You're right. I need to update that article. It was written before I implemented object handles, which is why it doesn't mention them.

It's already difficult for me to find the time to implement all the features needed for the library, much less to write tutorials or articles. If you'd like to write tutorials or sample programs I will be more than happy to add them to the site or even to the actual SDK package if they are good enough.

Regards,
Andreas

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