behaviorComponent.cpp 54 KB

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