simSet.h

Engine/source/console/simSet.h

More...

Classes:

class

A group of SimObjects.

class

An iterator that recursively and exhaustively traverses all objects in an SimGroup object tree.

class

A set of SimObjects.

class

An iterator that recursively and exhaustively traverses the contents of a SimSet.

Public Defines

Detailed Description

Public Defines

SIMSET_SET_ASSOCIATION(x) 
  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#ifndef _SIMSET_H_
 25#define _SIMSET_H_
 26
 27#ifndef _SIMOBJECT_H_
 28#include "console/simObject.h"
 29#endif
 30
 31#ifndef _SIMOBJECTLIST_H_
 32#include "console/simObjectList.h"
 33#endif
 34
 35#ifndef _SIMDICTIONARY_H_
 36#include "console/simDictionary.h"
 37#endif
 38
 39#ifndef _TSIGNAL_H_
 40#include "core/util/tSignal.h"
 41#endif
 42
 43#include "persistence/taml/tamlChildren.h"
 44
 45//---------------------------------------------------------------------------
 46/// A set of SimObjects.
 47///
 48/// It is often necessary to keep track of an arbitrary set of SimObjects.
 49/// For instance, Torque's networking code needs to not only keep track of
 50/// the set of objects which need to be ghosted, but also the set of objects
 51/// which must <i>always</i> be ghosted. It does this by working with two
 52/// sets. The first of these is the RootGroup (which is actually a SimGroup)
 53/// and the second is the GhostAlwaysSet, which contains objects which must
 54/// always be ghosted to the client.
 55///
 56/// Some general notes on SimSets:
 57///     - Membership is not exclusive. A SimObject may be a member of multiple
 58///       SimSets.
 59///     - A SimSet does not destroy subobjects when it is destroyed.
 60///     - A SimSet may hold an arbitrary number of objects.
 61///
 62/// Using SimSets, the code to work with these two sets becomes
 63/// relatively straightforward:
 64///
 65/// @code
 66///        // (Example from netObject.cc)
 67///        // To iterate over all the objects in the Sim:
 68///        for (SimSetIterator obj(Sim::getRootGroup()); *obj; ++obj)
 69///        {
 70///                  NetObject* nobj = dynamic_cast<NetObject*>(*obj);
 71///
 72///                 if (nobj)
 73///                   {
 74///                     // ... do things ...
 75///                 }
 76///         }
 77///
 78///         // (Example from netGhost.cc)
 79///         // To iterate over the ghostAlways set.
 80///         SimSet* ghostAlwaysSet = Sim::getGhostAlwaysSet();
 81///         SimSet::iterator i;
 82///
 83///         U32 sz = ghostAlwaysSet->size();
 84///         S32 j;
 85///
 86///         for(i = ghostAlwaysSet->begin(); i != ghostAlwaysSet->end(); i++)
 87///         {
 88///             NetObject *obj = (NetObject *)(*i);
 89///
 90///             /// ... do things with obj...
 91///         }
 92/// @endcode
 93///
 94class SimSet : public SimObject, public TamlChildren
 95{
 96   public:
 97
 98      typedef SimObject Parent;
 99      typedef SimObject Children;
100
101      enum SetModification
102      {
103         SetCleared,
104         SetObjectAdded,
105         SetObjectRemoved
106      };
107
108      /// Signal for letting observers know when objects are added to or removed from
109      /// the set.
110      ///
111      /// @param modification In what way the set has been modified.
112      /// @param set The set that has been modified.
113      /// @param object If #modification is #SetObjectAdded or #SetObjectRemoved, this is
114      ///   the object that has been added or removed.  Otherwise NULL.
115      typedef Signal< void( SetModification modification, SimSet* set, SimObject* object ) > SetModificationSignal;
116
117   protected:
118
119      SimObjectList mObjectList;
120      void *mMutex;
121
122      /// Signal that is triggered when objects are added or removed from the set.
123      SetModificationSignal mSetModificationSignal;
124      
125      /// @name Callbacks
126      /// @{
127      
128      DECLARE_CALLBACK( void, onObjectAdded, ( SimObject* object ) );
129      DECLARE_CALLBACK( void, onObjectRemoved, ( SimObject* object ) );
130      
131      /// @}
132
133   public:
134
135      SimSet();
136      ~SimSet();
137
138      /// Return the signal that is triggered when an object is added to or removed
139      /// from the set.
140      const SetModificationSignal& getSetModificationSignal() const { return mSetModificationSignal; }
141      SetModificationSignal& getSetModificationSignal() { return mSetModificationSignal; }
142
143      /// @name STL Interface
144      /// @{
145
146      ///
147      typedef SimObjectList::iterator iterator;
148      typedef SimObjectList::value_type value;
149      SimObject* front() { return mObjectList.front(); }
150      SimObject* first() { return mObjectList.first(); }
151      SimObject* last()  { return mObjectList.last(); }
152      bool       empty() const { return mObjectList.empty();   }
153      S32        size() const  { return mObjectList.size(); }
154      iterator   begin() { return mObjectList.begin(); }
155      iterator   end()   { return mObjectList.end(); }
156      value operator[](S32 index) { return mObjectList[U32(index)]; }
157
158      inline iterator find( iterator first, iterator last, SimObject *obj)
159      { return T3D::find(first, last, obj); }
160      inline iterator find(SimObject *obj) 
161      { return T3D::find(begin(), end(), obj); }
162
163      /// Reorder the position of "obj" to either be the last object in the list or, if
164      /// "target" is given, to come before "target" in the list of children.
165      virtual bool reOrder( SimObject *obj, SimObject *target=0 );
166      
167      /// Return the object at the given index.
168      SimObject* at(S32 index) const { return mObjectList.at(index); }
169
170      /// Remove all objects from this set.
171      virtual void clear();
172      
173      /// @}
174
175      /// @name Set Management
176      /// @{
177
178      /// Add the given object to the set.
179      /// @param object Object to add to the set.
180      virtual void addObject( SimObject* object );
181      
182      /// Remove the given object from the set.
183      /// @param object Object to remove from the set.
184      virtual void removeObject( SimObject* object );
185
186      /// Add the given object to the end of the object list of this set.
187      /// @param object Object to add to the set.
188      virtual void pushObject( SimObject* object );
189      
190      /// Return true if this set accepts the given object as a child.
191      /// This method should be overridden for set classes that restrict membership.
192      virtual bool acceptsAsChild( SimObject* object ) const { return true; }
193      
194      /// Deletes all the objects in the set.
195      void deleteAllObjects();
196
197      /// Remove an object from the end of the list.
198      virtual void popObject();
199
200      void bringObjectToFront(SimObject* obj) { reOrder(obj, front()); }
201      void pushObjectToBack(SimObject* obj) { reOrder(obj, NULL); }
202
203      /// Performs a sort of the objects in the set using a script
204      /// callback function to do the comparison.
205      ///
206      /// An example script sort callback:
207      ///
208      /// @code
209      ///   function sortByName( %object1, %object2 )
210      ///   {
211      ///      return strcmp( %object1.getName(), %object2.getName() );
212      ///   }
213      /// @endcode
214      ///
215      /// Note: You should never modify the SimSet itself while in
216      /// the sort callback function as it can cause a deadlock.
217      ///
218      void scriptSort( const String &scriptCallbackFn );
219      
220      /// @}
221
222      void callOnChildren( const String &method, S32 argc, ConsoleValueRef argv[], bool executeOnChildGroups = true );
223
224      /// Return the number of objects in this set as well as all sets that are contained
225      /// in this set and its children.
226      ///
227      /// @note The child sets themselves count towards the total too.
228      U32 sizeRecursive();
229
230      virtual SimObject* findObjectByInternalName(StringTableEntry internalName, bool searchChildren = false);
231      SimObject* findObjectByLineNumber(const char* fileName, S32 declarationLine, bool searchChildren = false);   
232
233      /// Find the given object in this set.  Returns NULL if the object
234      /// is not part of this set.
235      SimObject* findObject( SimObject* object );
236
237      /// Add all child objects ( including children of children ) to the foundObjects
238      /// Vector which are of type T.
239
240      template< class T >
241      void findObjectByType( Vector<T*> &foundObjects );
242
243      /// Add all child objects ( including children of children ) to the foundObjects
244      /// Vector which are of type T and for which DecideAddObjectCallback return true;   
245
246      template< class T > 
247      void findObjectByCallback( bool ( *fn )( T* ), Vector<T*>& foundObjects );   
248      
249      SimObject* getRandom();
250
251      inline void lock()
252      {
253         #ifdef TORQUE_MULTITHREAD
254         Mutex::lockMutex(mMutex);
255         #endif
256      }
257
258      void unlock()
259      {
260         #ifdef TORQUE_MULTITHREAD
261         Mutex::unlockMutex(mMutex);
262         #endif
263      }
264
265      #ifdef TORQUE_DEBUG_GUARD
266      inline void _setVectorAssoc( const char *file, const U32 line )
267      {
268        mObjectList.setFileAssociation( file, line );
269      }
270      #endif
271
272      // SimObject.
273      DECLARE_CONOBJECT( SimSet );
274
275      virtual void onRemove();
276      virtual void onDeleteNotify(SimObject *object);
277
278      virtual SimObject* findObject( const char* name );
279
280      virtual void write(Stream &stream, U32 tabStop, U32 flags = 0);
281      virtual bool writeObject(Stream *stream);
282      virtual bool readObject(Stream *stream);
283
284      virtual SimSet* clone();
285
286      // TamlChildren
287      virtual U32 getTamlChildCount(void) const
288      {
289         return (U32)size();
290      }
291
292      virtual SimObject* getTamlChild(const U32 childIndex) const
293      {
294         // Sanity!
295         AssertFatal(childIndex < (U32)size(), "SimSet::getTamlChild() - Child index is out of range.");
296
297         // For when the assert is not used.
298         if (childIndex >= (U32)size())
299            return NULL;
300
301         return at(childIndex);
302      }
303
304      virtual void addTamlChild(SimObject* pSimObject)
305      {
306         // Sanity!
307         AssertFatal(pSimObject != NULL, "SimSet::addTamlChild() - Cannot add a NULL child object.");
308
309         addObject(pSimObject);
310      }
311};
312
313#ifdef TORQUE_DEBUG_GUARD
314#  define SIMSET_SET_ASSOCIATION( x ) x._setVectorAssoc( __FILE__, __LINE__ )
315#else
316#  define SIMSET_SET_ASSOCIATION( x )
317#endif
318
319template< class T >
320void SimSet::findObjectByType( Vector<T*> &foundObjects )
321{
322   T *curObj;
323   SimSet *curSet;
324
325   lock();
326
327   // Loop through our child objects.
328
329   SimObjectList::iterator itr = mObjectList.begin();   
330
331   for ( ; itr != mObjectList.end(); itr++ )
332   {
333      curObj = dynamic_cast<T*>( *itr );
334      curSet = dynamic_cast<SimSet*>( *itr );
335
336      // If child object is a set, call recursively into it.
337      if ( curSet && curSet->size() != 0)
338         curSet->findObjectByType( foundObjects ); 
339
340      // Add this child object if appropriate.
341      if ( curObj )
342         foundObjects.push_back( curObj );      
343   }
344
345   // Add this object if appropriate.
346   curObj = dynamic_cast<T*>(this);
347   if ( curObj )      
348      foundObjects.push_back( curObj );
349
350   unlock();
351}
352
353template< class T > 
354void SimSet::findObjectByCallback(  bool ( *fn )( T* ), Vector<T*> &foundObjects )
355{
356   T *curObj;
357   SimSet *curSet;
358
359   lock();
360
361   // Loop through our child objects.
362
363   SimObjectList::iterator itr = mObjectList.begin();
364
365   for ( ; itr != mObjectList.end(); itr++ )
366   {
367      curObj = dynamic_cast<T*>( *itr );
368      curSet = dynamic_cast<SimSet*>( *itr );
369
370      // If child object is a set, call recursively into it.
371      if ( curSet )
372         curSet->findObjectByCallback( fn, foundObjects ); 
373
374      // Add this child object if appropriate.
375      if ( curObj && ( fn == NULL || fn( curObj ) ) )
376         foundObjects.push_back( curObj );      
377   }
378
379   // Add this object if appropriate.
380   curObj = dynamic_cast<T*>(this);
381   if ( curObj && ( fn == NULL || fn( curObj ) ) )      
382      foundObjects.push_back( curObj );
383
384   unlock();
385}
386
387/// An iterator that recursively and exhaustively traverses the contents
388/// of a SimSet.
389///
390/// @see SimSet
391class SimSetIterator
392{
393protected:
394   struct Entry {
395      SimSet* set;
396      SimSet::iterator itr;
397   };
398   class Stack: public Vector<Entry> {
399   public:
400      void push_back(SimSet*);
401   };
402   Stack stack;
403
404public:
405   SimSetIterator(SimSet*);
406   SimObject* operator++();
407   SimObject* operator*() {
408      return stack.empty()? 0: *stack.last().itr;
409   }
410};
411
412//---------------------------------------------------------------------------
413/// A group of SimObjects.
414///
415/// A SimGroup is a stricter form of SimSet. SimObjects may only be a member
416/// of a single SimGroup at a time.
417///
418/// The SimGroup will automatically enforce the single-group-membership rule.
419///
420/// @code
421///      // From engine/sim/simPath.cc - getting a pointer to a SimGroup
422///      SimGroup* pMissionGroup = dynamic_cast<SimGroup*>(Sim::findObject("MissionGroup"));
423///
424///      // From game/trigger.cc:46 - iterating over a SimObject's group.
425///      SimObject* trigger = ...;
426///      SimGroup* pGroup = trigger->getGroup();
427///      for (SimGroup::iterator itr = pGroup->begin(); itr != pGroup->end(); itr++)
428///      {
429///         // do something with *itr
430///      }
431/// @endcode
432class SimGroup: public SimSet
433{
434   public:
435   
436      typedef SimSet Parent;
437
438      friend class SimManager;
439      friend class SimObject;
440
441   private:
442
443      SimNameDictionary mNameDictionary;
444
445      void _addObject( SimObject* object, bool forcePushBack = false );
446      void _removeObjectNoLock( SimObject* );
447
448   public:
449
450      ~SimGroup();
451
452      void addObject( SimObject* object, SimObjectId id);
453      void addObject( SimObject* object, const char* name );
454
455      // SimSet.
456      virtual void addObject( SimObject* object );
457      virtual void removeObject( SimObject* object );
458      virtual void pushObject( SimObject* object );
459      virtual void popObject();
460      virtual void clear();
461      
462      virtual SimGroup* clone();
463      virtual SimGroup* deepClone();
464
465      virtual SimObject* findObject(const char* name);
466      virtual void onRemove();
467
468      virtual bool processArguments( S32 argc, ConsoleValueRef *argv );
469
470      virtual SimObject* getObject(const S32& index);
471
472      DECLARE_CONOBJECT( SimGroup );
473};
474
475inline void SimGroup::addObject(SimObject* obj, SimObjectId id)
476{
477   obj->mId = id;
478   dSprintf( obj->mIdString, sizeof( obj->mIdString ), "%u", obj->mId );
479   addObject( obj );
480}
481
482inline void SimGroup::addObject(SimObject *obj, const char *name)
483{
484   addObject( obj );
485   obj->assignName(name);
486}
487
488/// An iterator that recursively and exhaustively traverses all objects
489/// in an SimGroup object tree.
490class SimGroupIterator: public SimSetIterator
491{
492public:
493   SimGroupIterator(SimGroup* grp): SimSetIterator(grp) {}
494   SimObject* operator++();
495};
496
497#endif // _SIMSET_H_
498