Advertisement

Problem returning reference to internal members

Started by May 30, 2014 07:27 AM
4 comments, last by WitchLord 10 years, 5 months ago

I've tried searching around google for this and couldn't find anything, so I apologize if this is a repeat.

I'm have a problem returning a reference to an internal class in AngelScript.

Basically I have a class like this:


class Engine
{
public:
    AudioSystem& getAudioSystem()
    {
        return m_audioSystem;
    }
private:
    AudioSystem m_audioSystem;
};
I instance the Engine class once for the whole program. I don't need to create/destroy Engine or AudioSystem from scripts, just access some functions
I'm exposing it like this:

     int r= state->RegisterObjectType("Engine", 0, asOBJ_REF | asOBJ_NOCOUNT);
     r = state->RegisterObjectMethod("Engine", "AudioSystem@ getAudioSystem()", asMETHODPR(Engine, getAudioSystem, (), AudioSystem&), asCALL_THISCALL); assert(r >= 0);

and AudioSystem like this


int result = state->RegisterObjectType("AudioSystem", 0, asOBJ_REF | asOBJ_NOCOUNT);
result = state->RegisterObjectMethod("AudioSystem", "bool addSound(const string &in, const string &in, const bool overwriteExisting = true, const bool useStoredPath = true, const bool isSoundEffect = false, const string extension = \".mp3\")",
		asMETHOD(AudioSystem, addSound), asCALL_THISCALL);

	result = state->RegisterObjectMethod("AudioSystem", "void playSound(const string &in, const int channel = 0, const bool loop = true, const float vol = 1.0)",
		asMETHOD(AudioSystem, playSound), asCALL_THISCALL);

My angelscript looks like this


void main()
{
	AudioSystem& as = engine.getAudioSystem();//.addSound("Dive into the Heart", "Dive into the Heart");
	as.addSound("Dive into the Heart", "Dive into the Heart");
	as.playSound("Dive into the Heart");
}
When I do this, I get an error
ERR | 'AudioSystem' is not declared
I tried playing around with handles in the angelscript, figuring I needed to use a @ handle not &. I changed it to

AudioSystem@ as = engine.getAudioSystem();
When I do this I get a nondescript error "Caught an exception from the application". So clearly I'm still doing something wrong.
Lastly, I tried changing me expose from asMETHODPR to asMETHOD

r = state->RegisterObjectMethod("Engine", "AudioSystem@ getAudioSystem()", asMETHOD(Engine, getAudioSystem), asCALL_THISCALL); assert(r >= 0);

Doing this seems to let me go further - I get in to the as.addSound() function call, but the AudioSystem instance it get's called on is uninitialized and not the AudioSystem instance inside Engine.

What am I doing wrong? Any help would be appreciated.

Thanks!

The & cannot be used in variable declarations in AngelScript. Instead you should use the @ symbol.

I think your problem lies with how you've registered the global property 'engine'. I suspect that you're probably giving the wrong address to AngelScript, but unfortunately you didn't show us how you've declared the global instance of your Engine in your application nor how you're making the call to RegisterGlobalProperty.

Please show how you expose the global instance of your Engine to the script so we can verify if it is correct.

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'm exposing it like this:


void registerEngine(asIScriptEngine* state, Engine* engine)
{
    //class definition export code here
    registerObjectToAngelScript<Engine>(state, "engine", "Engine", *engine, true, false);
}


template <class T>
int registerObjectToAngelScript(asIScriptEngine* scriptCtx, const std::string& index, const std::string& objType, T& object, const bool byPtr = true, const bool isConst = false)
{
	std::string objDeclaration((isConst ? "const " : "") + objType + " " + (byPtr ? "@" : "") + index);
	return scriptCtx->RegisterGlobalProperty(objDeclaration.c_str(), &object);
}

my objDeclaration sctring ends up looking like this:


objDeclaration: "Engine @engine"
Indeed. With this declaration you need to pass in a pointer to a pointer to the Engine when calling RegisterGlobalProperty. But from your code you seem to pass only a pointer to the Engine.

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

Hm yea when I pass a pointer only, it gives me a new/incorrectly initialized instance of Engine, so I changed the registration to


template <class T>
int registerObjectToAngelScript(asIScriptEngine* scriptCtx, const std::string& index, const std::string& objType, T& object, const bool byPtr = true, const bool isConst = false)
{
	std::string objDeclaration((isConst ? "const " : "") + objType + " " + (byPtr ? "@" : "") + index);
	T* objPtr = &object;
	return scriptCtx->RegisterGlobalProperty(objDeclaration.c_str(), &objPtr);
}

to make a pointer to a pointer. Now though, the engine instance is null (or the equivalent, 0xcccccccc in visual studio). Maybe I misunderstood what you meant?

The problem now is that you're giving the pointer to a local variable. The variable will go out of scope as soon as your function returns turning the pointer invalid.

If you prefer not to register a pointer to a pointer to the Engine, you can also change the declaration to remove the @, and then pass a pointer to the Engine directly.

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