Jump to content
  • Advertisement
Sign in to follow this  
slicer4ever

Angelscipt hello world problems.

This topic is 2482 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 everyone, i'm a new user to angel script, and am trying to get the bare minimum up and running for a hello world.

this is what i have so far, as i'm trying to keep it down to the absolute minimum, and do not want to use the string addon(i want to learn the inner functions, instead of just passing it off.):


#include <stdio.h>
#include <time.h>
#include <angelscript.h>
#include <string.h>
#include <new.h>

class str{
private:
char *m_str;
public:

char *to_c(void) const{
return m_str;
}

str &operator=(const str &o){
if(o.to_c()){
unsigned int l = strlen(o.to_c())+1;
if(m_str) delete[] m_str; m_str = new char[l];
memcpy(m_str, o.to_c(), sizeof(char)*l);
}
return *this;
}

str() : m_str(0x0){};

str(const str &o) : m_str(0x0){
if(o.to_c()){
unsigned int l = strlen(o.to_c())+1;
m_str = new char[l];
memcpy(m_str, o.to_c(), sizeof(char)*l);
}
}

str(const char *s) : m_str(0x0){
printf("s: %s\n", s);
unsigned int l=strlen(s)+1;
m_str = new char[l];
memcpy(m_str, s, sizeof(char)*l);
printf("Done...\n");
}

~str(){
if(m_str) delete[] m_str;
}
};


#define TST "void HelloWorld(void){ Print(\'Hello World!\'); }"

void Print(str &s){
printf("Print Called\n");
printf("'%s'\n", s.to_c());
return;
}

static str StringFactory(unsigned int l, const char *s){
printf("SFactory Called\n");
return str(s);
}

void MCallBack(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);
}

static void StrConstruct(str *Ptr){
printf("Construct Called\n");
new(Ptr) str();
}

static void StrCopy(const str &o, str *Ptr){
printf("Copy Called\n");
new(Ptr) str(o);
}

static void StrDestruct(str *Ptr){
printf("Destruct Called\n");
Ptr->~str();
}

int main(int argc, char **argv){
asIScriptEngine *Engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
if(!Engine) printf("Error Creating engine\n");
Engine->SetMessageCallback(asFUNCTION(MCallBack), 0x0, asCALL_CDECL);
Engine->RegisterObjectType("str", sizeof(str), asOBJ_VALUE|asOBJ_APP_CLASS_CDK);
Engine->RegisterStringFactory("str", asFUNCTION(StringFactory), asCALL_CDECL);
Engine->RegisterObjectBehaviour("str", asBEHAVE_CONSTRUCT, "void str()", asFUNCTION(StrConstruct), asCALL_CDECL_OBJLAST);
Engine->RegisterObjectBehaviour("str", asBEHAVE_CONSTRUCT, "void str(const str &in)", asFUNCTION(StrCopy), asCALL_CDECL_OBJLAST);
Engine->RegisterObjectBehaviour("str", asBEHAVE_DESTRUCT, "void str()", asFUNCTION(StrDestruct), asCALL_CDECL_OBJLAST);
Engine->RegisterObjectMethod("str", "str &opAssign(const str &in)", asMETHODPR(str, operator =, (const str &), str&), asCALL_THISCALL);

if( !strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) printf("Not\n");
if(Engine->RegisterGlobalFunction("void Print(str &out)", asFUNCTION(Print), asCALL_CDECL)<0) printf("Error Registering...\n");
asIScriptModule *Mod = Engine->GetModule(0x0, asGM_ALWAYS_CREATE);
//printf("Str: %d\n", strlen(TST));
if(Mod->AddScriptSection("FistScript", TST, strlen(TST))<0) printf("Error adding script...\n");
if(Mod->Build()<0) printf("Error building Mod...\n");
//printf("Build: %d\n", Mod->Build());
asIScriptContext *Cntx = Engine->CreateContext();
int FuncID = Mod->GetFunctionIdByDecl("void HelloWorld(void)");
if(FuncID<0) printf("Error, can't find HelloWorld\n");
Cntx->Prepare(FuncID);
Cntx->Execute();
Cntx->Release();
Engine->Release();
int t=time(0x0)+10;
while(time(0x0)<t);
return 0;
}


