Advertisement

About CScriptHandle

Started by June 18, 2012 09:31 PM
9 comments, last by WitchLord 12 years, 5 months ago
Hi,

i use CScriptHandle like this


CScriptHandle handle;
asIScriptObject *obj = Npcs[id]->scriptObject->object;
handle.opAssign(obj, Npcs[id]->scriptObject->type->GetTypeId());
obj->Release();
return handle;


script

TestShip @npc = cast<TestShip@>(AI.GetNpcScriptHandle(second.id));
if(npc is null)
dbg("FAIL!");


first question:

asIScriptObject stored in CScriptHandle is already created way before being used by CScriptHandle.
i continuously use asIScriptObject to find which script object is associated with npc.
i dont get the call obj->Release(); (without it, Kept by application error)
if CScriptHandle holds a ref wont it be released when it goes out of scope, why do i need to call release on my precious object?

second question:

TestShip class is inherited from NpcShip
so when i cast it like this

NpcShip @npc = cast<NpcShip@>(AI.GetNpcScriptHandle(second.id));

@npc is always null, it cant cast it.
i am assuming this expected behaviour.
if so, how should i achieve this cast? (very important since i cant really know object type, only its base class)

Thank you.
Question 1:

I agree with you. Calling Release() shouldn't be needed here. I'll have to check what is happening.

As a side note. I'll need to implement a Set() method to be used from the application instead of opAssign(). opAssign() only works if there is an active context (in your case I guess there is as you didn't get a null-pointer-access exception).

Question 2:

The CScriptHandle doesn't have the intelligence yet to see that the TestShip also is a NpcShip. The CScriptHandle::opCast() method needs to implement this with call to engine->IsHandleCompatibleWithObject().

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
I tested the scenario for returning a CScriptHandle, the following function is working properly:



static CScriptHandle ReturnRef()
{
asIScriptContext *ctx = asGetActiveContext();
asIScriptEngine *engine = ctx->GetEngine();
asIScriptModule *mod = engine->GetModule("test");
int typeId = mod->GetTypeIdByDecl("CTest");

asIScriptObject *obj = reinterpret_cast<asIScriptObject *>(engine->CreateScriptObject(typeId));

CScriptHandle ref;
ref.opAssign(obj, typeId);

// Need to release our reference as the CScriptHandle counts its own, and we will not keep our reference
obj->Release();

return ref;
}


The function is registered with:



engine->RegisterGlobalFunction("ref @ReturnRef()", asFUNCTION(ReturnRef), asCALL_CDECL);


and the script that called it looks like this:



class CTest
{
int val;
CTest()
{
val = 42;
}
}
void func()
{
ref @r = ReturnRef();
assert( r !is null );
CTest @t = cast<CTest>(r);
assert( t !is null );
assert( t.val == 42 );
}



Observe, that in this function I really do have to call Release() because the application creates the instance in the call and won't keep a reference to the object that will be returned by the CScriptHandle.

In your case, as the application will hold on to the reference even after the return, the Release() method should not be called.

My guess is that the Release() is missing in some other place, probably when you're cleaning up your C++ Npcs, which is when the script object needs to be destroyed too.

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

you are right, physics callback of a projectile was holding a reference to npc even though it should not.
Thank you.

on the second issue.
i try to handle the cast issue by using CScriptAny, since i saw in implementation that it checks for IsHandleCompatibleWithObject


int tid = Npcs[id]->scriptObject->type->GetTypeId();
tid |= asTYPEID_OBJHANDLE; // make type id a handle,
asIScriptObject **o = &obj; // CScriptAny expects a handle, so give it a pointer to a pointer, it will derefence it as i understand it
CScriptAny *myAny = new CScriptAny(o, tid, engine);
return myAny;

script

NpcShip @npc;
any a = AI.GetNpcScriptHandleAsAny(second.id);
a.retrieve(@npc); // returns false


this fails at IsHandleCompatibleWithObject. doesnt think TestShip is an NpcShip. ( script side casting works)

should i stop trying to work around it till you finish CScriptHandle smile.png

edit:

