# Registering struct and object handle problem

This topic is 2848 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

hey,

it's me ... again

i run into a new problem that i couldn't fix for myself. i want to register a struct to the ASengine and use that struct within scripts as parameter. i'm not quite sure if i did it correctly.

another problem is, that i get the following error:
System function (Row:1, Col:23) : ERR : Object handle is not supported for this type

when trying to use a ref registered object as parameter in a scriptfile.

here is the scriptfile:
can i use EventData@ as parameter to be able to manipulate the data within the object so the data gets manipulated in the c++ application as well? (call by reference).

here is how i register the objects so far:

what i am trying to do:
i have an observerclass that observes units in my game if the cast,attack,move,... when an event happens the EventData object will be created and the onEvent of abilities will be called to f.e. return damage to the attacker if the attacked unit has the thorn ability.

regards simon

edit: nvm guys, i could fix it myself. i was a little bit confused about the @ operator and the reference/handle thing in angelscript but i think i managed it now and understand it.
@ == * in c++ with additional features for angelscript when registering functions (f.e. @+ operator for registering)
& doesn't exist, instead you have to use &in,&out or &inout or you use the as_UNSAFE_WHATEVER config which is not recommended.

##### Share on other sites
Sorry for taking so long in responding. But it seems you've figured it out on your own anyway. From your edit-comments you seem to have understood things perfectly.

##### Share on other sites
it seems like i didn't

run into a new problem today, yeah \o/

i'm trying to run those scripts:
http://codepad.org/RpLUFjxK <-- script that initializes a unit and adds an ability to it
http://codepad.org/dkxXQmwE <-- script for the ability which registers itself as an observer for the unit to support the onEvent method

the 2 scripts are functioning, when i create the ability within the c++ application and register the ability as observer within the c++ application.
today i tried to export that functionality to angelscript but i don't get it to work.

That is how i register the gameobj_mgr singleton and methods that give the functionality for creating units/abilities:

And here is how i register the unitobserver methods and how i register the object types:

the problem i run into:
unit&in/ability&in doesn't work for handletype objects? when i run the app i get the following error:
No matching signatures to 'GameObjMgr::createAbility(string, Unit@&)'

k, so i register the method as Unit@&in instead of Unit&in. Then the next error appears within Fireball,as where it seems that angelscript doesn't know that ability inherits from unitobserver so i can't pass an ability to the method when it is registered with the unitobserver parameter.
when i change the registerparameter to ability the appliaction just crashes without an error.

i'm not quite sure how to solve this right now, so again i'm hoping for some help.

##### Share on other sites
The createAbility function was registered with Unit &in. While this is passing the object by reference, it is also saying that the function will not modify the object, so it is really analog to passing by value, in that AngelScript will make a copy of the object and pass the reference to the copy instead of the real object. The &in form is mostly only used for compatibility with C++ where most object parameters are passed by reference, even though in many cases they are not meant to be modified.

The compiler error that there is no matching signature with Unit@& is because you explicitly took the handle of the object when trying to call the function, i.e. @self. When doing so you told AngelScript that you want to do something with the handle, not the object itself, which is why it doesn't match with the Unit &in that operates on the object.

Using Unit@&in, translates to Unit** or Unit*& in C++, which is probably not what you had intended.

I believe your createAbility method should really be taking as parameter a 'Unit@', i.e. a handle to a Unit object, or if you want to force that the parameter is never null, you can use 'Unit &inout'. Both of these will make sure you receive a pointer to the actual object, and that you are allowed to modify it or even store it for later use.

As for the ability inheriting from unitobserver issue:

You have registered the unitobserver as a value type, while the ability is a reference type. That will not work. In order to be able to establish inheritance between the types they must all be reference types.

Once they are both reference types, you can establish the relationship between the two by registering implicit and explicit reference cast behaviours, to allow one type to be cast to the other.

##### Share on other sites
k, i think i managed the inheritance problem and the most part of the other problem i guess.
however after debugging a while due to a crash i found a problem in the scripline:

 GAMEOBJ_MGR.createAbility( "Default/Feuerball", self );

