// EntityProperties.h // // Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com // // Extended properties table, primarily intended for data-inheritable properties and those defined by JavaScript functions. // // Usage: These properties are accessed via functions in CEntity/CBaseEntity // // TODO: Fix the silent failures of the conversion functions: need to work out what to do in these cases. // Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com /* #ifndef ENTITY_PROPERTIES_INCLUDED #define ENTITY_PROPERTIES_INCLUDED #include "CStr.h" #include "Vector3D.h" #include "ScriptObject.h" #include "scripting/JSInterface_Entity.h" #include "scripting/JSInterface_Vector3D.h" #ifndef __GNUC__ class IBoundPropertyOwner; class CBaseEntity; // Property interface class IBoundProperty { protected: IBoundPropertyOwner* m_owner; void (IBoundPropertyOwner::*m_updateFn)(); virtual void set( const jsval value ) = 0; public: void fromjsval( const jsval value ); virtual jsval tojsval() = 0; virtual bool rebuild( IBoundProperty* parent, bool triggerFn = true ) = 0; // Returns true if the rebuild changed the value of this property. void associate( IBoundPropertyOwner* owner, const CStrW& name ); void associate( IBoundPropertyOwner* owner, const CStrW& name, void (IBoundPropertyOwner::*updateFn)() ); virtual ~IBoundProperty() {} }; // Specialize at least: // - jsval conversion functions (set, tojsval) // Generic primitive one: template class CBoundProperty : public IBoundProperty { T m_data; bool m_inherited; public: CBoundProperty() { m_inherited = true; } CBoundProperty( const T& copy ) { m_inherited = false; m_data = copy; } operator T&() { return( m_data ); } operator const T&() const { return( m_data ); } T& operator=( const T& copy ) { m_inherited = false; return( m_data = copy ); } void set( const jsval value ); jsval tojsval(); bool rebuild( IBoundProperty* parent, bool triggerFn = true ) { if( m_inherited && parent ) { *this = *( (CBoundProperty*)parent ); if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)(); } return( !m_inherited ); } }; // Generic class one: template class CBoundObjectProperty : public IBoundProperty, public T { bool m_inherited; public: CBoundObjectProperty() { m_inherited = true; } CBoundObjectProperty( const T& copy ) : T( copy ) { m_inherited = false; } T& operator=( const T& copy ) { IBoundPropertyOwner* sv_owner = m_owner; void (IBoundPropertyOwner::*sv_updateFn)() = m_updateFn; (T&)*this = copy; m_owner = sv_owner; m_updateFn = sv_updateFn; m_inherited = false; return( *this ); } void set( const jsval value ); jsval tojsval(); bool rebuild( IBoundProperty* parent, bool triggerFn = true ) { if( m_inherited && parent ) { // Save some properties so they won't be overwritten IBoundPropertyOwner* sv_owner = m_owner; void (IBoundPropertyOwner::*sv_updateFn)() = m_updateFn; *this = *( (CBoundObjectProperty*)parent ); m_owner = sv_owner; m_updateFn = sv_updateFn; m_inherited = true; if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)(); } return( !m_inherited ); } }; // And an explicit one: template<> class CBoundProperty : public IBoundProperty { CBaseEntity* m_data; public: CBoundProperty() { m_data = NULL; } CBoundProperty( CBaseEntity* copy ) { m_data = copy; } operator CBaseEntity*&() { return( m_data ); } operator CBaseEntity*() const { return( m_data ); } CBaseEntity*& operator=( CBaseEntity* copy ) { return( m_data = copy ); } // Standard pointerish things CBaseEntity& operator*() { return( *m_data ); } CBaseEntity* operator->() { return( m_data ); } void set( const jsval value ); jsval tojsval(); bool rebuild( IBoundProperty* parent, bool triggerFn = true ) { return( false ); // Can't inherit a CBaseEntity* } }; // A jsval property template<> class CBoundProperty : public IBoundProperty { jsval m_data; bool m_inherited; public: CBoundProperty() { m_data = JSVAL_NULL; m_inherited = true; RootJSVal(); } CBoundProperty( const jsval value ) { set( value ); m_inherited = false; RootJSVal(); } CBoundProperty( CStrW value ) { m_data = STRING_TO_JSVAL( JS_NewUCStringCopyZ( g_ScriptingHost.getContext(), value ) ); RootJSVal(); } ~CBoundProperty() { UprootJSVal(); } void set( const jsval value ) { UprootJSVal(); m_data = value; m_inherited = false; RootJSVal(); } jsval tojsval() { return( m_data ); } bool rebuild( IBoundProperty* parent, bool triggerFn = true ) { if( m_inherited && parent ) { UprootJSVal(); m_data = ( (CBoundProperty*)parent )->m_data; RootJSVal(); } return( !m_inherited ); } void RootJSVal() { if( JSVAL_IS_GCTHING( m_data ) ) JS_AddRoot( g_ScriptingHost.GetContext(), &m_data ); } void UprootJSVal() { if( JSVAL_IS_GCTHING( m_data ) ) JS_RemoveRoot( g_ScriptingHost.GetContext(), &m_data ); } }; #endif */