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
100      enum SetModification
101      {
102         SetCleared,
103         SetObjectAdded,
104         SetObjectRemoved
105      };
106
107      /// Signal for letting observers know when objects are added to or removed from
108      /// the set.
109      ///
110      /// @param modification In what way the set has been modified.
111      /// @param set The set that has been modified.
112      /// @param object If #modification is #SetObjectAdded or #SetObjectRemoved, this is
113      ///   the object that has been added or removed.  Otherwise NULL.
114      typedef Signal< void( SetModification modification, SimSet* set, SimObject* object ) > SetModificationSignal;
115
116   protected:
117
118      SimObjectList objectList;
119      void *mMutex;
120
121      /// Signal that is triggered when objects are added or removed from the set.
122      SetModificationSignal mSetModificationSignal;
123      
124      /// @name Callbacks
125      /// @{
126      
127      DECLARE_CALLBACK( void, onObjectAdded, ( SimObject* object ) );
128      DECLARE_CALLBACK( void, onObjectRemoved, ( SimObject* object ) );
129      
130      /// @}
131
132   public:
133
134      SimSet();
135      ~SimSet();
136
137      /// Return the signal that is triggered when an object is added to or removed
138      /// from the set.
139      const SetModificationSignal& getSetModificationSignal() const { return mSetModificationSignal; }
140      SetModificationSignal& getSetModificationSignal() { return mSetModificationSignal; }
141
142      /// @name STL Interface
143      /// @{
144
145      ///
146      typedef SimObjectList::iterator iterator;
147      typedef SimObjectList::value_type value;
148      SimObject* front() { return objectList.front(); }
149      SimObject* first() { return objectList.first(); }
150      SimObject* last()  { return objectList.last(); }
151      bool       empty() const { return objectList.empty();   }
152      S32        size() const  { return objectList.size(); }
153      iterator   begin() { return objectList.begin(); }
154      iterator   end()   { return objectList.end(); }
155      value operator[](S32 index) { return objectList[U32(index)]; }
156
157      inline iterator find( iterator first, iterator last, SimObject *obj)
158      { return ::find(first, last, obj); }
159      inline iterator find(SimObject *obj) 
160      { return ::find(begin(), end(), obj); }
161
162      /// Reorder the position of "obj" to either be the last object in the list or, if
163      /// "target" is given, to come before "target" in the list of children.
164      virtual bool reOrder( SimObject *obj, SimObject *target=0 );
165      
166      /// Return the object at the given index.
167      SimObject* at(S32 index) const { return objectList.at(index); }
168
169      /// Remove all objects from this set.
170      virtual void clear();
171      
172      /// @}
173
174      /// @name Set Management
175      /// @{
176
177      /// Add the given object to the set.
178      /// @param object Object to add to the set.
179      virtual void addObject( SimObject* object );
180      
181      /// Remove the given object from the set.
182      /// @param object Object to remove from the set.
183      virtual void removeObject( SimObject* object );
184
185      /// Add the given object to the end of the object list of this set.
186      /// @param object Object to add to the set.
187      virtual void pushObject( SimObject* object );
188      
189      /// Return true if this set accepts the given object as a child.
190      /// This method should be overridden for set classes that restrict membership.
191      virtual bool acceptsAsChild( SimObject* object ) const { return true; }
192      
193      /// Deletes all the objects in the set.
194      void deleteAllObjects();
195
196      /// Remove an object from the end of the list.
197      virtual void popObject();
198
199      void bringObjectToFront(SimObject* obj) { reOrder(obj, front()); }
200      void pushObjectToBack(SimObject* obj) { reOrder(obj, NULL); }
201
202      /// Performs a sort of the objects in the set using a script
203      /// callback function to do the comparison.
204      ///
205      /// An example script sort callback:
206      ///
207      /// @code
208      ///   function sortByName( %object1, %object2 )
209      ///   {
210      ///      return strcmp( %object1.getName(), %object2.getName() );
211      ///   }
212      /// @endcode
213      ///
214      /// Note: You should never modify the SimSet itself while in
215      /// the sort callback function as it can cause a deadlock.
216      ///
217      void scriptSort( const String &scriptCallbackFn );
218      
219      /// @}
220
221      void callOnChildren( const String &method, S32 argc, ConsoleValueRef argv[], bool executeOnChildGroups = true );
222
223      /// Return the number of objects in this set as well as all sets that are contained
224      /// in this set and its children.
225      ///
226      /// @note The child sets themselves count towards the total too.
227      U32 sizeRecursive();
228
229      virtual SimObject* findObjectByInternalName(StringTableEntry internalName, bool searchChildren = false);
230      SimObject* findObjectByLineNumber(const char* fileName, S32 declarationLine, bool searchChildren = false);   
231
232      /// Find the given object in this set.  Returns NULL if the object
233      /// is not part of this set.
234      SimObject* findObject( SimObject* object );
235
236      /// Add all child objects ( including children of children ) to the foundObjects
237      /// Vector which are of type T.
238
239      template< class T >
240      void findObjectByType( Vector<T*> &foundObjects );
241
242      /// Add all child objects ( including children of children ) to the foundObjects
243      /// Vector which are of type T and for which DecideAddObjectCallback return true;   
244
245      template< class T > 
246      void findObjectByCallback( bool ( *fn )( T* ), Vector<T*>& foundObjects );   
247      
248      SimObject* getRandom();
249
250      inline void lock()
251      {
252         #ifdef TORQUE_MULTITHREAD
253         Mutex::lockMutex(mMutex);
254         #endif
255      }
256
257      void unlock()
258      {
259         #ifdef TORQUE_MULTITHREAD
260         Mutex::unlockMutex(mMutex);
261         #endif
262      }
263
264      #ifdef TORQUE_DEBUG_GUARD
265      inline void _setVectorAssoc( const char *file, const U32 line )
266      {
267         objectList.setFileAssociation( file, line );
268      }
269      #endif
270
271      // SimObject.
272      DECLARE_CONOBJECT( SimSet );
273
274      virtual void onRemove();
275      virtual void onDeleteNotify(SimObject *object);
276
277      virtual SimObject* findObject( const char* name );
278
279      virtual void write(Stream &stream, U32 tabStop, U32 flags = 0);
280      virtual bool writeObject(Stream *stream);
281      virtual bool readObject(Stream *stream);
282
283      virtual SimSet* clone();
284
285      // TamlChildren
286      virtual U32 getTamlChildCount(void) const
287      {
288         return (U32)size();
289      }
290
291      virtual SimObject* getTamlChild(const U32 childIndex) const
292      {
293         // Sanity!
294         AssertFatal(childIndex < (U32)size(), "SimSet::getTamlChild() - Child index is out of range.");
295
296         // For when the assert is not used.
297         if (childIndex >= (U32)size())
298            return NULL;
299
300         return at(childIndex);
301      }
302
303      virtual void addTamlChild(SimObject* pSimObject)
304      {
305         // Sanity!
306         AssertFatal(pSimObject != NULL, "SimSet::addTamlChild() - Cannot add a NULL child object.");
307
308         addObject(pSimObject);
309      }
310};
311
312#ifdef TORQUE_DEBUG_GUARD
313#  define SIMSET_SET_ASSOCIATION( x ) x._setVectorAssoc( __FILE__, __LINE__ )
314#else
315#  define SIMSET_SET_ASSOCIATION( x )
316#endif
317
318template< class T >
319void SimSet::findObjectByType( Vector<T*> &foundObjects )
320{
321   T *curObj;
322   SimSet *curSet;
323
324   lock();
325
326   // Loop through our child objects.
327
328   SimObjectList::iterator itr = objectList.begin();   
329
330   for ( ; itr != objectList.end(); itr++ )
331   {
332      curObj = dynamic_cast<T*>( *itr );
333      curSet = dynamic_cast<SimSet*>( *itr );
334
335      // If child object is a set, call recursively into it.
336      if ( curSet )
337         curSet->findObjectByType( foundObjects ); 
338
339      // Add this child object if appropriate.
340      if ( curObj )
341         foundObjects.push_back( curObj );      
342   }
343
344   // Add this object if appropriate.
345   curObj = dynamic_cast<T*>(this);
346   if ( curObj )      
347      foundObjects.push_back( curObj );
348
349   unlock();
350}
351
352template< class T > 
353void SimSet::findObjectByCallback(  bool ( *fn )( T* ), Vector<T*> &foundObjects )
354{
355   T *curObj;
356   SimSet *curSet;
357
358   lock();
359
360   // Loop through our child objects.
361
362   SimObjectList::iterator itr = objectList.begin();   
363
364   for ( ; itr != objectList.end(); itr++ )
365   {
366      curObj = dynamic_cast<T*>( *itr );
367      curSet = dynamic_cast<SimSet*>( *itr );
368
369      // If child object is a set, call recursively into it.
370      if ( curSet )
371         curSet->findObjectByCallback( fn, foundObjects ); 
372
373      // Add this child object if appropriate.
374      if ( curObj && ( fn == NULL || fn( curObj ) ) )
375         foundObjects.push_back( curObj );      
376   }
377
378   // Add this object if appropriate.
379   curObj = dynamic_cast<T*>(this);
380   if ( curObj && ( fn == NULL || fn( curObj ) ) )      
381      foundObjects.push_back( curObj );
382
383   unlock();
384}
385
386/// An iterator that recursively and exhaustively traverses the contents
387/// of a SimSet.
388///
389/// @see SimSet
390class SimSetIterator
391{
392protected:
393   struct Entry {
394      SimSet* set;
395      SimSet::iterator itr;
396   };
397   class Stack: public Vector<Entry> {
398   public:
399      void push_back(SimSet*);
400   };
401   Stack stack;
402
403public:
404   SimSetIterator(SimSet*);
405   SimObject* operator++();
406   SimObject* operator*() {
407      return stack.empty()? 0: *stack.last().itr;
408   }
409};
410
411//---------------------------------------------------------------------------
412/// A group of SimObjects.
413///
414/// A SimGroup is a stricter form of SimSet. SimObjects may only be a member
415/// of a single SimGroup at a time.
416///
417/// The SimGroup will automatically enforce the single-group-membership rule.
418///
419/// @code
420///      // From engine/sim/simPath.cc - getting a pointer to a SimGroup
421///      SimGroup* pMissionGroup = dynamic_cast<SimGroup*>(Sim::findObject("MissionGroup"));
422///
423///      // From game/trigger.cc:46 - iterating over a SimObject's group.
424///      SimObject* trigger = ...;
425///      SimGroup* pGroup = trigger->getGroup();
426///      for (SimGroup::iterator itr = pGroup->begin(); itr != pGroup->end(); itr++)
427///      {
428///         // do something with *itr
429///      }
430/// @endcode
431class SimGroup: public SimSet
432{
433   public:
434   
435      typedef SimSet Parent;
436
437      friend class SimManager;
438      friend class SimObject;
439
440   private:
441
442      SimNameDictionary mNameDictionary;
443
444      void _addObject( SimObject* object, bool forcePushBack = false );
445      void _removeObjectNoLock( SimObject* );
446
447   public:
448
449      ~SimGroup();
450
451      void addObject( SimObject* object, SimObjectId id);
452      void addObject( SimObject* object, const char* name );
453
454      // SimSet.
455      virtual void addObject( SimObject* object );
456      virtual void removeObject( SimObject* object );
457      virtual void pushObject( SimObject* object );
458      virtual void popObject();
459      virtual void clear();
460      
461      virtual SimGroup* clone();
462      virtual SimGroup* deepClone();
463
464      virtual SimObject* findObject(const char* name);
465      virtual void onRemove();
466
467      virtual bool processArguments( S32 argc, ConsoleValueRef *argv );
468
469      DECLARE_CONOBJECT( SimGroup );
470};
471
472inline void SimGroup::addObject(SimObject* obj, SimObjectId id)
473{
474   obj->mId = id;
475   dSprintf( obj->mIdString, sizeof( obj->mIdString ), "%u", obj->mId );
476   addObject( obj );
477}
478
479inline void SimGroup::addObject(SimObject *obj, const char *name)
480{
481   addObject( obj );
482   obj->assignName(name);
483}
484
485/// An iterator that recursively and exhaustively traverses all objects
486/// in an SimGroup object tree.
487class SimGroupIterator: public SimSetIterator
488{
489public:
490   SimGroupIterator(SimGroup* grp): SimSetIterator(grp) {}
491   SimObject* operator++();
492};
493
494#endif // _SIMSET_H_
495