if i create the ability in c++ using GAMEOBJ_MGR->createAbility( "Default/Feuerball", u1 ) where u1 is a reference to a unit it works just fine so i think there might be still a problem with the registered createability method to angelscript.
i used the inout operator since i want these specific parameters to not be null.
the new registercall looks like this now

 r = _engine->RegisterObjectMethod( "GameObjMgr", "Ability& createAbility(const string&in filePath, Unit&inout forUnit)", asMETHOD(GameObjMgr,createAbility), asCALL_THISCALL ); assert( r >= 0 ); 

the new object type registering looks like this
 // Register object types r = _engine->RegisterObjectType( "Ability", 0, asOBJ_REF ); assert( r >= 0 ); r = _engine->RegisterObjectBehaviour( "Ability", asBEHAVE_ADDREF, "void f()", asMETHOD(Ability, Ability::addRef), asCALL_THISCALL ); assert( r >= 0 ); r = _engine->RegisterObjectBehaviour( "Ability", asBEHAVE_RELEASE, "void f()", asMETHOD(Ability, Ability::release), asCALL_THISCALL ); assert( r >= 0 ); r = _engine->RegisterObjectType( "Unit", 0, asOBJ_REF ); assert( r >= 0 ); r = _engine->RegisterObjectBehaviour( "Unit", asBEHAVE_ADDREF, "void f()", asMETHOD(Unit, Unit::addRef), asCALL_THISCALL ); assert( r >= 0 ); r = _engine->RegisterObjectBehaviour( "Unit", asBEHAVE_RELEASE, "void f()", asMETHOD(Unit, Unit::release), asCALL_THISCALL ); assert( r >= 0 ); r = _engine->RegisterObjectType( "Player", 0, asOBJ_REF ); assert( r >= 0 ); r = _engine->RegisterObjectBehaviour( "Player", asBEHAVE_ADDREF, "void f()", asMETHOD(Player, Player::addRef), asCALL_THISCALL ); assert( r >= 0 ); r = _engine->RegisterObjectBehaviour( "Player", asBEHAVE_RELEASE, "void f()", asMETHOD(Player, Player::release), asCALL_THISCALL ); assert( r >= 0 ); r = _engine->RegisterObjectType( "UnitObserver", 0, asOBJ_REF ); assert( r >= 0 ); r = _engine->RegisterObjectBehaviour( "UnitObserver", asBEHAVE_ADDREF, "void f()", asMETHOD(UnitObserver, UnitObserver::addRef), asCALL_THISCALL ); assert( r >= 0 ); r = _engine->RegisterObjectBehaviour( "UnitObserver", asBEHAVE_RELEASE, "void f()", asMETHOD(UnitObserver, UnitObserver::release), asCALL_THISCALL ); assert( r >= 0 ); r = _engine->RegisterObjectType( "EventData", sizeof(UnitObserver::EventData), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS ); assert( r >= 0 ); r = _engine->RegisterObjectType( "GameObjMgr", 0, asOBJ_REF | asOBJ_NOHANDLE ); assert( r >= 0 ); // set inheritance relationship between ability and unitobserver r = _engine->RegisterObjectBehaviour( "UnitObserver", asBEHAVE_REF_CAST, "Ability@ f()", asFUNCTION((refCast<UnitObserver,Ability>)), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = _engine->RegisterObjectBehaviour( "Ability", asBEHAVE_IMPLICIT_REF_CAST, "UnitObserver@ f()", asFUNCTION((refCast<Ability,UnitObserver>)), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); 

the application crashes in the following part
 asIScriptObject *AScriptMgr::createScriptUnit( const std::string& scriptPath, Unit& unit ) { int r = 0; asIScriptObject* obj = 0; ScriptUnit* scriptunit = getScriptUnitScript( scriptPath ); if( scriptunit == 0 ) return 0; asIScriptContext* ctx = prepareCtx( scriptunit->_factoryID ); ctx->SetArgObject( 0, &unit ); r = executeCall( ctx ); if( r == asEXECUTION_FINISHED ) { obj = *( (asIScriptObject**) ctx->GetAddressOfReturnValue()); obj->AddRef(); } returnCtx( ctx ); return obj; } 

at: r = executeCall( ctx );

and the problem itself occurs in the scriptline i posted above.
the error ist:
This application has requested the Runtime to terminate it in an unusual way.
terminate called after throwing an instance of 'std::bad_alloc'

regards

