2
0

tamlCustom.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 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. #ifndef _TAML_CUSTOM_H_
  23. #define _TAML_CUSTOM_H_
  24. #ifndef _FACTORY_CACHE_H_
  25. #include "memory/factoryCache.h"
  26. #endif
  27. #ifndef _STRINGTABLE_H_
  28. #include "string/stringTable.h"
  29. #endif
  30. #ifndef _CONSOLE_H_
  31. #include "console/console.h"
  32. #endif
  33. #ifndef B2_MATH_H
  34. #include "box2d/Common/b2Math.h"
  35. #endif
  36. #ifndef _COLOR_H_
  37. #include "graphics/color.h"
  38. #endif
  39. #ifndef _SIMBASE_H_
  40. #include "sim/simBase.h"
  41. #endif
  42. #include "memory/safeDelete.h"
  43. //-----------------------------------------------------------------------------
  44. #define MAX_TAML_NODE_FIELDVALUE_LENGTH 2048
  45. //-----------------------------------------------------------------------------
  46. class TamlWriteNode;
  47. class TamlCustomNode;
  48. class TamlCustomField;
  49. extern FactoryCache<TamlCustomNode> TamlCustomNodeFactory;
  50. extern FactoryCache<TamlCustomField> TamlCustomFieldFactory;
  51. typedef Vector<TamlCustomNode*> TamlCustomNodeVector;
  52. typedef Vector<TamlCustomField*> TamlCustomFieldVector;
  53. //-----------------------------------------------------------------------------
  54. class TamlCustomField : public IFactoryObjectReset
  55. {
  56. public:
  57. TamlCustomField()
  58. {
  59. resetState();
  60. }
  61. virtual ~TamlCustomField()
  62. {
  63. // Everything should already be cleared in a state reset.
  64. // Touching any memory here is dangerous as this type is typically
  65. // held in a static factory cache until shutdown at which point
  66. // pretty much anything or everything could be invalid!
  67. }
  68. virtual void resetState( void )
  69. {
  70. mFieldName = StringTable->EmptyString;
  71. *mFieldValue = 0;
  72. }
  73. void set( const char* pFieldName, const char* pFieldValue );
  74. inline void setFieldValue( const char* pFieldName, const ColorI& fieldValue )
  75. {
  76. // Fetch the field value.
  77. const char* pFieldValue = Con::getData( TypeColorI, &const_cast<ColorI&>(fieldValue), 0 );
  78. // Did we get a field value?
  79. if ( pFieldValue == NULL )
  80. {
  81. // No, so warn.
  82. Con::warnf( "Taml: Failed to add node field name '%s' with ColorI value.", pFieldName );
  83. pFieldValue = StringTable->EmptyString;
  84. }
  85. set( pFieldName, pFieldValue );
  86. }
  87. inline void setFieldValue( const char* pFieldName, const ColorF& fieldValue )
  88. {
  89. // Fetch the field value.
  90. const char* pFieldValue = Con::getData( TypeColorF, &const_cast<ColorF&>(fieldValue), 0 );
  91. // Did we get a field value?
  92. if ( pFieldValue == NULL )
  93. {
  94. // No, so warn.
  95. Con::warnf( "Taml: Failed to add node field name '%s' with ColorF value.", pFieldName );
  96. pFieldValue = StringTable->EmptyString;
  97. }
  98. set( pFieldName, pFieldValue );
  99. }
  100. inline void setFieldValue( const char* pFieldName, const Point2I& fieldValue )
  101. {
  102. char fieldValueBuffer[32];
  103. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d %d", fieldValue.x, fieldValue.y );
  104. set( pFieldName, fieldValueBuffer );
  105. }
  106. inline void setFieldValue( const char* pFieldName, const Point2F& fieldValue )
  107. {
  108. char fieldValueBuffer[32];
  109. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %0.5g", fieldValue.x, fieldValue.y );
  110. set( pFieldName, fieldValueBuffer );
  111. }
  112. inline void setFieldValue( const char* pFieldName, const b2Vec2& fieldValue )
  113. {
  114. char fieldValueBuffer[32];
  115. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %.5g", fieldValue.x, fieldValue.y );
  116. set( pFieldName, fieldValueBuffer );
  117. }
  118. inline void setFieldValue( const char* pFieldName, const U32 fieldValue )
  119. {
  120. char fieldValueBuffer[16];
  121. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
  122. set( pFieldName, fieldValueBuffer );
  123. }
  124. inline void setFieldValue( const char* pFieldName, const bool fieldValue )
  125. {
  126. char fieldValueBuffer[16];
  127. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
  128. set( pFieldName, fieldValueBuffer );
  129. }
  130. inline void setFieldValue( const char* pFieldName, const S32 fieldValue )
  131. {
  132. char fieldValueBuffer[16];
  133. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
  134. set( pFieldName, fieldValueBuffer );
  135. }
  136. inline void setFieldValue( const char* pFieldName, const float fieldValue )
  137. {
  138. char fieldValueBuffer[16];
  139. dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g", fieldValue );
  140. set( pFieldName, fieldValueBuffer );
  141. }
  142. inline void setFieldValue( const char* pFieldName, const char* fieldValue )
  143. {
  144. set( pFieldName, fieldValue );
  145. }
  146. inline void getFieldValue( ColorF& fieldValue ) const
  147. {
  148. fieldValue.set( 1.0f, 1.0f, 1.0f, 1.0f );
  149. // Set color.
  150. const char* argv = (char*)mFieldValue;
  151. Con::setData( TypeColorF, &fieldValue, 0, 1, &argv );
  152. }
  153. inline void getFieldValue( ColorI& fieldValue ) const
  154. {
  155. fieldValue.set( 255, 255, 255, 255 );
  156. // Set color.
  157. const char* argv = (char*)mFieldValue;
  158. Con::setData( TypeColorI, &fieldValue, 0, 1, &argv );
  159. }
  160. inline void getFieldValue( Point2I& fieldValue ) const
  161. {
  162. if ( dSscanf( mFieldValue, "%d %d", &fieldValue.x, &fieldValue.y ) != 2 )
  163. {
  164. // Warn.
  165. Con::warnf( "TamlCustomField - Reading point2I but it has an incorrect format: '%s'.", mFieldValue );
  166. }
  167. }
  168. inline void getFieldValue( Point2F& fieldValue ) const
  169. {
  170. if ( dSscanf( mFieldValue, "%g %g", &fieldValue.x, &fieldValue.y ) != 2 )
  171. {
  172. // Warn.
  173. Con::warnf( "TamlCustomField - Reading point2F but it has an incorrect format: '%s'.", mFieldValue );
  174. }
  175. }
  176. inline void getFieldValue( b2Vec2& fieldValue ) const
  177. {
  178. if ( dSscanf( mFieldValue, "%g %g", &fieldValue.x, &fieldValue.y ) != 2 )
  179. {
  180. // Warn.
  181. Con::warnf( "TamlCustomField - Reading vector but it has an incorrect format: '%s'.", mFieldValue );
  182. }
  183. }
  184. inline void getFieldValue( bool& fieldValue ) const
  185. {
  186. fieldValue = dAtob( mFieldValue );
  187. }
  188. inline void getFieldValue( S32& fieldValue ) const
  189. {
  190. fieldValue = dAtoi( mFieldValue );
  191. }
  192. inline void getFieldValue( U32& fieldValue ) const
  193. {
  194. fieldValue = (U32)dAtoi( mFieldValue );
  195. }
  196. inline void getFieldValue( F32& fieldValue ) const
  197. {
  198. fieldValue = dAtof( mFieldValue );
  199. }
  200. inline const char* getFieldValue( void ) const
  201. {
  202. return mFieldValue;
  203. }
  204. inline StringTableEntry getFieldName( void ) const { return mFieldName; }
  205. bool fieldNameBeginsWith( const char* pComparison ) const
  206. {
  207. const U32 comparisonLength = dStrlen( pComparison );
  208. const U32 fieldNameLength = dStrlen( mFieldName );
  209. if ( comparisonLength == 0 || fieldNameLength == 0 || comparisonLength > fieldNameLength )
  210. return false;
  211. StringTableEntry comparison = StringTable->insert( pComparison );
  212. char fieldNameBuffer[1024];
  213. // Sanity!
  214. AssertFatal( fieldNameLength < sizeof(fieldNameBuffer), "TamlCustomField: Field name is too long." );
  215. dStrcpy( fieldNameBuffer, mFieldName );
  216. fieldNameBuffer[fieldNameLength-1] = 0;
  217. StringTableEntry fieldName = StringTable->insert( fieldNameBuffer );
  218. return ( fieldName == comparison );
  219. }
  220. inline bool isValueEmpty( void ) const { return *mFieldValue == 0; }
  221. private:
  222. StringTableEntry mFieldName;
  223. char mFieldValue[MAX_TAML_NODE_FIELDVALUE_LENGTH];
  224. };
  225. //-----------------------------------------------------------------------------
  226. class TamlCustomNode : public IFactoryObjectReset
  227. {
  228. public:
  229. TamlCustomNode()
  230. {
  231. // Reset proxy object.
  232. // NOTE: This MUST be done before the state is reset otherwise we'll be touching uninitialized stuff.
  233. mpProxyWriteNode = NULL;
  234. mpProxyObject = NULL;
  235. resetState();
  236. }
  237. virtual ~TamlCustomNode()
  238. {
  239. // Everything should already be cleared in a state reset.
  240. // Touching any memory here is dangerous as this type is typically
  241. // held in a static factory cache until shutdown at which point
  242. // pretty much anything or everything could be invalid!
  243. }
  244. virtual void resetState( void )
  245. {
  246. // We don't need to delete the write node as it'll get destroyed when the compilation is reset!
  247. mpProxyWriteNode = NULL;
  248. mpProxyObject = NULL;
  249. // Cache the children.
  250. while ( mChildren.size() > 0 )
  251. {
  252. TamlCustomNodeFactory.cacheObject( mChildren.back() );
  253. mChildren.pop_back();
  254. }
  255. // Cache the fields.
  256. while( mFields.size() > 0 )
  257. {
  258. TamlCustomFieldFactory.cacheObject( mFields.back() );
  259. mFields.pop_back();
  260. }
  261. // Reset the node name.
  262. mNodeName = StringTable->EmptyString;
  263. // Reset node text.
  264. mNodeText.resetState();
  265. // Reset the ignore empty flag.
  266. mIgnoreEmpty = false;
  267. }
  268. inline TamlCustomNode* addNode( SimObject* pProxyObject )
  269. {
  270. // Sanity!
  271. AssertFatal( pProxyObject != NULL, "Field object cannot be NULL." );
  272. AssertFatal( mpProxyWriteNode == NULL, "Field write node must be NULL." );
  273. // Create a custom node.
  274. TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
  275. // Set node name.
  276. pCustomNode->setNodeName( pProxyObject->getClassName() );
  277. // Set proxy object.
  278. pCustomNode->mpProxyObject = pProxyObject;
  279. // Store node.
  280. mChildren.push_back( pCustomNode );
  281. return pCustomNode;
  282. }
  283. inline TamlCustomNode* addNode( const char* pNodeName, const bool ignoreEmpty = true )
  284. {
  285. // Create a custom node.
  286. TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
  287. // Fetch node name.
  288. pCustomNode->setNodeName( pNodeName );
  289. // Set ignore-empty flag.
  290. pCustomNode->setIgnoreEmpty( ignoreEmpty );
  291. // Store node.
  292. mChildren.push_back( pCustomNode );
  293. return pCustomNode;
  294. }
  295. inline void removeNode( const U32 index )
  296. {
  297. // Sanity!
  298. AssertFatal( index < (U32)mChildren.size(), "tamlCustomNode::removeNode() - Index is out of bounds." );
  299. // Cache the custom node.
  300. TamlCustomNodeFactory.cacheObject( mChildren[index] );
  301. // Remove it.
  302. mChildren.erase( index );
  303. }
  304. inline const TamlCustomNode* findNode( const char* pNodeName ) const
  305. {
  306. // Sanity!
  307. AssertFatal( pNodeName != NULL, "Cannot find Taml node name that is NULL." );
  308. // Fetch node name.
  309. StringTableEntry nodeName = StringTable->insert( pNodeName );
  310. // Find node.
  311. for( Vector<TamlCustomNode*>::const_iterator nodeItr = mChildren.begin(); nodeItr != mChildren.end(); ++nodeItr )
  312. {
  313. if ( (*nodeItr)->getNodeName() == nodeName )
  314. return (*nodeItr);
  315. }
  316. return NULL;
  317. }
  318. inline TamlCustomField* addField( const char* pFieldName, const ColorI& fieldValue )
  319. {
  320. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  321. pNodeField->setFieldValue( pFieldName, fieldValue );
  322. return registerField( pNodeField );
  323. }
  324. inline TamlCustomField* addField( const char* pFieldName, const ColorF& fieldValue )
  325. {
  326. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  327. pNodeField->setFieldValue( pFieldName, fieldValue );
  328. return registerField( pNodeField );
  329. }
  330. inline TamlCustomField* addField( const char* pFieldName, const Point2I& fieldValue )
  331. {
  332. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  333. pNodeField->setFieldValue( pFieldName, fieldValue );
  334. return registerField( pNodeField );
  335. }
  336. inline TamlCustomField* addField( const char* pFieldName, const Point2F& fieldValue )
  337. {
  338. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  339. pNodeField->setFieldValue( pFieldName, fieldValue );
  340. return registerField( pNodeField );
  341. }
  342. inline TamlCustomField* addField( const char* pFieldName, const b2Vec2& fieldValue )
  343. {
  344. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  345. pNodeField->setFieldValue( pFieldName, fieldValue );
  346. return registerField( pNodeField );
  347. }
  348. inline TamlCustomField* addField( const char* pFieldName, const U32 fieldValue )
  349. {
  350. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  351. pNodeField->setFieldValue( pFieldName, fieldValue );
  352. return registerField( pNodeField );
  353. }
  354. inline TamlCustomField* addField( const char* pFieldName, const bool fieldValue )
  355. {
  356. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  357. pNodeField->setFieldValue( pFieldName, fieldValue );
  358. return registerField( pNodeField );
  359. }
  360. inline TamlCustomField* addField( const char* pFieldName, const S32 fieldValue )
  361. {
  362. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  363. pNodeField->setFieldValue( pFieldName, fieldValue );
  364. return registerField( pNodeField );
  365. }
  366. inline TamlCustomField* addField( const char* pFieldName, const float fieldValue )
  367. {
  368. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  369. pNodeField->setFieldValue( pFieldName, fieldValue );
  370. return registerField( pNodeField );
  371. }
  372. inline TamlCustomField* addField( const char* pFieldName, const char* fieldValue )
  373. {
  374. TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
  375. pNodeField->setFieldValue( pFieldName, fieldValue );
  376. return registerField( pNodeField );
  377. }
  378. inline const TamlCustomField* findField( const char* pFieldName ) const
  379. {
  380. // Sanity!
  381. AssertFatal( pFieldName != NULL, "Cannot find Taml field name that is NULL." );
  382. // Fetch field name.
  383. StringTableEntry fieldName = StringTable->insert( pFieldName );
  384. // Find node field.
  385. for( TamlCustomFieldVector::const_iterator fieldItr = mFields.begin(); fieldItr != mFields.end(); ++fieldItr )
  386. {
  387. if ( (*fieldItr)->getFieldName() == fieldName )
  388. return (*fieldItr);
  389. }
  390. return NULL;
  391. }
  392. inline void setNodeName( const char* pNodeName )
  393. {
  394. // Sanity!
  395. AssertFatal( pNodeName != NULL, "Cannot add a NULL node name." );
  396. mNodeName = StringTable->insert( pNodeName );
  397. }
  398. inline StringTableEntry getNodeName( void ) const { return mNodeName; }
  399. void setWriteNode( TamlWriteNode* pWriteNode );
  400. inline void setNodeText( const char* pNodeText )
  401. {
  402. AssertFatal( dStrlen( pNodeText ) < MAX_TAML_NODE_FIELDVALUE_LENGTH, "Custom node text is too long." );
  403. mNodeText.set( StringTable->EmptyString, pNodeText );
  404. }
  405. inline const TamlCustomField& getNodeTextField( void ) const { return mNodeText; }
  406. inline TamlCustomField& getNodeTextField( void ) { return mNodeText; }
  407. inline const Vector<TamlCustomNode*>& getChildren( void ) const { return mChildren; }
  408. inline const TamlCustomFieldVector& getFields( void ) const { return mFields; }
  409. inline bool isProxyObject( void ) const { return mpProxyObject != NULL; }
  410. template<typename T> T* getProxyObject( const bool deleteIfNotType ) const
  411. {
  412. // Return nothing if no proxy object.
  413. if ( mpProxyObject == NULL )
  414. return NULL;
  415. // Cast object to specified type.
  416. T* pTypeCast = dynamic_cast<T*>( mpProxyObject );
  417. // Destroy the object if not the specified type and requested to do so.
  418. if ( deleteIfNotType && pTypeCast == NULL )
  419. {
  420. mpProxyObject->deleteObject();
  421. return NULL;
  422. }
  423. return pTypeCast;
  424. }
  425. inline const TamlWriteNode* getProxyWriteNode( void ) const { return mpProxyWriteNode; }
  426. inline bool isEmpty( void ) const { return mNodeText.isValueEmpty() && mFields.size() == 0 && mChildren.size() == 0; }
  427. inline void setIgnoreEmpty( const bool ignoreEmpty ) { mIgnoreEmpty = ignoreEmpty; }
  428. inline bool getIgnoreEmpty( void ) const { return mIgnoreEmpty; }
  429. private:
  430. inline TamlCustomField* registerField( TamlCustomField* pCustomField )
  431. {
  432. #if TORQUE_DEBUG
  433. // Ensure a field name conflict does not exist.
  434. for( Vector<TamlCustomField*>::iterator nodeFieldItr = mFields.begin(); nodeFieldItr != mFields.end(); ++nodeFieldItr )
  435. {
  436. // Skip if field name is not the same.
  437. if ( pCustomField->getFieldName() != (*nodeFieldItr)->getFieldName() )
  438. continue;
  439. // Warn!
  440. Con::warnf("Conflicting Taml node field name of '%s' in node '%s'.", pCustomField->getFieldName(), mNodeName );
  441. // Cache node field.
  442. TamlCustomFieldFactory.cacheObject( pCustomField );
  443. return NULL;
  444. }
  445. // Ensure the field value is not too long.
  446. if ( dStrlen( pCustomField->getFieldValue() ) >= MAX_TAML_NODE_FIELDVALUE_LENGTH )
  447. {
  448. // Warn.
  449. Con::warnf("Taml field name '%s' has a field value that is too long (Max:%d): '%s'.",
  450. pCustomField->getFieldName(),
  451. MAX_TAML_NODE_FIELDVALUE_LENGTH,
  452. pCustomField->getFieldValue() );
  453. // Cache node field.
  454. TamlCustomFieldFactory.cacheObject( pCustomField );
  455. return NULL;
  456. }
  457. #endif
  458. // Store node field.
  459. mFields.push_back( pCustomField );
  460. return pCustomField;
  461. }
  462. inline TamlCustomField* createField( void ) const { return TamlCustomFieldFactory.createObject(); }
  463. private:
  464. StringTableEntry mNodeName;
  465. TamlCustomField mNodeText;
  466. Vector<TamlCustomNode*> mChildren;
  467. TamlCustomFieldVector mFields;
  468. bool mIgnoreEmpty;
  469. SimObject* mpProxyObject;
  470. TamlWriteNode* mpProxyWriteNode;
  471. };
  472. //-----------------------------------------------------------------------------
  473. class TamlCustomNodes : public IFactoryObjectReset
  474. {
  475. public:
  476. TamlCustomNodes()
  477. {
  478. }
  479. virtual ~TamlCustomNodes()
  480. {
  481. resetState();
  482. }
  483. virtual void resetState( void )
  484. {
  485. // Cache the nodes.
  486. while ( mNodes.size() > 0 )
  487. {
  488. TamlCustomNodeFactory.cacheObject( mNodes.back() );
  489. mNodes.pop_back();
  490. }
  491. }
  492. inline TamlCustomNode* addNode( const char* pNodeName, const bool ignoreEmpty = true )
  493. {
  494. // Create a custom node.
  495. TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
  496. // Set node name.
  497. pCustomNode->setNodeName( pNodeName );
  498. // Set ignore-empty flag.
  499. pCustomNode->setIgnoreEmpty( ignoreEmpty );
  500. #if TORQUE_DEBUG
  501. // Ensure a node name conflict does not exist.
  502. for( TamlCustomNodeVector::iterator nodeItr = mNodes.begin(); nodeItr != mNodes.end(); ++nodeItr )
  503. {
  504. // Skip if node name is not the same.
  505. if ( pCustomNode->getNodeName() != (*nodeItr)->getNodeName() )
  506. continue;
  507. // Warn!
  508. Con::warnf("Conflicting Taml custom node name of '%s'.", pNodeName );
  509. // Cache node.
  510. TamlCustomNodeFactory.cacheObject( pCustomNode );
  511. return NULL;
  512. }
  513. #endif
  514. // Store node.
  515. mNodes.push_back( pCustomNode );
  516. return pCustomNode;
  517. }
  518. inline void removeNode( const U32 index )
  519. {
  520. // Sanity!
  521. AssertFatal( index < (U32)mNodes.size(), "tamlCustomNode::removeNode() - Index is out of bounds." );
  522. // Cache the custom node.
  523. TamlCustomNodeFactory.cacheObject( mNodes[index] );
  524. // Remove it.
  525. mNodes.erase( index );
  526. }
  527. inline const TamlCustomNode* findNode( const char* pNodeName ) const
  528. {
  529. // Sanity!
  530. AssertFatal( pNodeName != NULL, "Cannot find Taml node name that is NULL." );
  531. // Fetch node name.
  532. StringTableEntry nodeName = StringTable->insert( pNodeName );
  533. // Find node.
  534. for( Vector<TamlCustomNode*>::const_iterator nodeItr = mNodes.begin(); nodeItr != mNodes.end(); ++nodeItr )
  535. {
  536. if ( (*nodeItr)->getNodeName() == nodeName )
  537. return (*nodeItr);
  538. }
  539. return NULL;
  540. }
  541. inline const TamlCustomNodeVector& getNodes( void ) const { return mNodes; }
  542. private:
  543. TamlCustomNodeVector mNodes;
  544. };
  545. #endif // _TAML_CUSTOM_H_