🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

static methods and object handles

Started by
3 comments, last by Rain Dog 18 years, 1 month ago
First some background: as a lot of other people too I'm currently adding script support to my game project. I first used lua and luaBind but got more and more problems with that. So I downloaded angelscript and did some tests with it. Two questions: First: static methods I've got a simple test class like that: class A { static void StaticTest( const float pParam) { cout << "StaticTest: " << pParam << endl;} } I tried to register this static method as follows engine->RegisterObjectMethod( "A", "void StaticTest( const float)", asFUNCTION( A::StaticTest), asCALL_CDECL); but I get -7 (asNOT_SUPPORTED) as return value. So I tried to register this method at least as a global function engine->RegisterGlobalFunction( "void StaticTest( const float)", asFUNCTION( A::StaticTest), asCALL_CDECL); This registrations went fine but when I call this function from a script like this ExecuteScriptString( "StaticTest( 5.0f);"); not "5.0f" get's printed but it prints some long number (1084227584) which could be the this-pointer as an integer or something but is surely not the 5.0f I gave in. :) So what do I do wrong? And is there actually any possibility to register static class methods? -------------------- Second: problems with object pointers in scripts Consider some simple object factory and some simple object on the C++-side class SomeObjectFactory { [...] OneObject *CreateOneObject( ...) { ... } OneObject *GetObjectByName( const char *....) { [...] if( object_found) return object; else return NULL; } [...] } class OneObject { // reference counting only needed for script support void AddRef() {..} void Release() {...} const int SomeMethod() { return 5; } } On the script side: void AngelTest() { OneObject @obj = objectFactory.GetObjectByName( ...); if( obj != null) print( obj.SomeMethod()); } My problem is that I can't really see the reason why I must bloat all my classes with i.e. reference counting just to be able to use object handles on the script side. Isn't there any way to register my classes and to be able to work with object pointers on the script side without been forced to add reference counting? On the C++ side I take care of all the memory and object managment. I register everything so that OneObject can't be instanciated on the script side (registering objects with size 0). On the script side I just want to retrieve a pointer or NULL from the some C++ object factory and call some methods on the retrieved pointer. Well, pretty much a standard scenario, as you can see. The project I want to add scripting support to is rather large. So, as you might agree, adding reference counting (and maybe other things) to probably some hundred classes is surely not a solution for me. Is there a way around? I could write a template class which add's fake reference counting to any class, but I would like to avoid such measures if I can. Thanks for your time. Bye, Stefan.
Advertisement
Static class functions are just like normal global functions as far as C++ is concerned. You couldn't bind it as a method simply because it isn't; methods must have either the asCALL_THISCALL or asCALL_CDECL_OBJLAST calling convention, and require that a pointer to the object is one of the parameters to the function (For a straight method, that's the hidden this*. For a wrapped method, it's a * that comes last in the arguments. Thus, OBJLAST.)

As for getting the wrong number; everything in your code looks fine. I have no idea why it wouldn't work.

For your second problem;

If you are already using smart pointers to manage stuff in C++, you can hook into that mechanism when binding. For example, the scaffolding for boost::intrusive_ptr can be bound directly to the add_ref and release behaviors. Or you could just bind the smart pointer as the type in angelscript and pass it in by value. (This is what I do. Unfortunatly, it means you have to wrap all your methods. I'm writing wrapper templates for this too)
If niether of those are an option, you can use references. Either of the in/out/inout variety (Which, IIRC, might require the add_ref/release behaviors anyway) or by enabling asUNSAFE_REFERENCES, which makes references behave just like in C++ (That is, as a pointer that can't be null)
//Method through smart pointer wrapper//Type guide://	R - return type//	P - smart pointer type//	C - type smart pointer points too//	M - method on C//	rest - parameters//use asCALL_CDDECL_OBJLASTtemplate<typename R,typename P, typename C, R(C::*M)()>R MethodThroughPointer0(P* thisp) { return ((**thisp).*M)(); }template<typename R,typename P, typename C, R(C::*M)(), typename P1>R MethodThroughPointer1(P1 p1, P* thisp) { return ((**thisp).*M)(p1); }template<typename R,typename P, typename C, R(C::*M)(), typename P1, typename P2>R MethodThroughPointer2(P1 p1, P2 p2, P* thisp) { return ((**thisp).*M)(p1,p2); }template<typename R,typename P, typename C, R(C::*M)(), typename P1, typename P2, typename P3>R MethodThroughPointer3(P1 p1, P2 p2, P3 p3, P* thisp) { return ((**thisp).*M)(p1,p2,p3); }template<typename R,typename P, typename C, R(C::*M)(), typename P1, typename P2, typename P3, typename P4>R MethodThroughPointer4(P1 p1, P2 p2, P3 p3, P4 p4, P* thisp) { return ((**thisp).*M)(p1,p2,p3,p4); }template<typename R,typename P, typename C, R(C::*M)(), typename P1, typename P2, typename P3, typename P4, typename P5>R MethodThroughPointer5(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P* thisp) { return ((**thisp).*M)(p1,p2,p3,p4,p5); }


Sorry it took so long. Needed someone to point out to me that boost smart pointers don't have an operator->*.
Thanks for your explainations.

@static methods:
It's alright for me to register static functions as globals on the script side. I'm was just a bit sad about loosing the class scope/namespace, as that will surely lead to problems when there is more than one class with equally named static functions.

The reason for why I didn't get the float parameter I gave in is still unknown. I got in contact with Andreas so there will surely be a solution soon.


@reference couting:
Thanks for the template helper, looks useful.

I don't use smart pointers. I just take care of all the objects on the C++ side myself and I wondered why I have to register reference counting behaviour for objects which only exist on the script side as pointers or references (Handles) to objects. AS cannot rely on the reference counting as one is allowed to register dummy functions which don't do anything. My classes on the C++ side don't use reference counting, too.

I'm just wondering why I have to add so much stuff to my classes to use them on the script side for no apparent reason.

Well, I guess I have to live with that. It's not that big problem. :)

Thanks for your help.

Bye, Stefan.
What you can do to make it easier to add references, etc, is 1: inherit from a "Referenced" base class or 2, create a macro: DECLARE_IS_REFERENCEABLE().

This topic is closed to new replies.

Advertisement