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