1
0
forked from 0ad/0ad
0ad/source/scripting/ScriptableComplex.h
Ykkrosh 35e91718c5 # Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.

This was SVN commit r4261.
2006-08-28 17:36:42 +00:00

288 lines
10 KiB
C++

/*
ScriptableComplex.h
The version of CJSObject<> that retains the ability to use inheritance
in its objects. Shouldn't be used any more for anything but entity code.
This file contains only declarations of class CJSComplex and its methods.
Their implementations are in ScriptableComplex.inl. Because CJSComplex is
a templated class, any source file that uses these methods directly must
#include ScritpableComplex.inl to link to them. However, files that
only need to know that something is a CJSComplex need not do this. This
was done to speed up compile times after modifying CJSComplex's internals:
before, 30+ files had to be recompiled because they #included Entity.h
which #includes ScriptableComplex.h.
*/
#ifndef SCRIPTABLE_COMPLEX_INCLUDED
#define SCRIPTABLE_COMPLEX_INCLUDED
#include "scripting/ScriptingHost.h"
#include "simulation/ScriptObject.h"
#include "JSConversions.h"
#include <set>
class IJSComplex;
class IJSComplexProperty
{
public:
bool m_AllowsInheritance;
bool m_Inherited;
bool m_Intrinsic;
// This is to make sure that all the fields are initialized at construction
inline IJSComplexProperty():
m_AllowsInheritance(true),
m_Inherited(true),
m_Intrinsic(true)
{}
virtual jsval Get( JSContext* cx, IJSComplex* owner ) = 0;
virtual void Set( JSContext* cx, IJSComplex* owner, jsval Value ) = 0;
// Copies the data directly out of a parent property
// Warning: Don't use if you're not certain the properties are not of the same type.
virtual void ImmediateCopy( IJSComplex* CopyTo, IJSComplex* CopyFrom, IJSComplexProperty* CopyProperty ) = 0;
jsval Get( IJSComplex* owner ) { return( Get( g_ScriptingHost.GetContext(), owner ) ); }
void Set( IJSComplex* owner, jsval Value ) { return( Set( g_ScriptingHost.GetContext(), owner, Value ) ); }
virtual ~IJSComplexProperty() {}
};
class IJSComplex
{
// Make copy constructor and assignment operator private - since copying of
// these objects is unsafe unless done specially.
// These will never be implemented (they are, after all, here to *prevent*
// copying)
IJSComplex(const IJSComplex &other);
IJSComplex& operator=(const IJSComplex &other);
public:
typedef STL_HASH_MAP<CStrW, IJSComplexProperty*, CStrW_hash_compare> PropertyTable;
typedef std::vector<IJSComplex*> InheritorsList;
typedef std::set<CStrW> StringTable;
typedef std::pair<StringTable, StringTable::iterator> IteratorState;
// Used for freshen/update
typedef void (IJSComplex::*NotifyFn)();
// Property getters and setters
typedef jsval (IJSComplex::*GetFn)();
typedef void (IJSComplex::*SetFn)( jsval );
// Properties of this object
PropertyTable m_Properties;
// Parent object
IJSComplex* m_Parent;
// Objects that inherit from this
InheritorsList m_Inheritors;
// Destructor
virtual ~IJSComplex() { }
// Set the base, and rebuild
void SetBase( IJSComplex* m_Parent );
// Rebuild any intrinsic (mapped-to-C++-variable) properties
virtual void Rebuild() = 0;
// HACK: Doesn't belong here.
virtual void rebuildClassSet() = 0;
// Check for a property
virtual IJSComplexProperty* HasProperty( const CStrW& PropertyName ) = 0;
// Get all properties of an object
virtual void FillEnumerateSet( IteratorState* it, CStrW* PropertyRoot = NULL ) = 0;
// Retrieve the value of a property (returning false if that property is not defined)
virtual bool GetProperty( JSContext* cx, const CStrW& PropertyName, jsval* vp ) = 0;
// Add a property (with immediate value)
virtual void AddProperty( const CStrW& PropertyName, jsval Value ) = 0;
virtual void AddProperty( const CStrW& PropertyName, const CStrW& Value ) = 0;
inline IJSComplex() {}
};
class CJSReflector;
template<typename T, bool ReadOnly, typename ReturnType, ReturnType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )>
void AddMethodImpl( const char* Name, uintN MinArgs );
template<typename T, bool ReadOnly, typename PropType>
void AddClassPropertyImpl( const CStrW& PropertyName, PropType T::*Native, bool PropAllowInheritance = true, IJSComplex::NotifyFn Update = NULL, IJSComplex::NotifyFn Refresh = NULL );
template<typename T, bool ReadOnly, typename PropType>
void AddReadOnlyClassPropertyImpl( const CStrW& PropertyName, PropType T::*Native, bool PropAllowInheritance = true, IJSComplex::NotifyFn Update = NULL, IJSComplex::NotifyFn Refresh = NULL );
template<typename T, bool ReadOnly, typename PropType>
void MemberAddPropertyImpl( IJSComplex* obj, const CStrW& PropertyName, PropType* Native, bool PropAllowInheritance = true, IJSComplex::NotifyFn Update = NULL, IJSComplex::NotifyFn Refresh = NULL );
template<typename T, bool ReadOnly, typename PropType>
void MemberAddReadOnlyPropertyImpl( IJSComplex* obj, const CStrW& PropertyName, PropType* Native, bool PropAllowInheritance = true, IJSComplex::NotifyFn Update = NULL, IJSComplex::NotifyFn Refresh = NULL );
template<typename T, bool ReadOnly = false> class CJSComplex : public IJSComplex
{
public:
typedef STL_HASH_MAP<CStrW, CJSReflector*, CStrW_hash_compare> ReflectorTable;
template<typename Q> friend class CJSComplexPropertyAccessor;
JSObject* m_JS;
std::vector<CScriptObject> m_Watches;
ReflectorTable m_Reflectors;
static JSPropertySpec JSI_props[];
static std::vector<JSFunctionSpec> m_Methods;
static PropertyTable m_IntrinsicProperties;
public:
static JSClass JSI_class;
// Whether native code is responsible for managing this object.
// Script constructors should clear this *BEFORE* creating a JS
// mirror (otherwise it'll be rooted).
bool m_EngineOwned;
// JS Property access
bool GetProperty( JSContext* cx, const CStrW& PropertyName, jsval* vp );
void SetProperty( JSContext* cx, const CStrW& PropertyName, jsval* vp );
void WatchNotify( JSContext* cx, const CStrW& PropertyName, jsval* newval );
//
// Functions that must be provided to JavaScript
//
static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
static JSBool JSSetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
static JSBool JSEnumerate( JSContext* cx, JSObject* obj, JSIterateOp enum_op, jsval* statep, jsid *idp );
static JSBool SetWatchAll( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
static JSBool UnWatchAll( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
static void ScriptingInit( const char* ClassName, JSNative Constructor = NULL, uintN ConstructorMinArgs = 0 );
static void ScriptingShutdown();
static void DefaultFinalize( JSContext *cx, JSObject *obj );
public:
JSObject* GetScript();
// Creating and releasing script objects is done automatically most of the time, but you
// can do it explicitly.
void CreateScriptObject();
void ReleaseScriptObject();
CJSComplex();
virtual ~CJSComplex();
void Shutdown();
void SetBase( IJSComplex* Parent );
void Rebuild();
IJSComplexProperty* HasProperty( const CStrW& PropertyName );
void FillEnumerateSet( IteratorState* it, CStrW* PropertyRoot = NULL );
void AddProperty( const CStrW& PropertyName, jsval Value );
void AddProperty( const CStrW& PropertyName, const CStrW& Value );
static void AddClassProperty( const CStrW& PropertyName, GetFn Getter, SetFn Setter = NULL );
// these functions are themselves templatized. we don't want to implement
// them in the header because that would drag in many dependencies.
//
// therefore, the publicly visible functions actually only call out to
// external friend functions implemented in the .inl file.
// these receive the template parameters from the class as well as the
// ones added for the member function.
//
// for non-static members, the friends additionally take a "this" pointer.
template<typename ReturnType, ReturnType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )>
static void AddMethod( const char* Name, uintN MinArgs )
{
AddMethodImpl<T, ReadOnly, ReturnType, NativeFunction>(Name, MinArgs);
}
template<typename PropType>
static void AddClassProperty( const CStrW& PropertyName, PropType T::*Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
{
AddClassPropertyImpl<T, ReadOnly, PropType>(PropertyName, Native, PropAllowInheritance, Update, Refresh);
}
template<typename PropType>
static void AddReadOnlyClassProperty( const CStrW& PropertyName, PropType T::*Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
{
AddReadOnlyClassPropertyImpl<T, ReadOnly, PropType>(PropertyName, Native, PropAllowInheritance, Update, Refresh);
}
// PropertyName must not already exist! (verified in debug build)
template<typename PropType>
void AddProperty( const CStrW& PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
{
MemberAddPropertyImpl<T, ReadOnly, PropType>(this, PropertyName, Native, PropAllowInheritance, Update, Refresh);
}
// PropertyName must not already exist! (verified in debug build)
template<typename PropType>
void AddReadOnlyProperty( const CStrW& PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
{
MemberAddReadOnlyPropertyImpl<T, ReadOnly, PropType>(this, PropertyName, Native, PropAllowInheritance, Update, Refresh);
}
// helper routine for Add*Property. Their interface requires the
// property not already exist; we check for this (in debug builds)
// and if so, warn and free the previously new-ed memory in
// m_Properties[PropertyName] (avoids mem leak).
void DeletePreviouslyAssignedProperty( const CStrW& PropertyName );
};
//
// static members
//
template<typename T, bool ReadOnly> JSClass CJSComplex<T, ReadOnly>::JSI_class = {
NULL, JSCLASS_HAS_PRIVATE | JSCLASS_NEW_ENUMERATE,
JS_PropertyStub, JS_PropertyStub,
JSGetProperty, JSSetProperty,
(JSEnumerateOp)JSEnumerate, JS_ResolveStub,
JS_ConvertStub, DefaultFinalize,
NULL, NULL, NULL, NULL
};
template<typename T, bool ReadOnly> JSPropertySpec CJSComplex<T, ReadOnly>::JSI_props[] = {
{ 0 },
};
template<typename T, bool ReadOnly> std::vector<JSFunctionSpec> CJSComplex<T, ReadOnly>::m_Methods;
template<typename T, bool ReadOnly> typename CJSComplex<T, ReadOnly>::PropertyTable CJSComplex<T, ReadOnly>::m_IntrinsicProperties;
template<typename T>
void ScriptableComplex_InitComplexPropertyAccessor();
//
// suballocator for CJSComplex.m_Properties elements
// (referenced from implementation in .inl)
//
extern void jscomplexproperty_suballoc_attach();
extern void jscomplexproperty_suballoc_detach();
extern void* jscomplexproperty_suballoc();
extern void jscomplexproperty_suballoc_free(IJSComplexProperty* p);
#endif