behaviorComponent.cpp 53 KB

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