Sign in to follow this  

Get asIObjectType of built-in type

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, I'm new to angelscript library. I try to make such task as passing array from application to script using scriptarray add-on. So I suppose I need this 

static CScriptArray *Create(asIObjectType *ot);

to create array on application side.

But I can't get asIObjectType for built-in types.

 

That's what I do (minimized example):

#include <angelscript.h>
#include <cstdio>

int main()
{
    asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
    int intTypeId = engine->GetTypeIdByDecl("int");
    
    if (intTypeId < 0)
    {
        printf("Type id is invalid\n");
    }
    else
    {
        asIObjectType* intType = engine->GetObjectTypeById(intTypeId);
        if (!intType)
        {
            printf("Can't retrieve type\n");
        }
    }
    engine->Release();
    return 0;
}

While it can retrieve type id with GetTypeIdByDecl, but GetObjectTypeById returns null. 

I use 2.29.0 version of angelscript.

Share this post


Link to post
Share on other sites

Primitive types are not object types, so it is not possible to get an object type for them. However, you don't need it. To construct the array you need the object type of the array itself, not the elements.

 

See the example from the manual:

 

// Registered with AngelScript as 'array<string> @CreateArrayOfString()'
CScriptArray *CreateArrayOfStrings()
{
  // If called from the script, there will always be an active
  // context, which can be used to obtain a pointer to the engine.
  asIScriptContext *ctx = asGetActiveContext();
  if( ctx )
  {
    asIScriptEngine* engine = ctx->GetEngine();
 
    // The script array needs to know its type to properly handle the elements.
    // Note that the object type should be cached to avoid performance issues
    // if the function is called frequently.
    asIObjectType* t = engine->GetObjectTypeByDecl("array<string>");
 
    // Create an array with the initial size of 3 elements
    CScriptArray* arr = CScriptArray::Create(t, 3);
    for( asUINT i = 0; i < arr->GetSize(); i++ )
    {
      // Set the value of each element
      string val("test");
      arr->SetValue(i, &val);
    }
 
    // The ref count for the returned handle was already set in the array's constructor
    return arr;
  }
  return 0;
}

 

Regards,

Andreas

Share this post


Link to post
Share on other sites

Thanks, I missed manual somehow. But now I got segmentation fault if I register created array as 

array<string>@ myArr

but this works:

array<string> myArr

The full code snippet:

#include <angelscript.h>
#include "scriptstdstring/scriptstdstring.h"
#include "scriptbuilder/scriptbuilder.h"
#include "scriptarray/scriptarray.h"
#include <cstdio>
#include <string>
#include <cassert>

CScriptArray *CreateArrayOfStrings(asIScriptEngine* engine)
{
    asIObjectType* t = engine->GetObjectTypeByDecl("array<string>");
    assert(t);
    CScriptArray* arr = CScriptArray::Create(t, 3);
    assert(arr);
    for( asUINT i = 0; i < arr->GetSize(); i++ )
    {
        std::string val("test");
        arr->SetValue(i, &val);
    }
    return arr;
}

void writeln(const std::string &msg)
{
    fprintf(stderr, "%s\n", msg.c_str());
}

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);
}

int main()
{
    asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
    int r = engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL); assert( r >= 0 );
    
    RegisterStdString(engine);
    RegisterScriptArray(engine, true);
    r = engine->RegisterGlobalFunction("void writeln(const string &in)", asFUNCTION(writeln), asCALL_CDECL); assert( r >= 0 );
    
    CScriptArray* myArr = CreateArrayOfStrings(engine);
    r = engine->RegisterGlobalProperty("array<string>@ myArr", myArr); assert(r >= 0);
    
    CScriptBuilder builder;
    r = builder.StartNewModule(engine, "MyModule"); 
    if( r < 0 ) 
    {
        printf("Unrecoverable error while starting a new module.\n");
        return 1;
    }
    r = builder.AddSectionFromFile("test.as");
    if( r < 0 )
    {
        printf("Please correct the errors in the script and try again.\n");
        return 1;
    }
    r = builder.BuildModule();
    if( r < 0 )
    {
        printf("Please correct the errors in the script and try again.\n");
        return 1;
    }
    
    asIScriptModule *mod = engine->GetModule("MyModule");
    asIScriptFunction *func = mod->GetFunctionByDecl("void main()");
    if( func == 0 )
    {
        printf("The script must have the function 'void main()'. Please add it and try again.\n");
        return 1;
    }
    
    asIScriptContext *ctx = engine->CreateContext();
    
    ctx->Prepare(func);
    r = ctx->Execute();
    if( r != asEXECUTION_FINISHED )
    {
        // The execution didn't complete as expected. Determine what happened.
        if( r == asEXECUTION_EXCEPTION )
        {
            // An exception occurred, let the script writer know what happened so it can be corrected.
            printf("An exception '%s' occurred. Please correct the code and try again.\n", ctx->GetExceptionString());
        }
    }
    
    ctx->Release();
    myArr->Release();
    engine->Release();
    return 0;
} 

Script code:

void main()
{
    for( uint n = 0; n < myArr.length(); n++ )
        writeln(myArr[n]);
}
 

I got seg fault in

asUINT CScriptArray::GetSize() const
{
	return buffer->numElements;
} 

Is it intended behavior?

Share this post


Link to post
Share on other sites


CScriptArray* myArr = CreateArrayOfStrings(engine);
r = engine->RegisterGlobalProperty("array<string>@ myArr", myArr); assert(r >= 0);

 

You're registering the array with incorrect level of indirection. 

 

When the declaration is a @ (handle) the second argument must be an address of a pointer, i.e:

 

CScriptArray* myArr = CreateArrayOfStrings(engine);
r = engine->RegisterGlobalProperty("array<string>@ myArr", &myArr); assert(r >= 0);

 

If the declaration is not a @, then the second argument should be the address to the actual object/value, e.g:

 

CScriptArray* myArr = CreateArrayOfStrings(engine);
r = engine->RegisterGlobalProperty("array<string> myArr", myArr); assert(r >= 0);
 

 

Unfortunately there is no way for AngelScript to detect the wrong level of indirection in the registration, so the application developer will need to pay extra attention here.

Share this post


Link to post
Share on other sites

Oh, comment in the example confused me. I mean this:

// Registered with AngelScript as 'array<string> @CreateArrayOfString()'

It made me think that pointer is already 'handle' because of '@' and that I don't need to pass reference to pointer, but just pointer.

Edited by FreeSlave

Share this post


Link to post
Share on other sites

A handle in AngelScript is basically the same as a pointer in C++. The indirection level is the same, as in a handle refers to an object, in the same way that a pointer refers to an object. The difference is that the handle will automatically increment/decrement the reference count to the object, and a handle can only refer to valid objects or null.

 

I guess the confusion is with RegisterGlobalProperty itself (you're not the first one to get confused with how it works). It has to get an address to the value of the declared type, so the script can see the same value that the application sees even if the application later changes that value. That's why when registering a global property as a handle you have to give the address of the handle, and not the handle itself.

Share this post


Link to post
Share on other sites

Thanks, I think, I got it. I always should pass pointer to type, even if type itself is kind of pointer (like handle). This is logical.

But I still need clarification about these cases:

MyClass a;
MyClass@ b;
@b = a;

and

MyClass a;
MyClass@ b;
@b = @a;

Is there some semantics difference?

Share this post


Link to post
Share on other sites

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

If you intended to correct an error in the post then please contact us.

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