//----------------------------------------------------------------------------- // Copyright (c) 2013 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- // [tom, 3/9/2007] To avoid having to change pretty much every source file, this // header is included from simBase.h where the original definitions of SimSet and // SimGroup were. simSet.h should not be included directly. Include dependencies // are hell. #ifndef _SIMSET_H_ #define _SIMSET_H_ #ifndef _SIM_OBJECT_H_ #include "sim/simObject.h" #endif #ifndef _SIM_OBJECT_LIST_H_ #include "sim/SimObjectList.h" #endif #ifndef _FIND_ITERATOR_H_ #include "collection/findIterator.h" #endif #ifndef _SIMDICTIONARY_H_ #include "sim/simDictionary.h" #endif #ifndef _TAML_CHILDREN_H_ #include "persistence/taml/tamlChildren.h" #endif //--------------------------------------------------------------------------- /// A set of SimObjects. /// /// It is often necessary to keep track of an arbitrary set of SimObjects. /// For instance, Torque's networking code needs to not only keep track of /// the set of objects which need to be ghosted, but also the set of objects /// which must always be ghosted. It does this by working with two /// sets. The first of these is the RootGroup (which is actually a SimGroup) /// and the second is the GhostAlwaysSet, which contains objects which must /// always be ghosted to the client. /// /// Some general notes on SimSets: /// - Membership is not exclusive. A SimObject may be a member of multiple /// SimSets. /// - A SimSet does not destroy subobjects when it is destroyed. /// - A SimSet may hold an arbitrary number of objects. /// /// Using SimSets, the code to work with these two sets becomes /// relatively straightforward: /// /// @code /// // (Example from netObject.cc) /// // To iterate over all the objects in the Sim: /// for (SimSetIterator obj(Sim::getRootGroup()); *obj; ++obj) /// { /// NetObject* nobj = dynamic_cast(*obj); /// /// if (nobj) /// { /// // ... do things ... /// } /// } /// /// // (Example from netGhost.cc) /// // To iterate over the ghostAlways set. /// SimSet* ghostAlwaysSet = Sim::getGhostAlwaysSet(); /// SimSet::iterator i; /// /// U32 sz = ghostAlwaysSet->size(); /// S32 j; /// /// for(i = ghostAlwaysSet->begin(); i != ghostAlwaysSet->end(); i++) /// { /// NetObject *obj = (NetObject *)(*i); /// /// /// ... do things with obj... /// } /// @endcode /// class SimSet: public SimObject, public TamlChildren { typedef SimObject Parent; typedef SimObject Children; protected: SimObjectList objectList; void *mMutex; public: SimSet() { VECTOR_SET_ASSOCIATION(objectList); mMutex = Mutex::createMutex(); } ~SimSet() { lock(); unlock(); Mutex::destroyMutex(mMutex); mMutex = NULL; } /// @name STL Interface /// @{ /// typedef SimObjectList::iterator iterator; typedef SimObjectList::value_type value; SimObject* front() { return objectList.front(); } SimObject* first() { return objectList.first(); } SimObject* last() { return objectList.last(); } bool empty() { return objectList.empty(); } S32 size() const { return objectList.size(); } iterator begin() { return objectList.begin(); } iterator end() { return objectList.end(); } value operator[] (S32 index) { return objectList[U32(index)]; } inline iterator find( iterator first, iterator last, SimObject *obj ) { return ::find(first, last, obj); } inline iterator find( SimObject *obj ) { return ::find(begin(), end(), obj); } template inline bool containsType( void ) { for( iterator itr = begin(); itr != end(); ++itr ) { if ( dynamic_cast(*itr) != NULL ) return true; } return false; } bool isMember(SimObject* obj); virtual bool reOrder( SimObject *obj, SimObject *target=0 ); SimObject* at(S32 index) const { return objectList.at(index); } void deleteObjects( void ); void clear(); /// @} virtual void onRemove(); virtual void onDeleteNotify(SimObject *object); /// @name Set Management /// @{ virtual void addObject(SimObject*); ///< Add an object to the set. virtual void removeObject(SimObject*); ///< Remove an object from the set. virtual void pushObject(SimObject*); ///< Add object to end of list. /// /// It will force the object to the end of the list if it already exists /// in the list. virtual void popObject(); ///< Remove an object from the end of the list. void bringObjectToFront(SimObject* obj) { reOrder(obj, front()); } void pushObjectToBack(SimObject* obj) { reOrder(obj, NULL); } /// @} virtual U32 getTamlChildCount( void ) const { return (U32)size(); } virtual SimObject* getTamlChild( const U32 childIndex ) const { // Sanity! AssertFatal( childIndex < (U32)size(), "SimSet::getTamlChild() - Child index is out of range." ); // For when the assert is not used. if ( childIndex >= (U32)size() ) return NULL; return at( childIndex ); } virtual void addTamlChild( SimObject* pSimObject ) { // Sanity! AssertFatal( pSimObject != NULL, "SimSet::addTamlChild() - Cannot add a NULL child object." ); addObject( pSimObject ); } void callOnChildren( const char * method, S32 argc, const char *argv[], bool executeOnChildGroups = true ); virtual void write(Stream &stream, U32 tabStop, U32 flags = 0); virtual SimObject *findObject(const char *name); SimObject* findObjectByInternalName(const char* internalName, bool searchChildren = false); virtual bool writeObject(Stream *stream); virtual bool readObject(Stream *stream); inline void lock() { #ifdef TORQUE_MULTITHREAD Mutex::lockMutex(mMutex); #endif } inline void unlock() { #ifdef TORQUE_MULTITHREAD Mutex::unlockMutex(mMutex); #endif } DECLARE_CONOBJECT(SimSet); #ifdef TORQUE_DEBUG inline void _setVectorAssoc( const char *file, const U32 line ) { objectList.setFileAssociation( file, line ); } #endif }; #ifdef TORQUE_DEBUG # define SIMSET_SET_ASSOCIATION( x ) x._setVectorAssoc( __FILE__, __LINE__ ) #else # define SIMSET_SET_ASSOCIATION( x ) #endif /// Iterator for use with SimSets /// /// @see SimSet class SimSetIterator { protected: struct Entry { SimSet* set; SimSet::iterator itr; }; class Stack: public Vector { public: void push_back(SimSet*); }; Stack stack; public: SimSetIterator(SimSet*); SimObject* operator++(); SimObject* operator*() { return stack.empty()? 0: *stack.last().itr; } }; //--------------------------------------------------------------------------- /// A group of SimObjects. /// /// A SimGroup is a stricter form of SimSet. SimObjects may only be a member /// of a single SimGroup at a time. /// /// The SimGroup will automatically enforce the single-group-membership rule. /// /// @code /// // From engine/sim/simPath.cc - getting a pointer to a SimGroup /// SimGroup* pMissionGroup = dynamic_cast(Sim::findObject("MissionGroup")); /// /// // From game/trigger.cc:46 - iterating over a SimObject's group. /// SimObject* trigger = ...; /// SimGroup* pGroup = trigger->getGroup(); /// for (SimGroup::iterator itr = pGroup->begin(); itr != pGroup->end(); itr++) /// { /// // do something with *itr /// } /// @endcode class SimGroup: public SimSet { private: friend class SimManager; friend class SimObject; typedef SimSet Parent; SimNameDictionary nameDictionary; public: ~SimGroup(); /// Add an object to the group. virtual void addObject(SimObject*); void addObject(SimObject*, SimObjectId); void addObject(SimObject*, const char *name); /// Remove an object from the group. virtual void removeObject(SimObject*); virtual void onRemove(); virtual void onChildRemoved(SimObject*); /// Find an object in the group. virtual SimObject* findObject(const char* name); bool processArguments(S32 argc, const char **argv); DECLARE_CONOBJECT(SimGroup); }; inline void SimGroup::addObject(SimObject* obj, SimObjectId id) { obj->mId = id; addObject( obj ); } inline void SimGroup::addObject(SimObject *obj, const char *name) { addObject( obj ); obj->assignName(name); } class SimGroupIterator: public SimSetIterator { public: SimGroupIterator(SimGroup* grp): SimSetIterator(grp) {} SimObject* operator++(); }; #endif // _SIMSET_H_