Hi,
I'm working on adding a scripting in my game engine. I registered btVector3 (the Vector3 from the bullet physics engine), but it is half-working : some methods are working (constructors, length, ...), but some are not (opAdd, opMul, opDiv, opSub, ...) : I get completely random values (garbage memory)
I created a small script to test this, registering a dummy Integer class:
#include <angelscript.h>
#include <cassert>
#include <cstdio>
#include <string>
class Integer {
public:
Integer() {
_i = 0;
}
Integer(int i) {
_i = i;
}
int getInt() const {
return _i;
}
void setInt(int i) {
_i = i;
}
private:
int _i;
};
void IntegerConstruct(Integer* self) {
new(self) Integer();
}
void IntegerConstructInt(int i, Integer* self) {
new(self) Integer(i);
}
void IntegerConstructCopy(const Integer& other, Integer* self) {
new(self) Integer(other);
}
void print(const Integer& i) {
printf("%d\n", i.getInt());
}
Integer operator+(const Integer& i1, const Integer& i2) {
printf("%d %d\n", i1.getInt(), i2.getInt()); //Debug
return Integer(i1.getInt() + i2.getInt());
}
const std::string code =
"void main() {\n"
" Integer i(42);\n"
" Integer j(1337);\n"
" print(i);\n"
" print(j);\n"
" print(i.opAdd(j));\n"
" print(i + j);\n"
"}\n"
;
class ScriptEngine {
private:
void MessageCallback(const asSMessageInfo* msg) {
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);
}
asIScriptEngine* _engine;
asIScriptModule* _mod;
public:
ScriptEngine() {
int r;
_engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
r = _engine->SetMessageCallback(asMETHOD(ScriptEngine, MessageCallback), this, asCALL_THISCALL); assert(r >= 0);
r = _engine->RegisterObjectType("Integer", sizeof(Integer), asOBJ_VALUE | asOBJ_APP_CLASS_CK | asOBJ_POD); assert(r >= 0);
r = _engine->RegisterObjectBehaviour("Integer", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(IntegerConstruct), asCALL_CDECL_OBJLAST); assert(r >= 0);
r = _engine->RegisterObjectBehaviour("Integer", asBEHAVE_CONSTRUCT, "void f(int i)", asFUNCTION(IntegerConstructInt), asCALL_CDECL_OBJLAST); assert(r >= 0);
r = _engine->RegisterObjectBehaviour("Integer", asBEHAVE_CONSTRUCT, "void f(const Integer& in)", asFUNCTION(IntegerConstructCopy), asCALL_CDECL_OBJLAST); assert(r >= 0);
r = _engine->RegisterObjectMethod("Integer", "int get_i() const", asMETHOD(Integer, getInt), asCALL_THISCALL); assert(r >= 0);
r = _engine->RegisterObjectMethod("Integer", "void set_i(int)", asMETHOD(Integer, setInt), asCALL_THISCALL); assert(r >= 0);
r = _engine->RegisterObjectMethod("Integer", "Integer opAdd(const Integer& in) const", asFUNCTIONPR(operator+, (const Integer&, const Integer&), Integer), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = _engine->RegisterGlobalFunction("void print(const Integer& in)", asFUNCTION(print), asCALL_CDECL); assert(r >= 0);
_mod = _engine->GetModule("Test", asGM_ALWAYS_CREATE);
r = _mod->AddScriptSection("script", code.c_str(), code.size()); assert(r >= 0);
r = _mod->Build(); assert(r >= 0);
}
~ScriptEngine() {
_engine->Release();
}
void run() {
int r;
asIScriptContext* ctx = _engine->CreateContext();
asIScriptFunction* func = _mod->GetFunctionByDecl("void main()");
r = ctx->Prepare(func); assert(r >= 0);
r = ctx->Execute(); assert(r >= 0);
ctx->Release();
}
};
int main() {
ScriptEngine script;
script.run();
return 0;
}
When I run it, I get an output like this:
42
1337
36575664 42
36575664
36575664 42
36575664
What I notice:
- Well, operator+ get 36575664 (it changes at every execution) instead of 1337
- 42 is the second argument of operator+ whereas it should be the first
- The result of 36575664 + 42 = 36575664 (n + 42 = n)
Maybe the implicit constructor isn't working? Let's try:
//...
int main() {
Integer i(42);
Integer j(i);
print(i);
print(j);
return 0;
}
I get this output:
42
42
So the implicit constructor works. But let's try to add an explicit one:
//...
Integer(const Integer& other) {
_i = other._i;
}
//...
int main() { //The implicit constructor test is removed
ScriptEngine script;
script.run();
return 0;
}
And now I get this output (which is the output expected):
42
1337
42 1337
1379
42 1337
1379
But now the things start to be very strange. Let's put a debug printf in the copy constructor, and in the function that is used to register it to angelscript:
//...
Integer(const Integer& other) {
_i = other._i;
printf("foo\n");
}
//...
void IntegerConstructCopy(const Integer& other, Integer* self) {
printf("bar\n");
new(self) Integer(other);
}
I get this output:
42
1337
42 1337
1379
42 1337
1379
So the copy constructor is never called, but is needed! Isn't this strange?
To go back to my original problem, here is my current script engine.
I looked in the btVector3's source file, and there is an explicit copy constructor, so I really don't know why my code isn't working...