behaviorComponent.cpp 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422
  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. #include "io/stream.h"
  23. #include "string/stringUnit.h"
  24. #include "memory/frameAllocator.h"
  25. #include "component/behaviors/behaviorComponent.h"
  26. #include "component/behaviors/behaviorTemplate.h"
  27. #ifndef _ASSET_FIELD_TYPES_H_
  28. #include "assets/assetFieldTypes.h"
  29. #endif
  30. #ifndef _TAML_CUSTOM_H_
  31. #include "persistence/taml/tamlCustom.h"
  32. #endif
  33. #ifndef _TAML_H_
  34. #include "persistence/taml/taml.h"
  35. #endif
  36. // Script bindings.
  37. #include "behaviorComponent_ScriptBinding.h"
  38. //-----------------------------------------------------------------------------
  39. static StringTableEntry behaviorIdFieldName = StringTable->insert( "Id" );
  40. static StringTableEntry behaviorNodeName = StringTable->insert( "Behaviors" );
  41. static StringTableEntry behaviorConnectionTypeName = StringTable->insert( "Connection" );
  42. static StringTableEntry behaviorTemplateAssetName = StringTable->insert( "Asset" );
  43. //-----------------------------------------------------------------------------
  44. BehaviorComponent::BehaviorComponent() :
  45. mMasterBehaviorId( 1 ),
  46. mpBehaviorFieldNames( NULL )
  47. {
  48. SIMSET_SET_ASSOCIATION( mBehaviors );
  49. }
  50. //-----------------------------------------------------------------------------
  51. bool BehaviorComponent::onAdd()
  52. {
  53. if( !Parent::onAdd() )
  54. return false;
  55. return true;
  56. }
  57. //-----------------------------------------------------------------------------
  58. void BehaviorComponent::onRemove()
  59. {
  60. // Remove all behaviors and notify.
  61. clearBehaviors();
  62. // Call parent.
  63. Parent::onRemove();
  64. }
  65. //-----------------------------------------------------------------------------
  66. void BehaviorComponent::onDeleteNotify( SimObject *object )
  67. {
  68. // Cast to a behavior instance.
  69. BehaviorInstance* pInstance = dynamic_cast<BehaviorInstance*>( object );
  70. // Ignore if not appropriate.
  71. if ( pInstance == NULL )
  72. return;
  73. // Is the behavior instance owned by this component?
  74. if ( pInstance->getBehaviorOwner() == this )
  75. {
  76. // Yes, so remove.
  77. removeBehavior( pInstance, false );
  78. }
  79. // Destroy any input connections to the instance.
  80. destroyBehaviorInputConnections( pInstance );
  81. }
  82. //-----------------------------------------------------------------------------
  83. void BehaviorComponent::copyTo(SimObject* obj)
  84. {
  85. // Call parent.
  86. Parent::copyTo(obj);
  87. // Fetch object.
  88. BehaviorComponent* pObject = dynamic_cast<BehaviorComponent*>(obj);
  89. // Sanity!
  90. AssertFatal(pObject != NULL, "BehaviorComponent::copyTo() - Object is not the correct type.");
  91. // Clear behaviors.
  92. pObject->clearBehaviors();
  93. // Behaviors
  94. U32 behaviorCount = getBehaviorCount();
  95. // Finish if no behaviors.
  96. if ( behaviorCount == 0 )
  97. return;
  98. // Initialize a clone map.
  99. typedef HashMap<BehaviorInstance*,BehaviorInstance*> typeBehaviorCloneHash;
  100. typeBehaviorCloneHash behaviorInstanceCloneMap;
  101. // Iterate behaviors.
  102. for ( U32 index = 0; index < behaviorCount; ++index )
  103. {
  104. // Clone the behavior instance.
  105. BehaviorInstance* pFromInstance = getBehavior(index);
  106. BehaviorTemplate* pFromTemplate = pFromInstance->getTemplate();
  107. BehaviorInstance* pToInstance = pFromTemplate->createInstance();
  108. // Assign dynamic fields from behavior instance.
  109. pToInstance->assignDynamicFieldsFrom( pFromInstance );
  110. // Add the behavior instance.
  111. pObject->addBehavior(pToInstance);
  112. // Add to the clone map.
  113. behaviorInstanceCloneMap.insert( pFromInstance, pToInstance );
  114. }
  115. // Iterate instance connections.
  116. for( typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.begin(); instanceItr != mBehaviorConnections.end(); ++instanceItr )
  117. {
  118. // Fetch output name connection(s).
  119. typeOutputNameConnectionHash* pOutputNameConnection = instanceItr->value;
  120. // Iterate output name connections.
  121. for( typeOutputNameConnectionHash::iterator outputItr = pOutputNameConnection->begin(); outputItr != pOutputNameConnection->end(); ++outputItr )
  122. {
  123. // Fetch port connection(s).
  124. typePortConnectionVector* pPortConnections = outputItr->value;
  125. // Iterate input connections.
  126. for( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
  127. {
  128. // Fetch connection.
  129. BehaviorPortConnection* pConnection = connectionItr;
  130. // Find behavior instance mappings.
  131. typeBehaviorCloneHash::iterator toOutputItr = behaviorInstanceCloneMap.find( pConnection->mOutputInstance );
  132. typeBehaviorCloneHash::iterator toInputItr = behaviorInstanceCloneMap.find( pConnection->mInputInstance );
  133. // Sanity!
  134. AssertFatal( toOutputItr != behaviorInstanceCloneMap.end(), "Failed to find output behavior instance mapping during copy." );
  135. AssertFatal( toInputItr != behaviorInstanceCloneMap.end(), "Failed to find input behavior instance mapping during copy." );
  136. // Fetch behavior instance mappings.
  137. BehaviorInstance* pToInstanceOutput = toOutputItr->value;
  138. BehaviorInstance* pToInstanceInput = toInputItr->value;
  139. // Make cloned connection.
  140. pObject->connect( pToInstanceOutput, pToInstanceInput, pConnection->mOutputName, pConnection->mInputName );
  141. }
  142. }
  143. }
  144. }
  145. //-----------------------------------------------------------------------------
  146. bool BehaviorComponent::addBehavior( BehaviorInstance* bi )
  147. {
  148. if( bi == NULL || !bi->isProperlyAdded() )
  149. return false;
  150. // Store behavior.
  151. mBehaviors.pushObject( bi );
  152. // Notify if the behavior instance is destroyed.
  153. deleteNotify( bi );
  154. // Set the behavior owner.
  155. bi->setBehaviorOwner( this );
  156. // Allocate a behavior Id.
  157. bi->setBehaviorId( mMasterBehaviorId++ );
  158. if( bi->isMethod("onBehaviorAdd") )
  159. Con::executef( bi , 1, "onBehaviorAdd" );
  160. return true;
  161. }
  162. //-----------------------------------------------------------------------------
  163. bool BehaviorComponent::removeBehavior( BehaviorInstance *bi, bool deleteBehavior )
  164. {
  165. for( SimSet::iterator itr = mBehaviors.begin(); itr != mBehaviors.end(); ++itr )
  166. {
  167. if( *itr == bi )
  168. {
  169. mBehaviors.removeObject( *itr );
  170. // Perform callback if allowed.
  171. if( bi->isProperlyAdded() && bi->isMethod("onBehaviorRemove") )
  172. Con::executef( bi , 1, "onBehaviorRemove" );
  173. // Destroy any output connections.
  174. destroyBehaviorOutputConnections( bi );
  175. if ( deleteBehavior && bi->isProperlyAdded() )
  176. {
  177. bi->deleteObject();
  178. }
  179. else
  180. {
  181. bi->setBehaviorOwner( NULL );
  182. bi->setBehaviorId( 0 );
  183. // Remove delete notification.
  184. clearNotify( bi );
  185. }
  186. return true;
  187. }
  188. }
  189. return false;
  190. }
  191. //-----------------------------------------------------------------------------
  192. void BehaviorComponent::clearBehaviors()
  193. {
  194. while( mBehaviors.size() > 0 )
  195. {
  196. BehaviorInstance *bi = dynamic_cast<BehaviorInstance *>( mBehaviors.first() );
  197. removeBehavior( bi );
  198. }
  199. }
  200. //-----------------------------------------------------------------------------
  201. BehaviorInstance *BehaviorComponent::getBehavior( StringTableEntry behaviorTemplateName )
  202. {
  203. for( SimSet::iterator itr = mBehaviors.begin(); itr != mBehaviors.end(); ++itr )
  204. {
  205. // Fetch behavior.
  206. BehaviorInstance* pBehaviorInstance = dynamic_cast<BehaviorInstance*>(*itr);
  207. if ( !pBehaviorInstance || pBehaviorInstance->getTemplateName() != behaviorTemplateName )
  208. continue;
  209. return pBehaviorInstance;
  210. }
  211. return NULL;
  212. }
  213. //-----------------------------------------------------------------------------
  214. bool BehaviorComponent::reOrder( BehaviorInstance *obj, U32 desiredIndex /* = 0 */ )
  215. {
  216. if( desiredIndex > (U32)mBehaviors.size() )
  217. return false;
  218. SimObject *target = mBehaviors.at( desiredIndex );
  219. return mBehaviors.reOrder( obj, target );
  220. }
  221. //-----------------------------------------------------------------------------
  222. void BehaviorComponent::destroyBehaviorOutputConnections( BehaviorInstance* pOutputBehavior )
  223. {
  224. // Sanity!
  225. AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
  226. // Is the output behavior owned by this behavior component?
  227. if ( pOutputBehavior->getBehaviorOwner() != this )
  228. {
  229. // No, so warn.
  230. Con::warnf(
  231. "Could not destroy output behavior connection for behavior '%s' as the output behavior is not owned by this component.",
  232. pOutputBehavior->getTemplateName()
  233. );
  234. return;
  235. }
  236. // Find behavior instance connections.
  237. typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
  238. // Finish if there are no outbound connections for this output behavior.
  239. if ( instanceItr == mBehaviorConnections.end() )
  240. return;
  241. // Fetch output name hash.
  242. typeOutputNameConnectionHash* pOutputNameHash = instanceItr->value;
  243. // Iterate all outputs.
  244. for ( typeOutputNameConnectionHash::iterator outputItr = pOutputNameHash->begin(); outputItr != pOutputNameHash->end(); ++outputItr )
  245. {
  246. // Fetch port connection(s).
  247. typePortConnectionVector* pPortConnections = outputItr->value;
  248. // Destroy port connections.
  249. delete pPortConnections;
  250. }
  251. // Destroy outputs.
  252. delete pOutputNameHash;
  253. // Remove connection.
  254. mBehaviorConnections.erase( pOutputBehavior->getId() );
  255. }
  256. //-----------------------------------------------------------------------------
  257. void BehaviorComponent::destroyBehaviorInputConnections( BehaviorInstance* pInputBehavior )
  258. {
  259. // Sanity!
  260. AssertFatal( pInputBehavior != NULL, "Input behavior cannot be NULL." );
  261. // Iterate connections.
  262. for ( typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.begin(); instanceItr != mBehaviorConnections.end(); ++instanceItr )
  263. {
  264. // Fetch output name hash.
  265. typeOutputNameConnectionHash* pOutputNameHash = instanceItr->value;
  266. // Iterate all outputs.
  267. for ( typeOutputNameConnectionHash::iterator outputItr = pOutputNameHash->begin(); outputItr != pOutputNameHash->end(); ++outputItr )
  268. {
  269. // Fetch port connection(s).
  270. typePortConnectionVector* pPortConnections = outputItr->value;
  271. bool connectionFound;
  272. do
  273. {
  274. // Flag connection as 'not found' initially.
  275. connectionFound = false;
  276. // Look for an existing connection to the specified input instance.
  277. for ( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
  278. {
  279. // Is this the input behavior?
  280. if ( connectionItr->mInputInstance == pInputBehavior )
  281. {
  282. // Yes, so destroy it.
  283. pPortConnections->erase_fast( connectionItr );
  284. // Flag connection as 'found'.
  285. connectionFound = true;
  286. break;
  287. }
  288. }
  289. } while (connectionFound);
  290. }
  291. }
  292. }
  293. //-----------------------------------------------------------------------------
  294. BehaviorInstance* BehaviorComponent::getBehaviorByInstanceId( const U32 behaviorId )
  295. {
  296. for( SimSet::iterator instanceItr = mBehaviors.begin(); instanceItr != mBehaviors.end(); ++instanceItr )
  297. {
  298. // Fetch behavior instance.
  299. BehaviorInstance* pInstance = static_cast<BehaviorInstance*>( *instanceItr );
  300. // Return instance if it has the same behavior Id.
  301. if ( pInstance->getBehaviorId() == behaviorId )
  302. return pInstance;
  303. }
  304. // Not found.
  305. return NULL;
  306. }
  307. //-----------------------------------------------------------------------------
  308. bool BehaviorComponent::connect( BehaviorInstance* pOutputBehavior, BehaviorInstance* pInputBehavior, StringTableEntry pOutputName, StringTableEntry pInputName )
  309. {
  310. // Sanity!
  311. AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
  312. AssertFatal( pInputBehavior != NULL, "Input behavior cannot be NULL." );
  313. AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
  314. AssertFatal( pInputName != NULL, "Input name cannot be NULL." );
  315. // Is the output behavior owned by this behavior component?
  316. if ( pOutputBehavior->getBehaviorOwner() != this )
  317. {
  318. // No, so warn.
  319. Con::warnf(
  320. "Could not connect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the output behavior is not owned by this component.",
  321. pOutputName,
  322. pOutputBehavior->getTemplateName(),
  323. pInputName,
  324. pInputBehavior->getTemplateName()
  325. );
  326. return false;
  327. }
  328. // Is the input behavior owned by this behavior component?
  329. if ( pInputBehavior->getBehaviorOwner() != this )
  330. {
  331. // No, so warn.
  332. Con::warnf(
  333. "Could not connect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the input behavior is not owned by this component.",
  334. pOutputName,
  335. pOutputBehavior->getTemplateName(),
  336. pInputName,
  337. pInputBehavior->getTemplateName()
  338. );
  339. return false;
  340. }
  341. // Does the output behavior have the specified output?
  342. if ( !pOutputBehavior->getTemplate()->hasBehaviorOutput( pOutputName ) )
  343. {
  344. // No, so warn.
  345. Con::warnf(
  346. "Could not connect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the output behavior does not have such an output.",
  347. pOutputName,
  348. pOutputBehavior->getTemplateName(),
  349. pInputName,
  350. pInputBehavior->getTemplateName()
  351. );
  352. return false;
  353. }
  354. // Does the input behavior have the specified input?
  355. if ( !pInputBehavior->getTemplate()->hasBehaviorInput( pInputName ) )
  356. {
  357. // No, so warn.
  358. Con::warnf(
  359. "Could not connect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the input behavior does not have such an input.",
  360. pOutputName,
  361. pOutputBehavior->getTemplateName(),
  362. pInputName,
  363. pInputBehavior->getTemplateName()
  364. );
  365. return false;
  366. }
  367. // Find behavior instance connections.
  368. typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
  369. // Are there currently any outbound connections for this output instance?
  370. if ( instanceItr == mBehaviorConnections.end() )
  371. {
  372. // No, so create an entry for this instance.
  373. typeOutputNameConnectionHash* pOutputHash = new typeOutputNameConnectionHash();
  374. // Insert new output hash.
  375. instanceItr = mBehaviorConnections.insert( pOutputBehavior->getId(), pOutputHash );
  376. }
  377. // Fetch output name hash.
  378. typeOutputNameConnectionHash* pOutputNameHash = instanceItr->value;
  379. // Find instance output connection.
  380. typeOutputNameConnectionHash::iterator outputItr = pOutputNameHash->find( pOutputName );
  381. // Are there currently any outbound connections for this specific output?
  382. if ( outputItr == pOutputNameHash->end() )
  383. {
  384. // No, so create an entry for this output.
  385. typePortConnectionVector* pPortConnections = new typePortConnectionVector();
  386. // Insert new port connections.
  387. outputItr = pOutputNameHash->insert( pOutputName, pPortConnections );
  388. }
  389. // Fetch port connection(s).
  390. typePortConnectionVector* pPortConnections = outputItr->value;
  391. // Look for an identical connection.
  392. for ( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
  393. {
  394. // Is this an identical connection?
  395. if ( connectionItr->mInputInstance == pInputBehavior && connectionItr->mInputName == pInputName )
  396. {
  397. // Yes, so warn.
  398. Con::warnf(
  399. "Could not connect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the connection already exists.",
  400. pOutputName,
  401. pOutputBehavior->getTemplateName(),
  402. pInputName,
  403. pInputBehavior->getTemplateName()
  404. );
  405. return false;
  406. }
  407. }
  408. // Populate port connection.
  409. BehaviorPortConnection portConnection( pOutputBehavior, pInputBehavior, pOutputName, pInputName );
  410. // Add port connection.
  411. pPortConnections->push_back( portConnection );
  412. // Notify if the input behavior instance is destroyed.
  413. deleteNotify( pInputBehavior );
  414. return true;
  415. }
  416. //-----------------------------------------------------------------------------
  417. bool BehaviorComponent::disconnect( BehaviorInstance* pOutputBehavior, BehaviorInstance* pInputBehavior, StringTableEntry pOutputName, StringTableEntry pInputName )
  418. {
  419. // Sanity!
  420. AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
  421. AssertFatal( pInputBehavior != NULL, "Input behavior cannot be NULL." );
  422. AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
  423. AssertFatal( pInputName != NULL, "Input name cannot be NULL." );
  424. // Is the output behavior owned by this behavior component?
  425. if ( pOutputBehavior->getBehaviorOwner() != this )
  426. {
  427. // No, so warn.
  428. Con::warnf(
  429. "Could not disconnect output '%s' on behavior '%s' from input '%s' on behavior '%s' as the output behavior is not owned by this component.",
  430. pOutputName,
  431. pOutputBehavior->getTemplateName(),
  432. pInputName,
  433. pInputBehavior->getTemplateName()
  434. );
  435. return false;
  436. }
  437. // Is the input behavior owned by this behavior component?
  438. if ( pInputBehavior->getBehaviorOwner() != this )
  439. {
  440. // No, so warn.
  441. Con::warnf(
  442. "Could not disconnect output '%s' on behavior '%s' from input '%s' on behavior '%s' as the input behavior is not owned by this component.",
  443. pOutputName,
  444. pOutputBehavior->getTemplateName(),
  445. pInputName,
  446. pInputBehavior->getTemplateName()
  447. );
  448. return false;
  449. }
  450. // Does the output behavior have the specified output?
  451. if ( !pOutputBehavior->getTemplate()->hasBehaviorOutput( pOutputName ) )
  452. {
  453. // No, so warn.
  454. Con::warnf(
  455. "Could not disconnect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the output behavior does not have such an output.",
  456. pOutputName,
  457. pOutputBehavior->getTemplateName(),
  458. pInputName,
  459. pInputBehavior->getTemplateName()
  460. );
  461. return false;
  462. }
  463. // Does the input behavior have the specified input?
  464. if ( !pInputBehavior->getTemplate()->hasBehaviorInput( pInputName ) )
  465. {
  466. // No, so warn.
  467. Con::warnf(
  468. "Could not disconnect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the input behavior does not have such an input.",
  469. pOutputName,
  470. pOutputBehavior->getTemplateName(),
  471. pInputName,
  472. pInputBehavior->getTemplateName()
  473. );
  474. return false;
  475. }
  476. // Find behavior instance connections.
  477. typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
  478. // Are there currently any outbound connections for this output instance?
  479. if ( instanceItr == mBehaviorConnections.end() )
  480. {
  481. // No, so warn.
  482. Con::warnf(
  483. "Could not disconnect output '%s' on behavior '%s' from input '%s' on behavior '%s' as the behavior does not have any connections.",
  484. pOutputName,
  485. pOutputBehavior->getTemplateName(),
  486. pInputName,
  487. pInputBehavior->getTemplateName()
  488. );
  489. return false;
  490. }
  491. // Fetch output name hash.
  492. typeOutputNameConnectionHash* pOutputNameHash = instanceItr->value;
  493. // Find instance output connection.
  494. typeOutputNameConnectionHash::iterator outputItr = pOutputNameHash->find( pOutputName );
  495. // Are there currently any outbound connections for this specific output?
  496. if ( outputItr == pOutputNameHash->end() )
  497. {
  498. // No, so warn.
  499. Con::warnf(
  500. "Could not disconnect output '%s' on behavior '%s' from input '%s' on behavior '%s' as the specified output does not have any connections.",
  501. pOutputName,
  502. pOutputBehavior->getTemplateName(),
  503. pInputName,
  504. pInputBehavior->getTemplateName()
  505. );
  506. return false;
  507. }
  508. // Fetch port connection(s).
  509. typePortConnectionVector* pPortConnections = outputItr->value;
  510. // Look for an existing connection to the specified input.
  511. for ( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
  512. {
  513. // Is this the requested disconnection?
  514. if ( connectionItr->mInputInstance == pInputBehavior && connectionItr->mInputName == pInputName )
  515. {
  516. // Yes, so remove connection.
  517. pPortConnections->erase_fast( connectionItr );
  518. return true;
  519. }
  520. }
  521. // Not found so warn.
  522. Con::warnf(
  523. "Could not disconnect output '%s' on behavior '%s' from input '%s' on behavior '%s' as the connection does not exist.",
  524. pOutputName,
  525. pOutputBehavior->getTemplateName(),
  526. pInputName,
  527. pInputBehavior->getTemplateName()
  528. );
  529. return false;
  530. }
  531. //-----------------------------------------------------------------------------
  532. bool BehaviorComponent::raise( BehaviorInstance* pOutputBehavior, StringTableEntry pOutputName )
  533. {
  534. // Sanity!
  535. AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
  536. AssertFatal( pOutputBehavior->isProperlyAdded(), "Output behavior is not registered." );
  537. AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
  538. // Is the output behavior owned by this behavior component?
  539. if ( pOutputBehavior->getBehaviorOwner() != this )
  540. {
  541. // No, so warn.
  542. Con::warnf(
  543. "Could not raise output '%s' on behavior '%s' as the output behavior is not owned by this component.",
  544. pOutputName,
  545. pOutputBehavior->getTemplateName()
  546. );
  547. return false;
  548. }
  549. // Does the behavior have the specified output?
  550. if ( !pOutputBehavior->getTemplate()->hasBehaviorOutput( pOutputName ) )
  551. {
  552. // No, so warn.
  553. Con::warnf(
  554. "Could not raise output '%s' on behavior '%s' as the behavior does not have such an output.",
  555. pOutputName,
  556. pOutputBehavior->getTemplateName()
  557. );
  558. return false;
  559. }
  560. // Execute a callback for the output.
  561. // NOTE: This callback should not delete behaviors otherwise strange things can happen!
  562. Con::executef( this, 2, pOutputName, pOutputBehavior->getIdString() );
  563. // Find behavior instance connections.
  564. typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
  565. // Finish if there are no outbound connections for this output behavior.
  566. if ( instanceItr == mBehaviorConnections.end() )
  567. return true;
  568. // Find instance output connection.
  569. typeOutputNameConnectionHash::iterator outputItr = instanceItr->value->find( pOutputName );
  570. // Finish if there are no outbound connections for this output.
  571. if ( outputItr == instanceItr->value->end() )
  572. return true;
  573. // Fetch port connection(s).
  574. typePortConnectionVector* pPortConnections = outputItr->value;
  575. // Process output connection(s).
  576. for ( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
  577. {
  578. // Fetch input behavior.
  579. BehaviorInstance* pInputBehavior = connectionItr->mInputInstance;
  580. // Fetch input name.
  581. StringTableEntry pInputName = connectionItr->mInputName;
  582. #ifdef TORQUE_DEBUG
  583. // Sanity!
  584. AssertFatal( pInputBehavior->isProperlyAdded(), "Input behavior is not registered." );
  585. // Does the behavior have the specified input?
  586. if ( !pInputBehavior->getTemplate()->hasBehaviorInput( pInputName ) )
  587. {
  588. // No, so warn.
  589. Con::warnf(
  590. "Could not raise input '%s' on behavior '%s' as the behavior does not have such an input.",
  591. pInputName,
  592. pInputBehavior->getTemplateName()
  593. );
  594. return false;
  595. }
  596. #endif
  597. // Execute a callback for the input.
  598. // NOTE: This callback should not delete behaviors otherwise strange things can happen!
  599. Con::executef( pInputBehavior, 3, pInputName, pOutputBehavior->getIdString(), pOutputName );
  600. }
  601. return true;
  602. }
  603. //-----------------------------------------------------------------------------
  604. U32 BehaviorComponent::getBehaviorConnectionCount( BehaviorInstance* pOutputBehavior, StringTableEntry pOutputName )
  605. {
  606. // Sanity!
  607. AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
  608. AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
  609. // Is the output behavior owned by this behavior component?
  610. if ( pOutputBehavior->getBehaviorOwner() != this )
  611. {
  612. // No, so warn.
  613. Con::warnf(
  614. "Could not get behavior connection count on output '%s' on behavior '%s' as the output behavior is not owned by this component.",
  615. pOutputName,
  616. pOutputBehavior->getTemplateName()
  617. );
  618. return 0;
  619. }
  620. // Does the behavior have the specified output?
  621. if ( !pOutputBehavior->getTemplate()->hasBehaviorOutput( pOutputName ) )
  622. {
  623. // No, so warn.
  624. Con::warnf(
  625. "Could not get behavior connection count for output '%s' on behavior '%s' as the behavior does not have such an output.",
  626. pOutputName,
  627. pOutputBehavior->getTemplateName()
  628. );
  629. return 0;
  630. }
  631. // Find behavior instance connections.
  632. typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
  633. // Finish if there are no outbound connections for this output behavior.
  634. if ( instanceItr == mBehaviorConnections.end() )
  635. return 0;
  636. // Find instance output connection.
  637. typeOutputNameConnectionHash::iterator outputItr = instanceItr->value->find( pOutputName );
  638. // Finish if there are no outbound connections for this output.
  639. if ( outputItr == instanceItr->value->end() )
  640. return 0;
  641. // Fetch port connection(s).
  642. typePortConnectionVector* pPortConnections = outputItr->value;
  643. // Return number of connections.
  644. return pPortConnections->size();
  645. }
  646. //-----------------------------------------------------------------------------
  647. const BehaviorComponent::BehaviorPortConnection* BehaviorComponent::getBehaviorConnection( BehaviorInstance* pOutputBehavior, StringTableEntry pOutputName, const U32 connectionIndex )
  648. {
  649. // Sanity!
  650. AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
  651. AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
  652. // Fetch behavior connection count.
  653. const U32 behaviorConnectionCount = getBehaviorConnectionCount( pOutputBehavior, pOutputName );
  654. // Finish if there are no connections.
  655. if ( behaviorConnectionCount == 0 )
  656. return NULL;
  657. // Is the connection index valid?
  658. if ( connectionIndex >= behaviorConnectionCount )
  659. {
  660. // No, so warn.
  661. Con::warnf(
  662. "Could not get behavior the behavior connection index '%d' on output '%s' on behavior '%s' as the output behavior only has '%d' connections",
  663. connectionIndex,
  664. pOutputName,
  665. pOutputBehavior->getTemplateName(),
  666. behaviorConnectionCount
  667. );
  668. return NULL;
  669. }
  670. // Fetch behavior connections.
  671. const typePortConnectionVector* pConnections = getBehaviorConnections( pOutputBehavior, pOutputName );
  672. // Fetch behavior connection.
  673. const BehaviorComponent::BehaviorPortConnection* pBehaviorConnection = &((*pConnections)[connectionIndex]);
  674. // Return behavior connection.
  675. return pBehaviorConnection;
  676. }
  677. //-----------------------------------------------------------------------------
  678. const BehaviorComponent::typePortConnectionVector* BehaviorComponent::getBehaviorConnections( BehaviorInstance* pOutputBehavior, StringTableEntry pOutputName )
  679. {
  680. // Sanity!
  681. AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
  682. AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
  683. // Is the output behavior owned by this behavior component?
  684. if ( pOutputBehavior->getBehaviorOwner() != this )
  685. {
  686. // No, so warn.
  687. Con::warnf(
  688. "Could not get behavior connections on output '%s' on behavior '%s' as the output behavior is not owned by this component.",
  689. pOutputName,
  690. pOutputBehavior->getTemplateName()
  691. );
  692. return NULL;
  693. }
  694. // Does the behavior have the specified output?
  695. if ( !pOutputBehavior->getTemplate()->hasBehaviorOutput( pOutputName ) )
  696. {
  697. // No, so warn.
  698. Con::warnf(
  699. "Could not get behavior connections for output '%s' on behavior '%s' as the behavior does not have such an output.",
  700. pOutputName,
  701. pOutputBehavior->getTemplateName()
  702. );
  703. return NULL;
  704. }
  705. // Find behavior instance connections.
  706. typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
  707. // Finish if there are no outbound connections for this output behavior.
  708. if ( instanceItr == mBehaviorConnections.end() )
  709. return NULL;
  710. // Find instance output connection.
  711. typeOutputNameConnectionHash::iterator outputItr = instanceItr->value->find( pOutputName );
  712. // Finish if there are no outbound connections for this output.
  713. if ( outputItr == instanceItr->value->end() )
  714. return NULL;
  715. // Fetch port connection(s).
  716. typePortConnectionVector* pPortConnections = outputItr->value;
  717. // Return number of connections.
  718. return pPortConnections;
  719. }
  720. //-----------------------------------------------------------------------------
  721. void BehaviorComponent::write( Stream &stream, U32 tabStop, U32 flags /* = 0 */ )
  722. {
  723. // Export selected only?
  724. if( ( flags & SelectedOnly ) && !isSelected() )
  725. {
  726. return;
  727. }
  728. if( mBehaviors.size() == 0 )
  729. {
  730. Parent::write( stream, tabStop, flags );
  731. return;
  732. }
  733. // The work we want to perform here is in the Taml callback.
  734. onTamlPreWrite();
  735. // Write object.
  736. Parent::write( stream, tabStop, flags );
  737. // The work we want to perform here is in the Taml callback.
  738. onTamlPostWrite();
  739. }
  740. //-----------------------------------------------------------------------------
  741. bool BehaviorComponent::handlesConsoleMethod( const char *fname, S32 *routingId )
  742. {
  743. // CodeReview [6/25/2007 justind]
  744. // If we're deleting the BehaviorComponent, don't forward the call to the
  745. // behaviors, the parent onRemove will handle freeing them
  746. // This should really be handled better, and is in the Parent implementation
  747. // but behaviors are a special case because they always want to be called BEFORE
  748. // the parent to act.
  749. if( dStricmp( fname, "delete" ) == 0 )
  750. return Parent::handlesConsoleMethod( fname, routingId );
  751. for( SimSet::iterator nItr = mBehaviors.begin(); nItr != mBehaviors.end(); nItr++ )
  752. {
  753. SimObject *pComponent = dynamic_cast<SimObject *>(*nItr);
  754. if( pComponent != NULL && pComponent->isMethod( fname ) )
  755. {
  756. *routingId = -2; // -2 denotes method on component
  757. return true;
  758. }
  759. }
  760. // Let parent handle it
  761. return Parent::handlesConsoleMethod( fname, routingId );
  762. }
  763. //-----------------------------------------------------------------------------
  764. // Needed to be able to directly call execute on a Namespace::Entry
  765. extern ExprEvalState gEvalState;
  766. const char *BehaviorComponent::callOnBehaviors( U32 argc, const char *argv[] )
  767. {
  768. if( mBehaviors.empty() )
  769. return Parent::callOnBehaviors( argc, argv );
  770. // Copy the arguments to avoid weird clobbery situations.
  771. FrameTemp<char *> argPtrs (argc);
  772. U32 strdupWatermark = FrameAllocator::getWaterMark();
  773. for( U32 i = 0; i < argc; i++ )
  774. {
  775. argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
  776. dStrcpy( argPtrs[i], argv[i] );
  777. }
  778. // Walk backwards through the list just as with components
  779. const char* result = "";
  780. bool handled = false;
  781. for( SimSet::iterator i = (mBehaviors.end()-1); i >= mBehaviors.begin(); i-- )
  782. {
  783. BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
  784. AssertFatal( pBehavior, "BehaviorComponent::callOnBehaviors - Bad behavior instance in list." );
  785. AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
  786. // Use the BehaviorInstance's namespace
  787. Namespace *pNamespace = pBehavior->getNamespace();
  788. if(!pNamespace)
  789. continue;
  790. // Lookup the Callback Namespace entry and then splice callback
  791. const char *cbName = StringTable->insert(argv[0]);
  792. Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
  793. if( pNSEntry )
  794. {
  795. // Set %this to our BehaviorInstance's Object ID
  796. argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
  797. // Change the Current Console object, execute, restore Object
  798. SimObject *save = gEvalState.thisObject;
  799. gEvalState.thisObject = pBehavior;
  800. result = pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
  801. gEvalState.thisObject = save;
  802. handled = true;
  803. break;
  804. }
  805. }
  806. // If this wasn't handled by a behavior above then pass along to the parent DynamicConsoleMethodComponent
  807. // to deal with it. If the parent cannot handle the message it will return an error string.
  808. if (!handled)
  809. {
  810. result = Parent::callOnBehaviors( argc, argv );
  811. }
  812. // Clean up.
  813. FrameAllocator::setWaterMark( strdupWatermark );
  814. return result;
  815. }
  816. //-----------------------------------------------------------------------------
  817. const char *BehaviorComponent::_callMethod( U32 argc, const char *argv[], bool callThis /* = true */ )
  818. {
  819. if( mBehaviors.empty() )
  820. return Parent::_callMethod( argc, argv, callThis );
  821. // Copy the arguments to avoid weird clobbery situations.
  822. FrameTemp<char *> argPtrs (argc);
  823. U32 strdupWatermark = FrameAllocator::getWaterMark();
  824. for( U32 i = 0; i < argc; i++ )
  825. {
  826. argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
  827. dStrcpy( argPtrs[i], argv[i] );
  828. }
  829. for( SimSet::iterator i = mBehaviors.begin(); i != mBehaviors.end(); i++ )
  830. {
  831. BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
  832. AssertFatal( pBehavior, "BehaviorComponent::_callMethod - Bad behavior instance in list." );
  833. AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
  834. // Use the BehaviorInstance's namespace
  835. Namespace *pNamespace = pBehavior->getNamespace();
  836. if(!pNamespace)
  837. continue;
  838. // Lookup the Callback Namespace entry and then splice callback
  839. const char *cbName = StringTable->insert(argv[0]);
  840. Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
  841. if( pNSEntry )
  842. {
  843. // Set %this to our BehaviorInstance's Object ID
  844. argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
  845. // Change the Current Console object, execute, restore Object
  846. SimObject *save = gEvalState.thisObject;
  847. gEvalState.thisObject = pBehavior;
  848. pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
  849. gEvalState.thisObject = save;
  850. }
  851. }
  852. // Pass this up to the parent since a BehaviorComponent is still a DynamicConsoleMethodComponent
  853. // it needs to be able to contain other components and behave properly
  854. const char* fnRet = Parent::_callMethod( argc, argv, callThis );
  855. // Clean up.
  856. FrameAllocator::setWaterMark( strdupWatermark );
  857. return fnRet;
  858. }
  859. //-----------------------------------------------------------------------------
  860. void BehaviorComponent::onTamlCustomWrite( TamlCustomNodes& customNodes )
  861. {
  862. // Call parent.
  863. Parent::onTamlCustomWrite( customNodes );
  864. // Fetch behavior count.
  865. const U32 behaviorCount = (U32)mBehaviors.size();
  866. // Finish if no behaviors.
  867. if( behaviorCount == 0 )
  868. return;
  869. // Fetch behavior template asset field type.
  870. StringTableEntry behaviorTemplateAssetFieldType = StringTable->insert( behaviorTemplateAssetName );
  871. // Add custom behaviors node.
  872. TamlCustomNode* pCustomBehaviorNode = customNodes.addNode( behaviorNodeName );
  873. // Iterate behaviors.
  874. for( SimSet::iterator behaviorItr = mBehaviors.begin(); behaviorItr != mBehaviors.end(); ++behaviorItr )
  875. {
  876. // Fetch behavior.
  877. BehaviorInstance* pBehaviorInstance = dynamic_cast<BehaviorInstance*>( *behaviorItr );
  878. // Fetch template.
  879. BehaviorTemplate* pBehaviorTemplate = pBehaviorInstance->getTemplate();
  880. // Add behavior node.
  881. TamlCustomNode* pBehaviorNode = pCustomBehaviorNode->addNode( pBehaviorInstance->getTemplateName() );
  882. // Add behavior Id field.
  883. pBehaviorNode->addField( behaviorIdFieldName, pBehaviorInstance->getBehaviorId() );
  884. // Fetch field count,
  885. const U32 behaviorFieldCount = pBehaviorTemplate->getBehaviorFieldCount();
  886. // Write out the fields which the behavior template knows about.
  887. for( U32 fieldIndex = 0; fieldIndex < behaviorFieldCount; ++fieldIndex )
  888. {
  889. // Fetch field.
  890. BehaviorTemplate::BehaviorField* pBehaviorField = pBehaviorTemplate->getBehaviorField( fieldIndex );
  891. // Set default field type.
  892. S32 fieldType = -1;
  893. // Is this an asset field type?
  894. if ( pBehaviorField != NULL && pBehaviorField->mType == behaviorTemplateAssetFieldType )
  895. {
  896. // Yes, so update field type.
  897. fieldType = TypeAssetId;
  898. }
  899. // Fetch field value.
  900. const char* pFieldValue = pBehaviorInstance->getPrefixedDynamicDataField( pBehaviorField->mName, NULL, fieldType );
  901. // Add behavior field.
  902. pBehaviorNode->addField( pBehaviorField->mName, pFieldValue );
  903. }
  904. }
  905. // Fetch behavior connection count.
  906. const U32 behaviorConnectionCount = (U32)mBehaviorConnections.size();
  907. // Finish if no behavior connections.
  908. if ( behaviorConnectionCount == 0 )
  909. return;
  910. // Iterate instance connections.
  911. for( typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.begin(); instanceItr != mBehaviorConnections.end(); ++instanceItr )
  912. {
  913. // Fetch output name connection(s).
  914. typeOutputNameConnectionHash* pOutputNameConnection = instanceItr->value;
  915. // Iterate output name connections.
  916. for( typeOutputNameConnectionHash::iterator outputItr = pOutputNameConnection->begin(); outputItr != pOutputNameConnection->end(); ++outputItr )
  917. {
  918. // Fetch port connection(s).
  919. typePortConnectionVector* pPortConnections = outputItr->value;
  920. // Iterate input connections.
  921. for( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
  922. {
  923. // Fetch connection.
  924. BehaviorPortConnection* pConnection = connectionItr;
  925. // Add connectionnode.
  926. TamlCustomNode* pConnectionNode = pCustomBehaviorNode->addNode( behaviorConnectionTypeName );
  927. // Add behavior field.
  928. pConnectionNode->addField( pConnection->mOutputName, pConnection->mOutputInstance->getBehaviorId() );
  929. pConnectionNode->addField( pConnection->mInputName, pConnection->mInputInstance->getBehaviorId() );
  930. }
  931. }
  932. }
  933. }
  934. //-----------------------------------------------------------------------------
  935. void BehaviorComponent::onTamlCustomRead( const TamlCustomNodes& customNodes )
  936. {
  937. // Call parent.
  938. Parent::onTamlCustomRead( customNodes );
  939. // Find custom behaviors node.
  940. const TamlCustomNode* pCustomBehaviorNode = customNodes.findNode( behaviorNodeName );
  941. // Do we have the property?
  942. if ( pCustomBehaviorNode != NULL )
  943. {
  944. // Yes, so reset maximum behavior Id.
  945. S32 maximumBehaviorId = 0;
  946. // Fetch behavior Id field name.
  947. StringTableEntry behaviorFieldIdName = StringTable->insert( behaviorIdFieldName );
  948. // Fetch behavior template asset field type.
  949. StringTableEntry behaviorTemplateAssetFieldType = StringTable->insert( behaviorTemplateAssetName );
  950. // Fetch children behavior nodes.
  951. const TamlCustomNodeVector& behaviorNodes = pCustomBehaviorNode->getChildren();
  952. // Iterate behavior nodes.
  953. for( TamlCustomNodeVector::const_iterator behaviorNodeItr = behaviorNodes.begin(); behaviorNodeItr != behaviorNodes.end(); ++behaviorNodeItr )
  954. {
  955. // Fetch behavior node.
  956. TamlCustomNode* pBehaviorNode = *behaviorNodeItr;
  957. if ( pBehaviorNode->getNodeName() == behaviorConnectionTypeName )
  958. {
  959. // Fetch field nodes.
  960. const TamlCustomFieldVector& connectionFieldNodes = pBehaviorNode->getFields();
  961. // Are there two properties?
  962. if ( connectionFieldNodes.size() != 2 )
  963. {
  964. // No, so warn.
  965. Con::warnf( "BehaviorComponent::onTamlCustomRead() - Encountered a behavior connection with more than two connection fields." );
  966. continue;
  967. }
  968. // Fetch property field #1.
  969. TamlCustomField* pPropertyField1 = *connectionFieldNodes.begin();
  970. TamlCustomField* pPropertyField2 = *(connectionFieldNodes.begin()+1);
  971. // Fetch behavior instances #1.
  972. BehaviorInstance* pBehaviorInstance1 = getBehaviorByInstanceId( dAtoi( pPropertyField1->getFieldValue() ) );
  973. // Did we find the behavior?
  974. if ( pBehaviorInstance1 == NULL )
  975. {
  976. // No, so warn.
  977. Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior instance Id '%s=%s'.",
  978. pPropertyField1->getFieldName(), pPropertyField1->getFieldValue() );
  979. continue;
  980. }
  981. // Fetch behavior instances #2.
  982. BehaviorInstance* pBehaviorInstance2 = getBehaviorByInstanceId( dAtoi( pPropertyField2->getFieldValue() ) );
  983. // Did we find the behavior?
  984. if ( pBehaviorInstance2 == NULL )
  985. {
  986. // No, so warn.
  987. Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior instance Id '%s=%s'.",
  988. pPropertyField2->getFieldName(), pPropertyField2->getFieldValue() );
  989. continue;
  990. }
  991. // Fetch behavior fields.
  992. StringTableEntry behaviorFieldName1 = pPropertyField1->getFieldName();
  993. StringTableEntry behaviorFieldName2 = pPropertyField2->getFieldName();
  994. BehaviorInstance* pOutputInstance;
  995. BehaviorInstance* pInputInstance;
  996. StringTableEntry outputName;
  997. StringTableEntry inputName;
  998. // Is the output on behavior instance #1?
  999. if ( pBehaviorInstance1->getTemplate()->hasBehaviorOutput( behaviorFieldName1 ) )
  1000. {
  1001. // Yes, so has behavior instance #2 got the input?
  1002. if ( !pBehaviorInstance2->getTemplate()->hasBehaviorInput( behaviorFieldName2 ) )
  1003. {
  1004. // No, so warn.
  1005. Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior input '%s' on behavior '%s'.",
  1006. behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
  1007. continue;
  1008. }
  1009. // Assign output/input appropriately.
  1010. pOutputInstance = pBehaviorInstance1;
  1011. pInputInstance = pBehaviorInstance2;
  1012. outputName = behaviorFieldName1;
  1013. inputName = behaviorFieldName2;
  1014. }
  1015. // Is the output on behavior instance #2?
  1016. else if ( pBehaviorInstance2->getTemplate()->hasBehaviorOutput( behaviorFieldName2 ) )
  1017. {
  1018. // Yes, so has behavior instance #1 got the input?
  1019. if ( !pBehaviorInstance1->getTemplate()->hasBehaviorInput( behaviorFieldName1 ) )
  1020. {
  1021. // No, so warn.
  1022. Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior input '%s' on behavior '%s'.",
  1023. behaviorFieldName1, pBehaviorInstance1->getTemplateName() );
  1024. continue;
  1025. }
  1026. // Assign output/input appropriately.
  1027. pOutputInstance = pBehaviorInstance2;
  1028. pInputInstance = pBehaviorInstance1;
  1029. outputName = behaviorFieldName2;
  1030. inputName = behaviorFieldName1;
  1031. }
  1032. else
  1033. {
  1034. // Warn.
  1035. Con::warnf( "BehaviorComponent::onTamlCustomRead() - Invalid output/input on behavior connection '%s=%s' & '%s=%s''.",
  1036. behaviorFieldName1, pBehaviorInstance1->getTemplateName(),
  1037. behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
  1038. continue;
  1039. }
  1040. // Can we connect?
  1041. if ( !connect( pOutputInstance, pInputInstance, outputName, inputName ) )
  1042. {
  1043. // No, so warn.
  1044. Con::warnf( "BehaviorComponent::onTamlCustomRead() - Failed to connect behaviors '%s=%s' & '%s=%s''.",
  1045. behaviorFieldName1, pBehaviorInstance1->getTemplateName(),
  1046. behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
  1047. continue;
  1048. }
  1049. }
  1050. else
  1051. {
  1052. // Fetch template.
  1053. BehaviorTemplate* pTemplate = dynamic_cast<BehaviorTemplate *>( Sim::findObject( pBehaviorNode->getNodeName() ) );
  1054. // Find template?
  1055. if( pTemplate == NULL )
  1056. {
  1057. // No, so warn appropriately.
  1058. Con::warnf( "BehaviorComponent::onTamlCustomRead() - Missing Behavior '%s'", pBehaviorNode->getNodeName() );
  1059. if( isMethod( "onBehaviorMissing" ) )
  1060. Con::executef( this, 2, "onBehaviorMissing", pBehaviorNode->getNodeName() );
  1061. // Skip it.
  1062. continue;
  1063. }
  1064. // Create an instance of the template.
  1065. BehaviorInstance* pBehaviorInstance = pTemplate->createInstance();
  1066. // Did we create a behavior instance?
  1067. if ( pBehaviorInstance == NULL )
  1068. {
  1069. // No, so warn appropriately.
  1070. Con::warnf( "BehaviorComponent::onTamlCustomRead() - Found behavior could not create an instance '%s'", pBehaviorNode->getNodeName() );
  1071. if( isMethod( "onBehaviorMissing" ) )
  1072. Con::executef( this, 2, "onBehaviorMissing", pBehaviorNode->getNodeName() );
  1073. // Skip it.
  1074. continue;
  1075. }
  1076. S32 behaviorId = 0;
  1077. // Fetch field nodes.
  1078. const TamlCustomFieldVector& fields = pBehaviorNode->getFields();
  1079. // Iterate fields.
  1080. for ( TamlCustomFieldVector::const_iterator nodeFieldItr = fields.begin(); nodeFieldItr != fields.end(); ++nodeFieldItr )
  1081. {
  1082. // Fetch field.
  1083. TamlCustomField* pField = *nodeFieldItr;
  1084. // Fetch field name.
  1085. const char* pFieldName = pField->getFieldName();
  1086. // Fetch field value.
  1087. const char* pFieldValue = pField->getFieldValue();
  1088. // Is this the behavior field Id name?
  1089. if ( pFieldName == behaviorFieldIdName )
  1090. {
  1091. // Yes, so assign it.
  1092. behaviorId = dAtoi( pFieldValue );
  1093. // Is the behavior Id valid?
  1094. if ( behaviorId < 1 )
  1095. {
  1096. // No, so warn.
  1097. Con::warnf( "BehaviorComponent::onTamlCustomRead() - Encountered an invalid behavior Id of '%d' on behavior '%s'.",
  1098. behaviorId,
  1099. pBehaviorNode->getNodeName() );
  1100. }
  1101. // Update maximum behavior Id found.
  1102. if ( behaviorId > maximumBehaviorId )
  1103. maximumBehaviorId = behaviorId;
  1104. /// Skip it.
  1105. continue;
  1106. }
  1107. // Fetch behavior field.
  1108. BehaviorTemplate::BehaviorField* pBehaviorField = pTemplate->getBehaviorField( pFieldName );
  1109. // Set default field type.
  1110. S32 fieldType = -1;
  1111. // Is this an asset field type?
  1112. if ( pBehaviorField != NULL && pBehaviorField->mType == behaviorTemplateAssetFieldType )
  1113. {
  1114. // Yes, so update field type.
  1115. fieldType = TypeAssetId;
  1116. }
  1117. // Set field.
  1118. pBehaviorInstance->setPrefixedDynamicDataField( pField->getFieldName(), NULL, pField->getFieldValue(), fieldType );
  1119. }
  1120. // Add behavior.
  1121. addBehavior( pBehaviorInstance );
  1122. // Override the automatically allocated behavior Id if the Id field is already defined in the TAML file.
  1123. // NOTE: This must be done after adding the behavior.
  1124. if (behaviorId != 0)
  1125. {
  1126. pBehaviorInstance->setBehaviorId( behaviorId );
  1127. }
  1128. }
  1129. }
  1130. // Set master as next behavior id.
  1131. mMasterBehaviorId = (U32)maximumBehaviorId+1;
  1132. }
  1133. }
  1134. //-----------------------------------------------------------------------------
  1135. static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
  1136. {
  1137. // Sanity!
  1138. AssertFatal( pClassRep != NULL, "BehaviorComponent::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
  1139. AssertFatal( pParentElement != NULL, "BehaviorComponent::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
  1140. // Write an unrestricted custom Taml schema.
  1141. Taml::WriteUnrestrictedCustomTamlSchema( behaviorNodeName, pClassRep, pParentElement );
  1142. }
  1143. //-----------------------------------------------------------------------------
  1144. IMPLEMENT_CONOBJECT_SCHEMA( BehaviorComponent, WriteCustomTamlSchema );