their's alot of debugging code, so please bare with it. anyway, the problem i'm getting is:

FistScript (1, 1) : INFO : Compiling void HelloWorld()
FistScript (1, 30) : WARN : Argument cannot be assigned. Output will be discarded.

i assumed the problem was because i didn't have an operator for assignment, and added that, only to be treated to the same problem.

now then, this is what i'm getting as debugging:


Not!
**Debug info above**
Construct Called
Print Called
'(null)'
SFactory Called
s: Hello World!
Done...
Destruct Called
Destruct Called


as you can see, the "Hello World!" portion is constructed after the script is executed, and is needed.

can anyone help me on figuring out what i'm doing wrong?

Share this post


Link to post
Share on other sites
Advertisement
You probably don't want Print() to take an out reference when you register it. You probably want it to be an in reference.

Share this post


Link to post
Share on other sites

You probably don't want Print() to take an out reference when you register it. You probably want it to be an in reference.


wow, i've been banging my head, going over and over the code, trying to figure it out, such a stupid oversight

thanks alot mate=-)

Share this post


Link to post
Share on other sites
alright, so i have another question, i'm working on asOBJ_REF object's, and much of my internal engine already works on the conecpt of referencing, my only problem is that much of it works like so:


class x{
public:
x *AddRef(void);
};


the problem, is that when i try to register this as the behavior like so:

Engine->RegisterObjectBehaviour("x", asBEHAVE_ADDREF, "x@ x()", asMETHOD(x, AddRef), asCALL_THISCALL)


and i get the error:

(0, 0) : ERR : Failed in call to function 'RegisterObjectBehaviour' with 'x' and 'x@ x()'

Share this post


Link to post
Share on other sites
You can register the method as returning a void, even though it really returns a pointer. As the method is returning a pointer this would be placed in the cpu registers and can safely be ignored by AngelScript without any negative impact.

Regards,
Andreas


Share this post


Link to post
Share on other sites
hey, thanks, so, i'm moving on with learning a bit more, and am running into another problem, essentially, much of my engine's vector's return float pointers to access the members, so, i thought of writing a simple wrapper and wrap the values into the simple struct representing the data, like so:


#include <stdio.h>
#include <time.h>
#include <string>
#include <new.h>
#include <angelscript.h>
#include "../../add_on/scriptstdstring/scriptstdstring.h"

using namespace std;

struct vec{
float x,y,z;
vec(float mx, float my, float mz){
x = mx;
y = my;
z = mz;
}
};

class x{
private:
float m_Pos[3];
int m_RefCnt;
public:
x *AddRef(void){
printf("Add Ref\n");
m_RefCnt++;
return this;
}

void SetPos(float x, float y, float z){
m_Pos[0] = x;
m_Pos[1] = y;
m_Pos[2] = z;
return;
}

float *GetPos(void){
return m_Pos;
}

void Release(void){
printf("Release called\n");
if(--m_RefCnt==0) delete this;
}

x() : m_RefCnt(1){
memset(m_Pos, 0, sizeof(float)*3);
printf("Construct x: 0x%x\n", this);
}

~x(){
printf("Deconstruct x\n");
}
};

#define TST "void HelloWorld(void){ x n; vec z = n.GetPos(); y.SetPos(z.x+1.0, z.y+2.0, z.z+3.0);}"

void Print(string &s){
printf("'%s'\n", s.c_str());
return;
}


void MCallBack(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);
}

x *xConstruct(){ return new x(); }

vec xRVec(x *o){
printf("o: 0x%x\n",o);
return vec(o->GetPos()[0], o->GetPos()[1], o->GetPos()[2]);
}