TestShip @npc; // not NpcShip (base)
any a = AI.GetNpcScriptHandleAsAny(second.id);
a.retrieve(@npc);

works. but,
NpcShip @npc; a.retrieve(@npc); doesnt
I just checked in the changes for CScriptHandle. Besides supporting polymorphing for script classes I also made some other changes for the C++ interface that should hopefully make slightly easier to use.

You can find it at the head revision in the SVN.

Let me know if it works or if you face any troubles with it.

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

Thank you for your trouble, but it doesnt work :(

it is same problem as i mentioned in my previous post about CScriptAny.

IsHandleCompatibleWithObject does not accept types as compatible.
CScriptAny is stuck at the same place too

here is how class inheritance looks like,

class NpcBase
{
// npc related stuff, like handles to c++ objects
};

class NpcShip : NpcBase
{
// ship related stuff
};

class TestShip : NpcShip
{
// individual npc ship
};


here i cast in script, this works

TestShip ship;
TestShip @shipHandle = @ship;

NpcShip @baseShip;
@baseShip = cast<NpcShip>(shipHandle);

if(baseShip !is null)
dbg("success!");

prints success

i use it like this

NpcShip @npc;
@npc = cast<NpcShip>(AI.GetNpcScriptHandle(second.id)); // GetNpcScriptHandle returns TestShip@


Casting it to NpcBase also does not work. Casting to TestShip continues to work with new Cast method.

i thought maybe i made a mistake in my c++ code, so i tried this script

TestShip ship;
TestShip @handle = @ship;
any shipAny;
shipAny.store(@handle);
NpcShip @base;
shipAny.retrieve(@base);

if(base is null)
dbg("Fail");

prints Fail.

now i m pretty sure IsHandleCompatibleWithObject doesnt return true when it should.

sorry for the long verbose code
Advertisement
Yes, it's possible the method has a bug. Yesterday I only tested with Interfaces. I'll add a test for inherited classes too.

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

You were right. IsHandleCompatibleWithObject was completely ignoring the inheritance.

It's just a small change to fix this:



bool asCScriptEngine::IsHandleCompatibleWithObject(void *obj, int objTypeId, int handleTypeId) const
{
// if equal, then it is obvious they are compatible
if( objTypeId == handleTypeId )
return true;

// Get the actual data types from the type ids
asCDataType objDt = GetDataTypeFromTypeId(objTypeId);
asCDataType hdlDt = GetDataTypeFromTypeId(handleTypeId);

// A handle to const cannot be passed to a handle that is not referencing a const object
if( objDt.IsHandleToConst() && !hdlDt.IsHandleToConst() )
return false;

if( objDt.GetObjectType() == hdlDt.GetObjectType() )
{
// The object type is equal
return true;
}
else if( objDt.IsScriptObject() && obj )
{
// There's still a chance the object implements the requested interface
asCObjectType *objType = ((asCScriptObject*)obj)->objType;
if( objType->Implements(hdlDt.GetObjectType()) )
return true;

// ---> Add this
// It may also be an inheritance
if( objType->DerivesFrom(hdlDt.GetObjectType()) )
return true;
}

return false;
}


I'll have this fix checked in tonight.

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

thank you casting works.

but a new bug appears :)

this is from test_addon_scripthandle.cpp file

r = ExecuteString(engine, "ref @r = ReturnRef(); \n"
"assert( r !is null ); \n"
"CTest @t = cast<CTest>(r); \n"
"assert( t !is null ); \n"
"assert( t.val == 42 ); \n", mod);

this test works.

but when change it like that

r = ExecuteString(engine, "ref @r = ReturnRef(); \n"
"assert( r !is null ); \n"
"CTest @t = cast<CTest>(ReturnRef()); \n" // use ReturnRef() directly
"assert( t !is null ); \n"
"assert( t.val == 42 ); \n", mod);


it causes an assertion at this line :
line number: 917 as_compiler.cpp
asASSERT( tempVariables.GetLength() == 0 );
Thanks. This is probably a bug with the asOBJ_ASHANDLE feature. I'll look into it.

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