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 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
