// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef CL_REFLECT_H #define CL_REFLECT_H #include "nel/misc/rgba.h" #include "lua_object.h" // #include class CReflectable; class CLuaState; struct CClassInfo; /** A property of a reflectable object * NB: multiple inheritance not supported */ class CReflectedProperty { public: enum TType { Boolean = 0, SInt32, UInt32, Float, String, UCString, RGBA, LuaMethod }; // other types will be added when needed // define some pointer-to-member types typedef bool (CReflectable::* TGetBool) () const; typedef sint32 (CReflectable::* TGetSInt32) () const; typedef uint32 (CReflectable::* TGetUInt32) () const; typedef float (CReflectable::* TGetFloat) () const; typedef std::string (CReflectable::* TGetString) () const; typedef ucstring (CReflectable::* TGetUCString) () const; typedef NLMISC::CRGBA (CReflectable::* TGetRGBA) () const; // typedef void (CReflectable::* TSetBool) (bool); typedef void (CReflectable::* TSetSInt32) (sint32); typedef void (CReflectable::* TSetUInt32) (uint32); typedef void (CReflectable::* TSetFloat) (float); typedef void (CReflectable::* TSetString) (const std::string &); typedef void (CReflectable::* TSetUCString) (const ucstring &); typedef void (CReflectable::* TSetRGBA) (NLMISC::CRGBA col); // typedef int (CReflectable:: *TLuaMethod) (CLuaState &luaState); public: TType Type; // In each union we have method pointers to retrieve / set the data of the desired type (as told in 'Type') union { TGetBool GetBool; TGetSInt32 GetSInt32; TGetUInt32 GetUInt32; TGetFloat GetFloat; TGetString GetString; TGetUCString GetUCString; TGetRGBA GetRGBA; TLuaMethod GetLuaMethod; // lua method can only be obtained, not written ... } GetMethod; union { TSetBool SetBool; TSetSInt32 SetSInt32; TSetUInt32 SetUInt32; TSetFloat SetFloat; TSetString SetString; TSetUCString SetUCString; TSetRGBA SetRGBA; } SetMethod; // name of the property std::string Name; mutable CLuaObject LuaMethodRef; // cache pointer to function call if type == LuaMethod const CClassInfo *ParentClass; // filled when 'registerClass' is called }; // a vector of reflected properties typedef std::vector TReflectedProperties; struct CClassInfo; /** Base class for a reflectable object * NB: multiple inheritance not supported */ class CReflectable { public: virtual ~CReflectable() {} virtual const char *getReflectedClassName() const { return "CReflectable"; } virtual const char *getRflectedParentClassName() const { return ""; } /** When registering classes, the reflect system will call this function on each class * to know which properties they exports. * To defines which properties are exported use the REFLECT_EXPORT_** macros. * By doing so, a new 'getReflectedProperties' function will be defined */ static void getReflectedProperties(TReflectedProperties &/* props */) { } // get class infos for this reflectable object const CClassInfo *getClassInfo(); /** get a property from this object by name * TODO nico : optimized version for lua string (found in CLuaIHM) would maybe fit better here ... */ const CReflectedProperty *getReflectedProperty(const std::string &propertyName, bool dspWarning= true) const; }; struct CLuaIndexedProperty { const CReflectedProperty *Prop; CLuaString Id; // must keep id here, so that we are sure the string is not gc in lua and its pointer remains valid }; struct CClassInfo { TReflectedProperties Properties; // the properties exported by this class const CClassInfo *ParentClass; // pointer to infos of the parent class, or NULL if it is a root class std::string ClassName; /** For lua speedup (used by CLuaIHM) : because lua string are unique, we can use them to access property directly. */ typedef CHashMap TLuaStrToPropMap; mutable TLuaStrToPropMap LuaStrToProp; }; /** Simple reflection system. * Used by the GUI and some other objects. * It is used to export some properties so that we can easily manipulate them in the GUI scripts (either lua or with CInterfaceExpr). * NB: multiple inheritance not supported * * Example of use : a class exporting a boolean * * class CTestClass : public CReflectable * { * public: * void setValue(bool value) { _Value = value; } * bool getValue() const { return _Value; } * \\ export the bool value * REFLECT_EXPORT_START(CTestClass, CReflectable) * REFLECT_BOOL("myValue", setValue, getValue) * REFLECT_EXPORT_END * private: * bool _Value; * }; * * The class must then be registered with : * * REGISTER_REFLECTABLE_CLASS(CTestClass, CReflectable) * * NB: It should be registered after its parents * * * \author Nicolas Vizerie * \author Nevrax France * \date 2002 */ class CReflectSystem { public: typedef std::map TClassMap; public: // release memory static void release(); /** register a class and its properties * NB : class should be registered after their parent have been, or an assertion will be raised */ static void registerClass(const std::string &className, const std::string &parentName, const TReflectedProperties properties); // retrieve a property of a reflectable class, or NULL if unknown static const CReflectedProperty *getProperty(const std::string &className, const std::string &propertyName, bool dspWarning= true); // get the list of class for debug or read purpose (NULL if no register has been called) static const TClassMap *getClassMap() {return _ClassMap;} ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private: static TClassMap *_ClassMap; // each class and its infos }; /** Helper macros to export properties of a reflectable class */ /** Start a declaration of a reflectable class exports * Should be placed inside the class */ #define REFLECT_EXPORT_START(className, parentName) \ virtual const char *getReflectedClassName() const { return #className; } \ virtual const char *getReflectedParentClassName() const { return #parentName; } \ static void getReflectedProperties(TReflectedProperties &props) \ { \ typedef className A; \ typedef bool (className::* TGetBoola) () const; \ typedef sint32 (className::* TGetSInt32a) () const; \ typedef uint32 (className::* TGetUInt32a) () const; \ typedef float (className::* TGetFloata) () const; \ typedef std::string (className::* TGetStringa) () const; \ typedef ucstring (className::* TGetUCStringa) () const; \ typedef NLMISC::CRGBA (className::* TGetRGBAa) () const; \ typedef void (className::* TSetBoola) (bool); \ typedef void (className::* TSetSInt32a) (sint32); \ typedef void (className::* TSetUInt32a) (uint32); \ typedef void (className::* TSetFloata) (float); \ typedef void (className::* TSetStringa) (const std::string &); \ typedef void (className::* TSetUCStringa) (const ucstring &); \ typedef void (className::* TSetRGBAa) (NLMISC::CRGBA col); \ typedef int (className:: *TLuaMethoda) (CLuaState &luaState); \ nlunreferenced(props); // export a boolean value, by giving the name of the get and the set method #define REFLECT_BOOL(exportName, getMethod, setMethod) \ { \ CReflectedProperty prop; \ prop.Name = exportName; \ prop.Type = CReflectedProperty::Boolean; \ prop.GetMethod.GetBool = (CReflectedProperty::TGetBool) (TGetBoola) &A::getMethod; \ prop.SetMethod.SetBool = (CReflectedProperty::TSetBool) (TSetBoola) &A::setMethod; \ props.push_back(prop); \ } // export a sint32 value, by giving the name of the get and the set method #define REFLECT_SINT32(exportName, getMethod, setMethod) \ { \ CReflectedProperty prop; \ prop.Name = exportName; \ prop.Type = CReflectedProperty::SInt32; \ prop.GetMethod.GetSInt32 = (CReflectedProperty::TGetSInt32) (TGetSInt32a) &A::getMethod; \ prop.SetMethod.SetSInt32 = (CReflectedProperty::TSetSInt32) (TSetSInt32a) &A::setMethod; \ props.push_back(prop); \ } // export a sint32 value, by giving the name of the get and the set method #define REFLECT_UINT32(exportName, getMethod, setMethod) \ { \ CReflectedProperty prop; \ prop.Name = exportName; \ prop.Type = CReflectedProperty::UInt32; \ prop.GetMethod.GetUInt32 = (CReflectedProperty::TGetUInt32) (TGetUInt32a) &A::getMethod; \ prop.SetMethod.SetUInt32 = (CReflectedProperty::TSetUInt32) (TSetUInt32a) &A::setMethod; \ props.push_back(prop); \ } // export a float value, by giving the name of the get and the set method #define REFLECT_FLOAT(exportName, getMethod, setMethod) \ { \ CReflectedProperty prop; \ prop.Name = exportName; \ prop.Type = CReflectedProperty::Float; \ prop.GetMethod.GetFloat = (CReflectedProperty::TGetFloat) (TGetFloata) &A::getMethod; \ prop.SetMethod.SetFloat = (CReflectedProperty::TSetFloat) (TSetFloata) &A::setMethod; \ props.push_back(prop); \ } // export a string value, by giving the name of the get and the set method #define REFLECT_STRING(exportName, getMethod, setMethod) \ { \ CReflectedProperty prop; \ prop.Name = exportName; \ prop.Type = CReflectedProperty::String; \ prop.GetMethod.GetString = (CReflectedProperty::TGetString) (TGetStringa) &A::getMethod; \ prop.SetMethod.SetString = (CReflectedProperty::TSetString) (TSetStringa) &A::setMethod; \ props.push_back(prop); \ } // export a unicode string value, by giving the name of the get and the set method #define REFLECT_UCSTRING(exportName, getMethod, setMethod) \ { \ CReflectedProperty prop; \ prop.Name = exportName; \ prop.Type = CReflectedProperty::UCString; \ prop.GetMethod.GetUCString = (CReflectedProperty::TGetUCString) (TGetUCStringa) &A::getMethod; \ prop.SetMethod.SetUCString = (CReflectedProperty::TSetUCString) (TSetUCStringa) &A::setMethod; \ props.push_back(prop); \ } // export a color value, by giving the name of the get and the set method #define REFLECT_RGBA(exportName, getMethod, setMethod) \ { \ CReflectedProperty prop; \ prop.Name = exportName; \ prop.Type = CReflectedProperty::RGBA; \ prop.GetMethod.GetRGBA = (CReflectedProperty::TGetRGBA) (TGetRGBAa) &A::getMethod; \ prop.SetMethod.SetRGBA = (CReflectedProperty::TSetRGBA) (TSetRGBAa) &A::setMethod; \ props.push_back(prop); \ } // export a lua method #define REFLECT_LUA_METHOD(exportName, method) \ { \ CReflectedProperty prop; \ prop.Name = exportName; \ prop.Type = CReflectedProperty::LuaMethod; \ prop.GetMethod.GetLuaMethod = (CReflectedProperty::TLuaMethod) (TLuaMethoda) &A::method; \ props.push_back(prop); \ } // ends an export declaration #define REFLECT_EXPORT_END } // This macro registers a reflectable class to the manager #define REGISTER_REFLECTABLE_CLASS(className, parentName) \ { \ TReflectedProperties props; \ className::getReflectedProperties(props); \ CReflectSystem::registerClass(#className, #parentName, props); \ } #endif