simComponent.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "console/simObject.h"
  24. #include "console/consoleTypes.h"
  25. #include "component/simComponent.h"
  26. #include "core/stream/stream.h"
  27. SimComponent::SimComponent() : mOwner( NULL )
  28. {
  29. mComponentList.clear();
  30. mMutex = Mutex::createMutex();
  31. mEnabled = true;
  32. mTemplate = false;
  33. }
  34. SimComponent::~SimComponent()
  35. {
  36. Mutex::destroyMutex( mMutex );
  37. mMutex = NULL;
  38. }
  39. IMPLEMENT_CO_NETOBJECT_V1(SimComponent);
  40. ConsoleDocClass( SimComponent,
  41. "@brief Legacy component system, soon to be deprecated.\n\n"
  42. "Not intended for game development, for editors or internal use only.\n\n "
  43. "@internal");
  44. bool SimComponent::onAdd()
  45. {
  46. if( !Parent::onAdd() )
  47. return false;
  48. // Register
  49. _registerInterfaces( this );
  50. if( !_registerComponents( this ) )
  51. return false;
  52. //Con::executef( this, 1, "onAdd" );
  53. return true;
  54. }
  55. void SimComponent::_registerInterfaces( SimComponent *owner )
  56. {
  57. // First call this to expose the interfaces that this component will cache
  58. // before examining the list of subcomponents
  59. registerInterfaces( owner );
  60. // Early out to avoid mutex lock and such
  61. if( !hasComponents() )
  62. return;
  63. VectorPtr<SimComponent *> &components = lockComponentList();
  64. for( SimComponentIterator i = components.begin(); i != components.end(); i++ )
  65. {
  66. (*i)->mOwner = owner;
  67. // Tell the component itself to register it's interfaces
  68. (*i)->registerInterfaces( owner );
  69. (*i)->mOwner = NULL; // This tests to see if the object's onComponentRegister call will call up to the parent.
  70. // Recurse
  71. (*i)->_registerInterfaces( owner );
  72. }
  73. unlockComponentList();
  74. }
  75. bool SimComponent::_registerComponents( SimComponent *owner )
  76. {
  77. // This method will return true if the object contains no components. See the
  78. // documentation for SimComponent::onComponentRegister for more information
  79. // on this behavior.
  80. bool ret = true;
  81. // If this doesn't contain components, don't even lock the list.
  82. if( hasComponents() )
  83. {
  84. VectorPtr<SimComponent *> &components = lockComponentList();
  85. for( SimComponentIterator i = components.begin(); i != components.end(); i++ )
  86. {
  87. if( !(*i)->onComponentRegister( owner ) )
  88. {
  89. ret = false;
  90. break;
  91. }
  92. AssertFatal( (*i)->mOwner == owner, "Component failed to call parent onComponentRegister!" );
  93. // Recurse
  94. if( !(*i)->_registerComponents( owner ) )
  95. {
  96. ret = false;
  97. break;
  98. }
  99. }
  100. unlockComponentList();
  101. }
  102. return ret;
  103. }
  104. void SimComponent::_unregisterComponents()
  105. {
  106. if( !hasComponents() )
  107. return;
  108. VectorPtr<SimComponent *> &components = lockComponentList();
  109. for( SimComponentIterator i = components.begin(); i != components.end(); i++ )
  110. {
  111. (*i)->onComponentUnRegister();
  112. AssertFatal( (*i)->mOwner == NULL, "Component failed to call parent onUnRegister" );
  113. // Recurse
  114. (*i)->_unregisterComponents();
  115. }
  116. unlockComponentList();
  117. }
  118. void SimComponent::onRemove()
  119. {
  120. //Con::executef(this, 1, "onRemove");
  121. _unregisterComponents();
  122. // Delete all components
  123. VectorPtr<SimComponent *>&componentList = lockComponentList();
  124. while(componentList.size() > 0)
  125. {
  126. SimComponent *c = componentList[0];
  127. componentList.erase( componentList.begin() );
  128. if( c->isProperlyAdded() )
  129. c->deleteObject();
  130. else if( !c->isRemoved() && !c->isDeleted() )
  131. delete c;
  132. // else, something else is deleting this, don't mess with it
  133. }
  134. unlockComponentList();
  135. Parent::onRemove();
  136. }
  137. //////////////////////////////////////////////////////////////////////////
  138. bool SimComponent::processArguments(S32 argc, const char **argv)
  139. {
  140. for(S32 i = 0; i < argc; i++)
  141. {
  142. SimComponent *obj = dynamic_cast<SimComponent*> (Sim::findObject(argv[i]) );
  143. if(obj)
  144. addComponent(obj);
  145. else
  146. Con::printf("SimComponent::processArguments - Invalid Component Object \"%s\"", argv[i]);
  147. }
  148. return true;
  149. }
  150. //////////////////////////////////////////////////////////////////////////
  151. void SimComponent::initPersistFields()
  152. {
  153. addGroup("Component");
  154. addProtectedField( "Template", TypeBool, Offset(mTemplate, SimComponent),
  155. &setIsTemplate, &defaultProtectedGetFn,
  156. "Places the object in a component set for later use in new levels." );
  157. endGroup("Component");
  158. // Call Parent.
  159. Parent::initPersistFields();
  160. }
  161. //------------------------------------------------------------------------------
  162. bool SimComponent::getInterfaces( ComponentInterfaceList *list, const char *type /* = NULL */, const char *name /* = NULL */,
  163. const SimComponent *owner /* = NULL */, bool notOwner /* = false */ )
  164. {
  165. AssertFatal( list != NULL, "Passing NULL for a list is not supported functionality for SimComponents." );
  166. return ( mInterfaceCache.enumerate( list, type, name, owner, notOwner ) > 0 );
  167. }
  168. bool SimComponent::registerCachedInterface( const char *type, const char *name, SimComponent *interfaceOwner, ComponentInterface *cinterface )
  169. {
  170. if( mInterfaceCache.add( type, name, interfaceOwner, cinterface ) )
  171. {
  172. cinterface->mOwner = interfaceOwner;
  173. // Recurse
  174. if( mOwner != NULL )
  175. return mOwner->registerCachedInterface( type, name, interfaceOwner, cinterface );
  176. return true;
  177. }
  178. // So this is not a good assert, because it will get triggered due to the recursive
  179. // nature of interface caching. I want to keep it here, though, just so nobody
  180. // else thinks, "Oh I'll add an assert here."
  181. //
  182. //AssertFatal( false, avar( "registerCachedInterface failed, probably because interface with type '%s', name '%s' and owner with SimObjectId '%d' already exists",
  183. // type, name, interfaceOwner->getId() ) );
  184. return false;
  185. }
  186. //////////////////////////////////////////////////////////////////////////
  187. // Component Management
  188. //////////////////////////////////////////////////////////////////////////
  189. bool SimComponent::addComponentFromField( void* obj, const char* data )
  190. {
  191. SimComponent *pComponent = dynamic_cast<SimComponent*>( Sim::findObject( data ) );
  192. if( pComponent != NULL )
  193. static_cast<SimComponent*>(obj)->addComponent( pComponent );
  194. return false;
  195. }
  196. // Add Component to this one
  197. bool SimComponent::addComponent( SimComponent *component )
  198. {
  199. AssertFatal( dynamic_cast<SimObject*>(component), "SimComponent - Cannot add non SimObject derived components!" );
  200. MutexHandle mh;
  201. if( mh.lock( mMutex, true ) )
  202. {
  203. for( SimComponentIterator nItr = mComponentList.begin(); nItr != mComponentList.end(); nItr++ )
  204. {
  205. SimComponent *pComponent = dynamic_cast<SimComponent*>(*nItr);
  206. AssertFatal( pComponent, "SimComponent::addComponent - NULL component in list!" );
  207. if( pComponent == component )
  208. return true;
  209. }
  210. if(component->onComponentAdd(this))
  211. {
  212. component->mOwner = this;
  213. mComponentList.push_back( component );
  214. return true;
  215. }
  216. }
  217. return false;
  218. }
  219. // Remove Component from this one
  220. bool SimComponent::removeComponent( SimComponent *component )
  221. {
  222. MutexHandle mh;
  223. if( mh.lock( mMutex, true ) )
  224. {
  225. for( SimComponentIterator nItr = mComponentList.begin(); nItr != mComponentList.end(); nItr++ )
  226. {
  227. SimComponent *pComponent = dynamic_cast<SimComponent*>(*nItr);
  228. AssertFatal( pComponent, "SimComponent::removeComponent - NULL component in list!" );
  229. if( pComponent == component )
  230. {
  231. AssertFatal( component->mOwner == this, "Somehow we contain a component who doesn't think we are it's owner." );
  232. (*nItr)->onComponentRemove(this);
  233. component->mOwner = NULL;
  234. mComponentList.erase( nItr );
  235. return true;
  236. }
  237. }
  238. }
  239. return false;
  240. }
  241. //////////////////////////////////////////////////////////////////////////
  242. bool SimComponent::onComponentAdd(SimComponent *target)
  243. {
  244. Con::executef(this, "onComponentAdd", Con::getIntArg(target->getId()));
  245. return true;
  246. }
  247. void SimComponent::onComponentRemove(SimComponent *target)
  248. {
  249. Con::executef(this, "onComponentRemove", Con::getIntArg(target->getId()));
  250. }
  251. //////////////////////////////////////////////////////////////////////////
  252. ComponentInterface *SimComponent::getInterface(const char *type /* = NULL */, const char *name /* = NULL */,
  253. const SimComponent *owner /* = NULL */, bool notOwner /* = false */)
  254. {
  255. ComponentInterfaceList iLst;
  256. if( getInterfaces( &iLst, type, name, owner, notOwner ) )
  257. return iLst[0];
  258. return NULL;
  259. }
  260. //////////////////////////////////////////////////////////////////////////
  261. bool SimComponent::writeField(StringTableEntry fieldname, const char* value)
  262. {
  263. if (!Parent::writeField(fieldname, value))
  264. return false;
  265. if( fieldname == StringTable->insert("owner") )
  266. return false;
  267. return true;
  268. }
  269. void SimComponent::write(Stream &stream, U32 tabStop, U32 flags /* = 0 */)
  270. {
  271. MutexHandle handle;
  272. handle.lock(mMutex); // When this goes out of scope, it will unlock it
  273. // export selected only?
  274. if((flags & SelectedOnly) && !isSelected())
  275. {
  276. for(U32 i = 0; i < mComponentList.size(); i++)
  277. mComponentList[i]->write(stream, tabStop, flags);
  278. return;
  279. }
  280. stream.writeTabs(tabStop);
  281. char buffer[1024];
  282. dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() ? getName() : "");
  283. stream.write(dStrlen(buffer), buffer);
  284. writeFields(stream, tabStop + 1);
  285. if(mComponentList.size())
  286. {
  287. stream.write(2, "\r\n");
  288. stream.writeTabs(tabStop+1);
  289. stream.writeLine((U8 *)"// Note: This is a list of behaviors, not arbitrary SimObjects as in a SimGroup or SimSet.\r\n");
  290. for(U32 i = 0; i < mComponentList.size(); i++)
  291. mComponentList[i]->write(stream, tabStop + 1, flags);
  292. }
  293. stream.writeTabs(tabStop);
  294. stream.write(4, "};\r\n");
  295. }
  296. //////////////////////////////////////////////////////////////////////////
  297. // Console Methods
  298. //////////////////////////////////////////////////////////////////////////
  299. ConsoleMethod( SimComponent, addComponents, bool, 3, 64, "%obj.addComponents( %compObjName, %compObjName2, ... );\n"
  300. "Adds additional components to current list.\n"
  301. "@param Up to 62 component names\n"
  302. "@return Returns true on success, false otherwise.")
  303. {
  304. for(S32 i = 2; i < argc; i++)
  305. {
  306. SimComponent *obj = dynamic_cast<SimComponent*> (Sim::findObject(argv[i]) );
  307. if(obj)
  308. object->addComponent(obj);
  309. else
  310. Con::printf("SimComponent::addComponents - Invalid Component Object \"%s\"", argv[i]);
  311. }
  312. return true;
  313. }
  314. ConsoleMethod( SimComponent, removeComponents, bool, 3, 64, "%obj.removeComponents( %compObjName, %compObjName2, ... );\n"
  315. "Removes components by name from current list.\n"
  316. "@param objNamex Up to 62 component names\n"
  317. "@return Returns true on success, false otherwise.")
  318. {
  319. for(S32 i = 2; i < argc; i++)
  320. {
  321. SimComponent *obj = dynamic_cast<SimComponent*> (Sim::findObject(argv[i]) );
  322. if(obj)
  323. object->removeComponent(obj);
  324. else
  325. Con::printf("SimComponent::removeComponents - Invalid Component Object \"%s\"", argv[i]);
  326. }
  327. return true;
  328. }
  329. ConsoleMethod( SimComponent, getComponentCount, S32, 2, 2, "() Get the current component count\n"
  330. "@return The number of components in the list as an integer")
  331. {
  332. return object->getComponentCount();
  333. }
  334. ConsoleMethod( SimComponent, getComponent, S32, 3, 3, "(idx) Get the component corresponding to the given index.\n"
  335. "@param idx An integer index value corresponding to the desired component.\n"
  336. "@return The id of the component at the given index as an integer")
  337. {
  338. S32 idx = dAtoi(argv[2]);
  339. if(idx < 0 || idx >= object->getComponentCount())
  340. {
  341. Con::errorf("SimComponent::getComponent - Invalid index %d", idx);
  342. return 0;
  343. }
  344. SimComponent *c = object->getComponent(idx);
  345. return c ? c->getId() : 0;
  346. }
  347. ConsoleMethod(SimComponent, setEnabled, void, 3, 3, "(enabled) Sets or unsets the enabled flag\n"
  348. "@param enabled Boolean value\n"
  349. "@return No return value")
  350. {
  351. object->setEnabled(dAtob(argv[2]));
  352. }
  353. ConsoleMethod(SimComponent, isEnabled, bool, 2, 2, "() Check whether SimComponent is currently enabled\n"
  354. "@return true if enabled and false if not")
  355. {
  356. return object->isEnabled();
  357. }
  358. ConsoleMethod(SimComponent, setIsTemplate, void, 3, 3, "(template) Sets or unsets the template flag\n"
  359. "@param template Boolean value\n"
  360. "@return No return value")
  361. {
  362. object->setIsTemplate(dAtob(argv[2]));
  363. }
  364. ConsoleMethod(SimComponent, getIsTemplate, bool, 2, 2, "() Check whether SimComponent is currently a template\n"
  365. "@return true if is a template and false if not")
  366. {
  367. return object->getIsTemplate();
  368. }