edit:
could it be a problem, that when a method in c++ looks like this
class& getFoo() const;
and the class is registered as asOBJ_REF that i shouldn't register it as
class& getFoo() const because the & operator in c++ is different to the & operator in as? however using &inout or &out throws the error, that it expected an identiefier, so class&inout or class&out as returnvalue seems to be unknown.

##### Share on other sites
std::bad_alloc usually means that you've encountered an out-of-memory condition. Does this happen on the first call, or only after running the application for a while?

Returning a reference in AngelScript works the same way as it does in C++. The way you registered the createAbility function is correct, assuming the C++ method looks something like this:

[source]
Ability &GameObjMgr::createAbility(const std::string &str, Unit &unit)
{
// The ability is created
Ability *ab = new Ability();

// The ability is stored somewhere, presumably in the unit
unit.StoreAbility(ab);

// A reference to the newly created ability is returned
return *ab;
}
[/source]

AngelScript will not call Release() on the returned reference (at least not without calling AddRef() first), so if you didn't store it somewhere for later release you will have a memory leak. If you had returned the Ability instance by handle (@) then AngelScript will call Release() on it after it is done with it.

You say the crash happens in the Execute() call. Does invoke the createAbility() function, or does it fail before? If it invokes the createAbility() function, do you see the expected values in the arguments?

##### Share on other sites
really appreceating your patience and help here andreas. thank you.

debugged some more and found out, that it invokes the createability method correctly. it also seems like it creates the ability correctly but the vector.push_back fails somehow.

 Ability & GameObjMgr::createAbility( const std::string & filePath, Unit& forUnit ) { Ability* a = new Ability( filePath, forUnit ); _abilities.push_back( a ); return *a; } 
_abilities.push_back(a) causes the crash. forUnit is passed correctly and a is created correctly.

gameobjmgr.hpp
 /* * GameMgr.hpp * * Created on: 18.12.2011 * Author: Simon */ #ifndef GAMEMGR_HPP_ #define GAMEMGR_HPP_ #include <string> #include <vector> #include "Unit.hpp" #include "Ability.hpp" class Player; class GameObjMgr { public: GameObjMgr(); ~GameObjMgr(); void init(); void update(); Player& createPlayer( const std::string& playerName ); void removePlayer( Player& player ); Unit& createUnit( const std::string& filePath, Player& forPlayer ); void removeUnit( Unit& unit ); Ability& createAbility( const std::string& filePath, Unit& forUnit ); void removeAbility( Ability& ability ); //addbuff protected: std::vector<Unit*> _units; std::vector<Ability*> _abilities; std::vector<Player*> _players; }; extern GameObjMgr* GAMEOBJ_MGR; #endif /* GAMEMGR_HPP_ */ 

when i comment the createability line in the unit.as script and use the following in the c++ application
 Unit& u1 = GAMEOBJ_MGR->createUnit( "Default/Frosch", p1 ); GAMEOBJ_MGR->createAbility("Default/Feuerball", u1); 
it works just fine. so the vector.pushback only fails when invoking the method by the script. could it be the problem, that i invoke createability before the scriptconstructor is finished?

edit:
maybe this helps you more. http://dl.dropbox.com/u/6414966/Spieleprogrammierung/Scion%20of%20Might%20-%20Console%20AS/Source.zip
the current sourcefiles.
included in the testscenario are unit,unitobserver,ability,gamemanager,scriptmanager and main

##### Share on other sites
That the push_back on std::vector fails tells me that the vector is either corrupt or the this pointer for GameObjMgr is invalid.

From the source code I believe it is the latest. It seems you register the global GAMEOBJ_MGR before the object has actually been created so the pointer that AngelScript has is invalid. (I actually find it strange that you didn't receive any null pointer exception from the script engine).

You need to make the call to _engine->RegisterGlobalProperty( "GameObjMgr GAMEOBJ_MGR", GAMEOBJ_MGR ); after the GAMEOBJ_MGR pointer has been initialized with the manager.

Regards,
Andreas

##### Share on other sites
and voila, we have a winner

thank you so much. that was the problem.
and no, i didn't get an error message when passing the 0 pointer of gameobj_mgr. i'm using angelscript 2.22.

##### Share on other sites
I've fixed the code so registering a global property with a null pointer will be properly detected now. The changes are in revision 1095.

Regards,
Andreas

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 9
• 11
• 15
• 21
• 26