Sign in to follow this  
jedjed

Calling Script Function with by value types

Recommended Posts

jedjed    100
Hi I'm having an issue when I try to call this script function: r = mEngine->RegisterObjectType("Entity", sizeof(IEntityPtr), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CDA ); bool entityCallback(IEntityPtr perm) { int id=mModule->GetFunctionIdByDecl("bool entityCallback(Entity)"); mContext->Prepare(id); mContext->SetArgObject(0, &perm); int r = mContext->Execute(); } mContext->Execute(); returns -1 even if the implementation in the script is empty. Just: bool entityCallback(Entity ent) { return(true); } What am I doing wrong?

Share this post


Link to post
Share on other sites
SiCrane    11839
Is IEntityPtr a smart pointer? If so, then it shouldn't be registered as asOBJ_POD and you should also register object behaviors like construct, destroy and assign.

Share this post


Link to post
Share on other sites
jedjed    100
So I've tried this many different ways but it still isn't working. What is the proper way to do this?

I want my app to call a script function and pass it what is a shared_ptr in my app. This shared_ptr will obviously exist for the length of the call into the script and the scripts wont use it outside of the call. So it seems like the memory management stuff isn't necessary.

But if it still is how do I create the value type properly when the value is a shared_ptr in my app?

Share this post


Link to post
Share on other sites
SiCrane    11839
asOBJ_POD can be used when the object is a POD type. Primitives are POD and a C++ class type is POD when it has no user defined constructor, destructor or assignment operator and also doesn't contain any non-POD members. boost::shared_ptr isn't POD because it defines constructors, a destructor and an assignment operator. To register a shared_ptr properly you'll to register it as a value type without the asOBJ_POD flag, as well as register the asBEHAVE_CONSTRUCT and asBEHAVE_DESTRUCT object behaviors and the opAssign object method.

Share this post


Link to post
Share on other sites
jedjed    100
Sorry to keep asking about this. The -1 thing was because I was calling the script function using an active context. Now that is fixed but now I'm getting garbage for the value types when they are passed back to my app.

So I must not be registering the Constructor,Destructor or assignment correctly. This is what I'm doing:

typedef boost::shared_ptr<IEntity> IEntityPtr;
r = mEngine->RegisterObjectType("Entity", sizeof(IEntityPtr), asOBJ_VALUE | asOBJ_APP_CLASS_CDA );

r = mEngine->RegisterObjectBehaviour("Entity", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(IEntityPtrConstructor), asCALL_CDECL_OBJLAST);

r = mEngine->RegisterObjectBehaviour("Entity", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(IEntityPtrDestructor), asCALL_CDECL_OBJLAST);

r = mEngine->RegisterObjectMethod("Entity", "Entity &opAssign(const Entity &in)", asMETHODPR(IEntityPtr, operator=, (const IEntityPtr&), IEntityPtr&), asCALL_THISCALL);

void IEntityPtrConstructor(void* memory)
{
new(memory) IEntityPtr();
}

void IEntityPtrDestructor(void* memory)
{
((IEntityPtr*)memory)->~IEntityPtr();
}

Share this post


Link to post
Share on other sites
SiCrane    11839
How are you passing them back to your application? This works for me:

#include "angelscript.h"
#include "scriptstdstring.h"

#include <iostream>
#include <cassert>
#include <cstdio>

#include <boost/shared_ptr.hpp>

struct Test {
int data;
};

typedef boost::shared_ptr<Test> TestPtr;

template <typename T>
void construct(void * memory) {
new (memory) T();
}

template <typename T>
void destroy(void * memory) {
((T *)memory)->~T();
}

void MessageCallback(const asSMessageInfo *msg, void *param)
{
const char *type = "ERR ";
if( msg->type == asMSGTYPE_WARNING )
type = "WARN";
else if( msg->type == asMSGTYPE_INFORMATION )
type = "INFO";

printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
}

void print(std::string & str) {
std::cout << str;
}

int main(int, char **) {
asIScriptEngine * engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);
RegisterStdString(engine);

int r;

r = engine->RegisterObjectType("TestPtr", sizeof(TestPtr), asOBJ_VALUE | asOBJ_APP_CLASS_CDA); assert(r >= 0);
r = engine->RegisterObjectBehaviour("TestPtr", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(construct<TestPtr>), asCALL_CDECL_OBJLAST); assert(r >= 0);
r = engine->RegisterObjectBehaviour("TestPtr", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(destroy<TestPtr>), asCALL_CDECL_OBJLAST); assert(r >= 0);
r = engine->RegisterObjectMethod("TestPtr", "TestPtr & opAssign(const TestPtr & in)", asMETHODPR(TestPtr, operator=, (const TestPtr &), TestPtr &), asCALL_THISCALL); assert(r >= 0);

r = engine->RegisterGlobalFunction("void print(string & in)", asFUNCTION(print), asCALL_CDECL); assert( r >= 0 );

const char script[] =
"TestPtr foo(TestPtr t) {\n"
" return t;\n"
"}\n"
;

asIScriptModule * mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
r = mod->AddScriptSection("script", script, sizeof(script) - 1); assert(r >= 0);
r = mod->Build(); assert(r >= 0);

int func_id = mod->GetFunctionIdByDecl("TestPtr foo(TestPtr t)"); assert(func_id >= 0);
asIScriptContext * ctx = engine->CreateContext();

TestPtr test(new Test);

test->data = 5;

r = ctx->Prepare(func_id); assert(r >= 0);
r = ctx->SetArgObject(0, &test); assert(r >= 0);
r = ctx->Execute(); assert(r >= 0);

TestPtr ret_val = *((TestPtr *)ctx->GetAddressOfReturnValue());
std::cout << ret_val->data << std::endl;
assert(test.get() == ret_val.get());

ctx->Release();
engine->Release();
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this