int main(int argc, char **argv){
asIScriptEngine *Engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
if(!Engine) printf("Error Creating engine\n");
Engine->SetMessageCallback(asFUNCTION(MCallBack), 0x0, asCALL_CDECL);
RegisterStdString(Engine);
if(Engine->RegisterObjectType("vec", sizeof(vec), asOBJ_VALUE|asOBJ_POD)<0) printf("Error registering vec\n");
if(Engine->RegisterObjectProperty("vec", "float x", 0)<0) printf("Error registering vec.x\n");
if(Engine->RegisterObjectProperty("vec", "float y", sizeof(float))<0) printf("Error registering vec.y\n");
if(Engine->RegisterObjectProperty("vec", "float z", sizeof(float)*2)<0) printf("Error registering vec.z\n");

if(Engine->RegisterObjectType("x", sizeof(x), asOBJ_REF)<0) printf("Error Registering x\n");
if(Engine->RegisterObjectBehaviour("x", asBEHAVE_FACTORY, "x@ x()", asFUNCTION(xConstruct), asCALL_CDECL)<0) printf("Factory not Registered\n");
if(Engine->RegisterObjectBehaviour("x", asBEHAVE_ADDREF, "void x()", asMETHOD(x, AddRef), asCALL_THISCALL)<0) printf("Release not Registered\n");
if(Engine->RegisterObjectBehaviour("x", asBEHAVE_RELEASE, "void x()", asMETHOD(x, Release), asCALL_THISCALL)<0) printf("Release not Register\n");
if(Engine->RegisterObjectMethod("x", "vec &GetPos()", asFUNCTION(xRVec), asCALL_CDECL_OBJLAST)<0) printf("Error registering GetPos()\n");
if(Engine->RegisterObjectMethod("x", "void SetPos(float,float,float)", asMETHOD(x, SetPos), asCALL_THISCALL)<0) printf("Error registering SetPos()\n");
if(Engine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(Print), asCALL_CDECL)<0) printf("Error Registering...\n");
x *y = new x();
Engine->RegisterGlobalProperty("x @y", &y);

asIScriptModule *Mod = Engine->GetModule(0x0, asGM_ALWAYS_CREATE);
if(Mod->AddScriptSection("FistScript", TST, strlen(TST))<0) printf("Error adding script...\n");
if(Mod->Build()<0) printf("Error building Mod...\n");
asIScriptContext *Cntx = Engine->CreateContext();
int FuncID = Mod->GetFunctionIdByDecl("void HelloWorld(void)");
if(FuncID<0) printf("Error, can't find HelloWorld\n");
printf("Preparing\n");
Cntx->Prepare(FuncID);
printf("Executing\n");
Cntx->Execute();
printf("y: %f %f %f\n", y->GetPos()[0], y->GetPos()[1], y->GetPos()[2]);
Cntx->Release();
Engine->Release();
y->Release();
int t=time(0x0)+10;
while(time(0x0)<t);
return 0;
}


however, when i check the pointer value of o in xRVec function, it's reporting a diffrent value for the created pointer, and consequently, is not receiving the correct input of values.

here's the current output:

Construct x: 0x5925c8
Preparing
Executing
Construct x: 0x5990a8
o: 0x598538
Release called
Deconstruct x
y: -431602080.000000 -431602080.000000 -431602080.000000
Release called
Deconstruct x

Share this post


Link to post
Share on other sites
The problem is that your xRVec function is implemented to return the vec type by value, but you registered it with AngelScript as returning the vec type by reference.

Because the xRVec is returning the type by value the C++ compiler adds a hidden pointer as the first argument. This pointer must be passed by the caller so the function can return the vec value in the location, but as AngelScript doesn't know this it doesn't pass the hidden pointer.

You can fix it by changing the registration to:



if(Engine->RegisterObjectMethod("x", "vec GetPos()", asFUNCTION(xRVec), asCALL_CDECL_OBJLAST)<0) printf("Error registering GetPos()\n");



You should also add the flag asOBJ_APP_CLASS_C to the registration of the vec type, i.e.



