Advertisement

Problem: Attempting to pass around a void* as a handle within Angelscript.

Started by June 24, 2013 10:27 PM
0 comments, last by WitchLord 11 years, 5 months ago

The Problem

I've attempted to register an object method ( asEngine_RegisterObjectMethod ) that takes in a GlobalData* and a uint, than returns a ref type. Something about returning the ref however seems to cause the function to pass in an invalid pointer as the first parameter. Modifying the function to return a non-generic type seems to correct the problem.

What I am trying to do -- Bigger Picture

I want to retrieve some data in the form of a void* and easily pass it around to various other bound functions.

In this simple example I want to retrieve a void* from an object as a generic handle, cast that handle, than pass that handle to another C-style function.

I want to able to return a void* as a ref ( or ref@, not sure since ref seems to be a special case), then cast that to a Entity@ and pass it along to a registered function that can take an Entity*.

I'd also like to avoid needing the user to register a cast function if they don't need to. It seems like CScriptHandle can already be casted from one handle type to another.

This is ideally how I want the angelscript to look when the user attempts to get/pass around the data.


GLOBALDATA@ GlobalData = GetGlobalData();
ENTITY@ Entity = cast<ENTITY>(GlobalData.GetData( 2 ));
if( Entity !is null ){
    Entity_ProcessEntity( Entity );
}

I have registered the CScriptHandle type with the asEngine, however I seem to be missing something important during the implementation as things are not working as expected.

This is what the simplified C++ modules look like.


static class GlobalData
{
public:
   void* GetData( uint index ){ return _data[index]; }

private:
   void** _data[10];
} GlobalDataInstance;


//C-Style interface for GlobalData
GlobalData* GlobalData_GetGlobalData( void ){
    return &GlobalDataInstance;
}

void* GlobalData_GetData( GlobalData* globalData, uint index ){
   return globalData->GetData(index);
}

void Entity_ProcessEntity( Entity* entity ){
    entity->DoWork();
}

This is how they are registered with asEngine


Result = asEngine_RegisterGlobalFunction( Engine, "GLOBALDATA@ GetGlobalData()", asFUNCTION_t( &GlobalData_GetGlobalData), asCALL_CDECL );
Result = asEngine_RegisterObjectType( Engine, "GLOBALDATA", 0, asOBJ_REF | asOBJ_NOCOUNT );
Result = asEngine_RegisterObjectMethod( Engine, "GLOBALDATA",   "ref GetData( uint Index) const",  asFUNCTION_t(&GlobalData_GetData), asCALL_CDECL_OBJFIRST );

Result = asEngine_RegisterGlobalFunction( Engine, "void Entity_ProcessEntity( ENTITY@ entity)", asFUNCTION_t( &Entity_ProcessEntity), asCALL_CDECL );

asEngine_RegisterObjectMethod( Engine, "GLOBALDATA", "ref GetData( uint Index) const", asFUNCTION_t(&GlobalData_GetData), asCALL_CDECL_OBJFIRST );
This seems to be where the problem is occuring. The GlobalData* provided here is not valid. It is not null, however it is not GlobalDataInstance.

It could be that CScriptHandle is not the right solution for what i want to do, which is why I've included all of the additional information.

CScriptHandle is a C++ class and not a simple pointer. When you tell AngelScript that a function returns a "ref", then AngelScript will expect to receive a valid CScriptHandle object, but in your case you're just returning a void*. The calling convention for returning an object by value is different from the calling convention for returning a pointer. In the former a hidden pointer to a memory buffer is passed as the first argument to the function. This is why you see an invalid pointer.

If you want to use a completely generic pointer like void* in C/C++, then it would be best for you to register void* as a type itself. Then you can register your functions that take and receive void* using this type:

asEngine_RegisterObjectType(engine, "void_ptr", sizeof(void*), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE);
asEngine_RegisterObjectMethod( Engine, "GLOBALDATA",   "void_ptr GetData( uint Index) const",  asFUNCTION_t(&GlobalData_GetData), asCALL_CDECL_OBJFIRST );

As for casting the void_ptr into valid handles; I think it is best for you to create an appropriate function for this. If you do not want to have one function for each possible cast type, then I suggest you implement a function that takes a variable argument type, similar to the CScriptAny::Retrieve method. The problem is that the void* doesn't carry any information about the type of the object it points to, so I have no idea how you plan on validating if the cast is valid or not.

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