Registering struct and object handle problem
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:
http://codepad.org/vb5ltPRX
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:
http://codepad.org/UC8Qp8rb
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.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
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:
http://codepad.org/qgDNqjIw
And here is how i register the unitobserver methods and how i register the object types:
http://codepad.org/GsuZJigI
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.
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.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
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.
Please contact the application's support team for more information.
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc[/quote]
any final advice?
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.
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?
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
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
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
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 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.
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