if(Engine->RegisterObjectType("vec", sizeof(vec), asOBJ_VALUE|asOBJ_POD|asOBJ_APP_CLASS_C)<0) printf("Error registering vec\n");

This will let AngelScript know that the vec type is really a C++ class with a structure, and can then properly treat the class when passing it by value to the application or receiving it by value in return values.

Regards,
Andreas

Share this post


Link to post
Share on other sites
hey, so, i did what you suggested, and got the following error:

(0, 0) : INFO : vec x::GetPos()
(0, 0) : ERR : Can't return type 'vec' by value unless the application type is
informed in the registration
(0, 0) : ERR : Invalid configuration. Verify the registered application interf
ace.


so, i instead appended the reference to the function instead, like so:

vec &xRVec(x *o){
printf("o: 0x%x\n",o);
return vec(o->GetPos()[0], o->GetPos()[1], o->GetPos()[2]);
}
...
if(Engine->RegisterObjectMethod("x", "vec &GetPos()", asFUNCTION(xRVec), asCALL_CDECL_OBJLAST)<0) printf("Error registering GetPos()\n");
...


this works fine, and compiles fine, but i get an compiler warning that i'm returning an temporary address, as i am.

basically, i'm surprised that it's still working when i'm clearly returning temporary addresses, which can't be guranteed to be valid.

i've tried playing around a bit to make sure doing a few calls to the function won't corrupt the value returned, and it seems to work fine. I assume angelscript copy's the returned value into it's own structure, so the temporary address isn't used longer than a copy in the end.

still i feel unsafe about doing this, is their another approach to what i'm doing?

otherwise so far i'm loving angelscript, much better than lua imo.

Share this post


Link to post
Share on other sites
The error message


Can't return type 'vec' by value unless the application type is informed in the registration


is because AngelScript doesn't have enough information about the type to know how it is treated in the native calling convention in order to return it by value.

Did you add the asOBJ_APP_CLASS_C flag that I mentioned in the last post? That is what AngelScript needs.

What platform are you using anyway? Is it 64bit Linux or Mac with gnuc/clang compiler? If it is then you'll also need to add the asOBJ_APP_CLASS_ALLFLOATS flag to let AngelScript know the vec type is composed of only floats. If you're not using 64bit Linux or Mac then you may still add the flag, but it is not needed as it doesn't make a difference what the class is composed of.

How to register a value type and what flags is described in the manual.

Manual: Registering a value type

Please let me know if the above article is not clear enough and I'll do my best to improve it.



Returning a reference to a local variable is not something you want to do. While it compiles it will most likely not give the result you want in all cases. If you need to return a reference to a new value, then store the value in a static variable and return the reference to that value. At least that way you're guaranteed the value will still be there when the caller uses the reference.

Regards,
Andreas

Share this post


Link to post
Share on other sites

The error message


Can't return type 'vec' by value unless the application type is informed in the registration


is because AngelScript doesn't have enough information about the type to know how it is treated in the native calling convention in order to return it by value.

Did you add the asOBJ_APP_CLASS_C flag that I mentioned in the last post? That is what AngelScript needs.

What platform are you using anyway? Is it 64bit Linux or Mac with gnuc/clang compiler? If it is then you'll also need to add the asOBJ_APP_CLASS_ALLFLOATS flag to let AngelScript know the vec type is composed of only floats. If you're not using 64bit Linux or Mac then you may still add the flag, but it is not needed as it doesn't make a difference what the class is composed of.

How to register a value type and what flags is described in the manual.

Manual: Registering a value type

Please let me know if the above article is not clear enough and I'll do my best to improve it.



Returning a reference to a local variable is not something you want to do. While it compiles it will most likely not give the result you want in all cases. If you need to return a reference to a new value, then store the value in a static variable and return the reference to that value. At least that way you're guaranteed the value will still be there when the caller uses the reference.

Regards,
Andreas


ok, thanks for the information, i didn't notice the app_class_c flag in the other post, i added that and it works without any warnings. thanks for the help.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!