simSet.h
Engine/source/console/simSet.h
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
define
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