123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "io/stream.h"
- #include "string/stringUnit.h"
- #include "memory/frameAllocator.h"
- #include "component/behaviors/behaviorComponent.h"
- #include "component/behaviors/behaviorTemplate.h"
- #ifndef _ASSET_FIELD_TYPES_H_
- #include "assets/assetFieldTypes.h"
- #endif
- #ifndef _TAML_CUSTOM_H_
- #include "persistence/taml/tamlCustom.h"
- #endif
- #ifndef _TAML_H_
- #include "persistence/taml/taml.h"
- #endif
- // Script bindings.
- #include "behaviorComponent_ScriptBinding.h"
- //-----------------------------------------------------------------------------
- static StringTableEntry behaviorIdFieldName = StringTable->insert( "Id" );
- static StringTableEntry behaviorNodeName = StringTable->insert( "Behaviors" );
- static StringTableEntry behaviorConnectionTypeName = StringTable->insert( "Connection" );
- static StringTableEntry behaviorTemplateAssetName = StringTable->insert( "Asset" );
- //-----------------------------------------------------------------------------
- BehaviorComponent::BehaviorComponent() :
- mMasterBehaviorId( 1 ),
- mpBehaviorFieldNames( NULL )
- {
- SIMSET_SET_ASSOCIATION( mBehaviors );
- }
- //-----------------------------------------------------------------------------
- bool BehaviorComponent::onAdd()
- {
- if( !Parent::onAdd() )
- return false;
- return true;
- }
- //-----------------------------------------------------------------------------
- void BehaviorComponent::onRemove()
- {
- // Remove all behaviors and notify.
- clearBehaviors();
- // Call parent.
- Parent::onRemove();
- }
- //-----------------------------------------------------------------------------
- void BehaviorComponent::onDeleteNotify( SimObject *object )
- {
- // Cast to a behavior instance.
- BehaviorInstance* pInstance = dynamic_cast<BehaviorInstance*>( object );
- // Ignore if not appropriate.
- if ( pInstance == NULL )
- return;
- // Is the behavior instance owned by this component?
- if ( pInstance->getBehaviorOwner() == this )
- {
- // Yes, so remove.
- removeBehavior( pInstance, false );
- }
- // Destroy any input connections to the instance.
- destroyBehaviorInputConnections( pInstance );
- }
- //-----------------------------------------------------------------------------
- void BehaviorComponent::copyTo(SimObject* obj)
- {
- // Call parent.
- Parent::copyTo(obj);
- // Fetch object.
- BehaviorComponent* pObject = dynamic_cast<BehaviorComponent*>(obj);
- // Sanity!
- AssertFatal(pObject != NULL, "BehaviorComponent::copyTo() - Object is not the correct type.");
- // Clear behaviors.
- pObject->clearBehaviors();
- // Behaviors
- U32 behaviorCount = getBehaviorCount();
- // Finish if no behaviors.
- if ( behaviorCount == 0 )
- return;
- // Initialize a clone map.
- typedef HashMap<BehaviorInstance*,BehaviorInstance*> typeBehaviorCloneHash;
- typeBehaviorCloneHash behaviorInstanceCloneMap;
- // Iterate behaviors.
- for ( U32 index = 0; index < behaviorCount; ++index )
- {
- // Clone the behavior instance.
- BehaviorInstance* pFromInstance = getBehavior(index);
- BehaviorTemplate* pFromTemplate = pFromInstance->getTemplate();
- BehaviorInstance* pToInstance = pFromTemplate->createInstance();
- // Assign dynamic fields from behavior instance.
- pToInstance->assignDynamicFieldsFrom( pFromInstance );
- // Add the behavior instance.
- pObject->addBehavior(pToInstance);
- // Add to the clone map.
- behaviorInstanceCloneMap.insert( pFromInstance, pToInstance );
- }
- // Iterate instance connections.
- for( typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.begin(); instanceItr != mBehaviorConnections.end(); ++instanceItr )
- {
- // Fetch output name connection(s).
- typeOutputNameConnectionHash* pOutputNameConnection = instanceItr->value;
- // Iterate output name connections.
- for( typeOutputNameConnectionHash::iterator outputItr = pOutputNameConnection->begin(); outputItr != pOutputNameConnection->end(); ++outputItr )
- {
- // Fetch port connection(s).
- typePortConnectionVector* pPortConnections = outputItr->value;
- // Iterate input connections.
- for( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
- {
- // Fetch connection.
- BehaviorPortConnection* pConnection = connectionItr;
- // Find behavior instance mappings.
- typeBehaviorCloneHash::iterator toOutputItr = behaviorInstanceCloneMap.find( pConnection->mOutputInstance );
- typeBehaviorCloneHash::iterator toInputItr = behaviorInstanceCloneMap.find( pConnection->mInputInstance );
- // Sanity!
- AssertFatal( toOutputItr != behaviorInstanceCloneMap.end(), "Failed to find output behavior instance mapping during copy." );
- AssertFatal( toInputItr != behaviorInstanceCloneMap.end(), "Failed to find input behavior instance mapping during copy." );
- // Fetch behavior instance mappings.
- BehaviorInstance* pToInstanceOutput = toOutputItr->value;
- BehaviorInstance* pToInstanceInput = toInputItr->value;
- // Make cloned connection.
- pObject->connect( pToInstanceOutput, pToInstanceInput, pConnection->mOutputName, pConnection->mInputName );
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- bool BehaviorComponent::addBehavior( BehaviorInstance* bi )
- {
- if( bi == NULL || !bi->isProperlyAdded() )
- return false;
- // Store behavior.
- mBehaviors.pushObject( bi );
- // Notify if the behavior instance is destroyed.
- deleteNotify( bi );
- // Set the behavior owner.
- bi->setBehaviorOwner( this );
- // Allocate a behavior Id.
- bi->setBehaviorId( mMasterBehaviorId++ );
- if( bi->isMethod("onBehaviorAdd") )
- Con::executef( bi , 1, "onBehaviorAdd" );
- return true;
- }
- //-----------------------------------------------------------------------------
- bool BehaviorComponent::removeBehavior( BehaviorInstance *bi, bool deleteBehavior )
- {
- for( SimSet::iterator itr = mBehaviors.begin(); itr != mBehaviors.end(); ++itr )
- {
- if( *itr == bi )
- {
- mBehaviors.removeObject( *itr );
- // Perform callback if allowed.
- if( bi->isProperlyAdded() && bi->isMethod("onBehaviorRemove") )
- Con::executef( bi , 1, "onBehaviorRemove" );
- // Destroy any output connections.
- destroyBehaviorOutputConnections( bi );
- if ( deleteBehavior && bi->isProperlyAdded() )
- {
- bi->deleteObject();
- }
- else
- {
- bi->setBehaviorOwner( NULL );
- bi->setBehaviorId( 0 );
- // Remove delete notification.
- clearNotify( bi );
- }
- return true;
- }
- }
- return false;
- }
- //-----------------------------------------------------------------------------
- void BehaviorComponent::clearBehaviors()
- {
- while( mBehaviors.size() > 0 )
- {
- BehaviorInstance *bi = dynamic_cast<BehaviorInstance *>( mBehaviors.first() );
- removeBehavior( bi );
- }
- }
- //-----------------------------------------------------------------------------
- BehaviorInstance *BehaviorComponent::getBehavior( StringTableEntry behaviorTemplateName )
- {
- for( SimSet::iterator itr = mBehaviors.begin(); itr != mBehaviors.end(); ++itr )
- {
- // Fetch behavior.
- BehaviorInstance* pBehaviorInstance = dynamic_cast<BehaviorInstance*>(*itr);
- if ( !pBehaviorInstance || pBehaviorInstance->getTemplateName() != behaviorTemplateName )
- continue;
- return pBehaviorInstance;
- }
- return NULL;
- }
- //-----------------------------------------------------------------------------
- bool BehaviorComponent::reOrder( BehaviorInstance *obj, U32 desiredIndex /* = 0 */ )
- {
- if( desiredIndex > (U32)mBehaviors.size() )
- return false;
- SimObject *target = mBehaviors.at( desiredIndex );
- return mBehaviors.reOrder( obj, target );
- }
- //-----------------------------------------------------------------------------
- void BehaviorComponent::destroyBehaviorOutputConnections( BehaviorInstance* pOutputBehavior )
- {
- // Sanity!
- AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
- // Is the output behavior owned by this behavior component?
- if ( pOutputBehavior->getBehaviorOwner() != this )
- {
- // No, so warn.
- Con::warnf(
- "Could not destroy output behavior connection for behavior '%s' as the output behavior is not owned by this component.",
- pOutputBehavior->getTemplateName()
- );
- return;
- }
- // Find behavior instance connections.
- typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
- // Finish if there are no outbound connections for this output behavior.
- if ( instanceItr == mBehaviorConnections.end() )
- return;
- // Fetch output name hash.
- typeOutputNameConnectionHash* pOutputNameHash = instanceItr->value;
- // Iterate all outputs.
- for ( typeOutputNameConnectionHash::iterator outputItr = pOutputNameHash->begin(); outputItr != pOutputNameHash->end(); ++outputItr )
- {
- // Fetch port connection(s).
- typePortConnectionVector* pPortConnections = outputItr->value;
- // Destroy port connections.
- delete pPortConnections;
- }
- // Destroy outputs.
- delete pOutputNameHash;
- // Remove connection.
- mBehaviorConnections.erase( pOutputBehavior->getId() );
- }
- //-----------------------------------------------------------------------------
- void BehaviorComponent::destroyBehaviorInputConnections( BehaviorInstance* pInputBehavior )
- {
- // Sanity!
- AssertFatal( pInputBehavior != NULL, "Input behavior cannot be NULL." );
- // Iterate connections.
- for ( typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.begin(); instanceItr != mBehaviorConnections.end(); ++instanceItr )
- {
- // Fetch output name hash.
- typeOutputNameConnectionHash* pOutputNameHash = instanceItr->value;
- // Iterate all outputs.
- for ( typeOutputNameConnectionHash::iterator outputItr = pOutputNameHash->begin(); outputItr != pOutputNameHash->end(); ++outputItr )
- {
- // Fetch port connection(s).
- typePortConnectionVector* pPortConnections = outputItr->value;
- bool connectionFound;
- do
- {
- // Flag connection as 'not found' initially.
- connectionFound = false;
- // Look for an existing connection to the specified input instance.
- for ( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
- {
- // Is this the input behavior?
- if ( connectionItr->mInputInstance == pInputBehavior )
- {
- // Yes, so destroy it.
- pPortConnections->erase_fast( connectionItr );
- // Flag connection as 'found'.
- connectionFound = true;
- break;
- }
- }
- } while (connectionFound);
- }
- }
- }
- //-----------------------------------------------------------------------------
- BehaviorInstance* BehaviorComponent::getBehaviorByInstanceId( const U32 behaviorId )
- {
- for( SimSet::iterator instanceItr = mBehaviors.begin(); instanceItr != mBehaviors.end(); ++instanceItr )
- {
- // Fetch behavior instance.
- BehaviorInstance* pInstance = static_cast<BehaviorInstance*>( *instanceItr );
- // Return instance if it has the same behavior Id.
- if ( pInstance->getBehaviorId() == behaviorId )
- return pInstance;
- }
- // Not found.
- return NULL;
- }
- //-----------------------------------------------------------------------------
- bool BehaviorComponent::connect( BehaviorInstance* pOutputBehavior, BehaviorInstance* pInputBehavior, StringTableEntry pOutputName, StringTableEntry pInputName )
- {
- // Sanity!
- AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
- AssertFatal( pInputBehavior != NULL, "Input behavior cannot be NULL." );
- AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
- AssertFatal( pInputName != NULL, "Input name cannot be NULL." );
- // Is the output behavior owned by this behavior component?
- if ( pOutputBehavior->getBehaviorOwner() != this )
- {
- // No, so warn.
- Con::warnf(
- "Could not connect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the output behavior is not owned by this component.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- // Is the input behavior owned by this behavior component?
- if ( pInputBehavior->getBehaviorOwner() != this )
- {
- // No, so warn.
- Con::warnf(
- "Could not connect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the input behavior is not owned by this component.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- // Does the output behavior have the specified output?
- if ( !pOutputBehavior->getTemplate()->hasBehaviorOutput( pOutputName ) )
- {
- // No, so warn.
- Con::warnf(
- "Could not connect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the output behavior does not have such an output.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- // Does the input behavior have the specified input?
- if ( !pInputBehavior->getTemplate()->hasBehaviorInput( pInputName ) )
- {
- // No, so warn.
- Con::warnf(
- "Could not connect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the input behavior does not have such an input.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- // Find behavior instance connections.
- typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
- // Are there currently any outbound connections for this output instance?
- if ( instanceItr == mBehaviorConnections.end() )
- {
- // No, so create an entry for this instance.
- typeOutputNameConnectionHash* pOutputHash = new typeOutputNameConnectionHash();
- // Insert new output hash.
- instanceItr = mBehaviorConnections.insert( pOutputBehavior->getId(), pOutputHash );
- }
- // Fetch output name hash.
- typeOutputNameConnectionHash* pOutputNameHash = instanceItr->value;
- // Find instance output connection.
- typeOutputNameConnectionHash::iterator outputItr = pOutputNameHash->find( pOutputName );
- // Are there currently any outbound connections for this specific output?
- if ( outputItr == pOutputNameHash->end() )
- {
- // No, so create an entry for this output.
- typePortConnectionVector* pPortConnections = new typePortConnectionVector();
- // Insert new port connections.
- outputItr = pOutputNameHash->insert( pOutputName, pPortConnections );
- }
- // Fetch port connection(s).
- typePortConnectionVector* pPortConnections = outputItr->value;
- // Look for an identical connection.
- for ( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
- {
- // Is this an identical connection?
- if ( connectionItr->mInputInstance == pInputBehavior && connectionItr->mInputName == pInputName )
- {
- // Yes, so warn.
- Con::warnf(
- "Could not connect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the connection already exists.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- }
-
- // Populate port connection.
- BehaviorPortConnection portConnection( pOutputBehavior, pInputBehavior, pOutputName, pInputName );
- // Add port connection.
- pPortConnections->push_back( portConnection );
- // Notify if the input behavior instance is destroyed.
- deleteNotify( pInputBehavior );
- return true;
- }
- //-----------------------------------------------------------------------------
- bool BehaviorComponent::disconnect( BehaviorInstance* pOutputBehavior, BehaviorInstance* pInputBehavior, StringTableEntry pOutputName, StringTableEntry pInputName )
- {
- // Sanity!
- AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
- AssertFatal( pInputBehavior != NULL, "Input behavior cannot be NULL." );
- AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
- AssertFatal( pInputName != NULL, "Input name cannot be NULL." );
- // Is the output behavior owned by this behavior component?
- if ( pOutputBehavior->getBehaviorOwner() != this )
- {
- // No, so warn.
- Con::warnf(
- "Could not disconnect output '%s' on behavior '%s' from input '%s' on behavior '%s' as the output behavior is not owned by this component.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- // Is the input behavior owned by this behavior component?
- if ( pInputBehavior->getBehaviorOwner() != this )
- {
- // No, so warn.
- Con::warnf(
- "Could not disconnect output '%s' on behavior '%s' from input '%s' on behavior '%s' as the input behavior is not owned by this component.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- // Does the output behavior have the specified output?
- if ( !pOutputBehavior->getTemplate()->hasBehaviorOutput( pOutputName ) )
- {
- // No, so warn.
- Con::warnf(
- "Could not disconnect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the output behavior does not have such an output.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- // Does the input behavior have the specified input?
- if ( !pInputBehavior->getTemplate()->hasBehaviorInput( pInputName ) )
- {
- // No, so warn.
- Con::warnf(
- "Could not disconnect output '%s' on behavior '%s' to input '%s' on behavior '%s' as the input behavior does not have such an input.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- // Find behavior instance connections.
- typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
- // Are there currently any outbound connections for this output instance?
- if ( instanceItr == mBehaviorConnections.end() )
- {
- // No, so warn.
- Con::warnf(
- "Could not disconnect output '%s' on behavior '%s' from input '%s' on behavior '%s' as the behavior does not have any connections.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- // Fetch output name hash.
- typeOutputNameConnectionHash* pOutputNameHash = instanceItr->value;
- // Find instance output connection.
- typeOutputNameConnectionHash::iterator outputItr = pOutputNameHash->find( pOutputName );
- // Are there currently any outbound connections for this specific output?
- if ( outputItr == pOutputNameHash->end() )
- {
- // No, so warn.
- Con::warnf(
- "Could not disconnect output '%s' on behavior '%s' from input '%s' on behavior '%s' as the specified output does not have any connections.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- // Fetch port connection(s).
- typePortConnectionVector* pPortConnections = outputItr->value;
- // Look for an existing connection to the specified input.
- for ( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
- {
- // Is this the requested disconnection?
- if ( connectionItr->mInputInstance == pInputBehavior && connectionItr->mInputName == pInputName )
- {
- // Yes, so remove connection.
- pPortConnections->erase_fast( connectionItr );
- return true;
- }
- }
- // Not found so warn.
- Con::warnf(
- "Could not disconnect output '%s' on behavior '%s' from input '%s' on behavior '%s' as the connection does not exist.",
- pOutputName,
- pOutputBehavior->getTemplateName(),
- pInputName,
- pInputBehavior->getTemplateName()
- );
-
- return false;
- }
- //-----------------------------------------------------------------------------
- bool BehaviorComponent::raise( BehaviorInstance* pOutputBehavior, StringTableEntry pOutputName )
- {
- // Sanity!
- AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
- AssertFatal( pOutputBehavior->isProperlyAdded(), "Output behavior is not registered." );
- AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
- // Is the output behavior owned by this behavior component?
- if ( pOutputBehavior->getBehaviorOwner() != this )
- {
- // No, so warn.
- Con::warnf(
- "Could not raise output '%s' on behavior '%s' as the output behavior is not owned by this component.",
- pOutputName,
- pOutputBehavior->getTemplateName()
- );
- return false;
- }
- // Does the behavior have the specified output?
- if ( !pOutputBehavior->getTemplate()->hasBehaviorOutput( pOutputName ) )
- {
- // No, so warn.
- Con::warnf(
- "Could not raise output '%s' on behavior '%s' as the behavior does not have such an output.",
- pOutputName,
- pOutputBehavior->getTemplateName()
- );
- return false;
- }
- // Execute a callback for the output.
- // NOTE: This callback should not delete behaviors otherwise strange things can happen!
- Con::executef( this, 2, pOutputName, pOutputBehavior->getIdString() );
- // Find behavior instance connections.
- typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
- // Finish if there are no outbound connections for this output behavior.
- if ( instanceItr == mBehaviorConnections.end() )
- return true;
- // Find instance output connection.
- typeOutputNameConnectionHash::iterator outputItr = instanceItr->value->find( pOutputName );
- // Finish if there are no outbound connections for this output.
- if ( outputItr == instanceItr->value->end() )
- return true;
- // Fetch port connection(s).
- typePortConnectionVector* pPortConnections = outputItr->value;
- // Process output connection(s).
- for ( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
- {
- // Fetch input behavior.
- BehaviorInstance* pInputBehavior = connectionItr->mInputInstance;
- // Fetch input name.
- StringTableEntry pInputName = connectionItr->mInputName;
- #ifdef TORQUE_DEBUG
- // Sanity!
- AssertFatal( pInputBehavior->isProperlyAdded(), "Input behavior is not registered." );
- // Does the behavior have the specified input?
- if ( !pInputBehavior->getTemplate()->hasBehaviorInput( pInputName ) )
- {
- // No, so warn.
- Con::warnf(
- "Could not raise input '%s' on behavior '%s' as the behavior does not have such an input.",
- pInputName,
- pInputBehavior->getTemplateName()
- );
- return false;
- }
- #endif
- // Execute a callback for the input.
- // NOTE: This callback should not delete behaviors otherwise strange things can happen!
- Con::executef( pInputBehavior, 3, pInputName, pOutputBehavior->getIdString(), pOutputName );
- }
- return true;
- }
- //-----------------------------------------------------------------------------
- U32 BehaviorComponent::getBehaviorConnectionCount( BehaviorInstance* pOutputBehavior, StringTableEntry pOutputName )
- {
- // Sanity!
- AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
- AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
- // Is the output behavior owned by this behavior component?
- if ( pOutputBehavior->getBehaviorOwner() != this )
- {
- // No, so warn.
- Con::warnf(
- "Could not get behavior connection count on output '%s' on behavior '%s' as the output behavior is not owned by this component.",
- pOutputName,
- pOutputBehavior->getTemplateName()
- );
- return 0;
- }
- // Does the behavior have the specified output?
- if ( !pOutputBehavior->getTemplate()->hasBehaviorOutput( pOutputName ) )
- {
- // No, so warn.
- Con::warnf(
- "Could not get behavior connection count for output '%s' on behavior '%s' as the behavior does not have such an output.",
- pOutputName,
- pOutputBehavior->getTemplateName()
- );
- return 0;
- }
- // Find behavior instance connections.
- typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
- // Finish if there are no outbound connections for this output behavior.
- if ( instanceItr == mBehaviorConnections.end() )
- return 0;
- // Find instance output connection.
- typeOutputNameConnectionHash::iterator outputItr = instanceItr->value->find( pOutputName );
- // Finish if there are no outbound connections for this output.
- if ( outputItr == instanceItr->value->end() )
- return 0;
- // Fetch port connection(s).
- typePortConnectionVector* pPortConnections = outputItr->value;
- // Return number of connections.
- return pPortConnections->size();
- }
- //-----------------------------------------------------------------------------
- const BehaviorComponent::BehaviorPortConnection* BehaviorComponent::getBehaviorConnection( BehaviorInstance* pOutputBehavior, StringTableEntry pOutputName, const U32 connectionIndex )
- {
- // Sanity!
- AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
- AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
- // Fetch behavior connection count.
- const U32 behaviorConnectionCount = getBehaviorConnectionCount( pOutputBehavior, pOutputName );
- // Finish if there are no connections.
- if ( behaviorConnectionCount == 0 )
- return NULL;
- // Is the connection index valid?
- if ( connectionIndex >= behaviorConnectionCount )
- {
- // No, so warn.
- Con::warnf(
- "Could not get behavior the behavior connection index '%d' on output '%s' on behavior '%s' as the output behavior only has '%d' connections",
- connectionIndex,
- pOutputName,
- pOutputBehavior->getTemplateName(),
- behaviorConnectionCount
- );
- return NULL;
- }
- // Fetch behavior connections.
- const typePortConnectionVector* pConnections = getBehaviorConnections( pOutputBehavior, pOutputName );
- // Fetch behavior connection.
- const BehaviorComponent::BehaviorPortConnection* pBehaviorConnection = &((*pConnections)[connectionIndex]);
- // Return behavior connection.
- return pBehaviorConnection;
- }
- //-----------------------------------------------------------------------------
- const BehaviorComponent::typePortConnectionVector* BehaviorComponent::getBehaviorConnections( BehaviorInstance* pOutputBehavior, StringTableEntry pOutputName )
- {
- // Sanity!
- AssertFatal( pOutputBehavior != NULL, "Output behavior cannot be NULL." );
- AssertFatal( pOutputName != NULL, "Output name cannot be NULL." );
- // Is the output behavior owned by this behavior component?
- if ( pOutputBehavior->getBehaviorOwner() != this )
- {
- // No, so warn.
- Con::warnf(
- "Could not get behavior connections on output '%s' on behavior '%s' as the output behavior is not owned by this component.",
- pOutputName,
- pOutputBehavior->getTemplateName()
- );
- return NULL;
- }
- // Does the behavior have the specified output?
- if ( !pOutputBehavior->getTemplate()->hasBehaviorOutput( pOutputName ) )
- {
- // No, so warn.
- Con::warnf(
- "Could not get behavior connections for output '%s' on behavior '%s' as the behavior does not have such an output.",
- pOutputName,
- pOutputBehavior->getTemplateName()
- );
- return NULL;
- }
- // Find behavior instance connections.
- typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.find( pOutputBehavior->getId() );
- // Finish if there are no outbound connections for this output behavior.
- if ( instanceItr == mBehaviorConnections.end() )
- return NULL;
- // Find instance output connection.
- typeOutputNameConnectionHash::iterator outputItr = instanceItr->value->find( pOutputName );
- // Finish if there are no outbound connections for this output.
- if ( outputItr == instanceItr->value->end() )
- return NULL;
- // Fetch port connection(s).
- typePortConnectionVector* pPortConnections = outputItr->value;
- // Return number of connections.
- return pPortConnections;
- }
- //-----------------------------------------------------------------------------
- void BehaviorComponent::write( Stream &stream, U32 tabStop, U32 flags /* = 0 */ )
- {
- // Export selected only?
- if( ( flags & SelectedOnly ) && !isSelected() )
- {
- return;
- }
- if( mBehaviors.size() == 0 )
- {
- Parent::write( stream, tabStop, flags );
- return;
- }
- // The work we want to perform here is in the Taml callback.
- onTamlPreWrite();
- // Write object.
- Parent::write( stream, tabStop, flags );
- // The work we want to perform here is in the Taml callback.
- onTamlPostWrite();
- }
- //-----------------------------------------------------------------------------
- bool BehaviorComponent::handlesConsoleMethod( const char *fname, S32 *routingId )
- {
- // CodeReview [6/25/2007 justind]
- // If we're deleting the BehaviorComponent, don't forward the call to the
- // behaviors, the parent onRemove will handle freeing them
- // This should really be handled better, and is in the Parent implementation
- // but behaviors are a special case because they always want to be called BEFORE
- // the parent to act.
- if( dStricmp( fname, "delete" ) == 0 )
- return Parent::handlesConsoleMethod( fname, routingId );
- for( SimSet::iterator nItr = mBehaviors.begin(); nItr != mBehaviors.end(); nItr++ )
- {
- SimObject *pComponent = dynamic_cast<SimObject *>(*nItr);
- if( pComponent != NULL && pComponent->isMethod( fname ) )
- {
- *routingId = -2; // -2 denotes method on component
- return true;
- }
- }
- // Let parent handle it
- return Parent::handlesConsoleMethod( fname, routingId );
- }
- //-----------------------------------------------------------------------------
- // Needed to be able to directly call execute on a Namespace::Entry
- extern ExprEvalState gEvalState;
- const char *BehaviorComponent::callOnBehaviors( U32 argc, const char *argv[] )
- {
- if( mBehaviors.empty() )
- return Parent::callOnBehaviors( argc, argv );
-
- // Copy the arguments to avoid weird clobbery situations.
- FrameTemp<char *> argPtrs (argc);
-
- U32 strdupWatermark = FrameAllocator::getWaterMark();
- for( U32 i = 0; i < argc; i++ )
- {
- argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
- dStrcpy( argPtrs[i], argv[i] );
- }
- // Walk backwards through the list just as with components
- const char* result = "";
- bool handled = false;
- for( SimSet::iterator i = (mBehaviors.end()-1); i >= mBehaviors.begin(); i-- )
- {
- BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
- AssertFatal( pBehavior, "BehaviorComponent::callOnBehaviors - Bad behavior instance in list." );
- AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
- // Use the BehaviorInstance's namespace
- Namespace *pNamespace = pBehavior->getNamespace();
- if(!pNamespace)
- continue;
- // Lookup the Callback Namespace entry and then splice callback
- const char *cbName = StringTable->insert(argv[0]);
- Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
- if( pNSEntry )
- {
- // Set %this to our BehaviorInstance's Object ID
- argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
- // Change the Current Console object, execute, restore Object
- SimObject *save = gEvalState.thisObject;
- gEvalState.thisObject = pBehavior;
- result = pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
- gEvalState.thisObject = save;
- handled = true;
- break;
- }
- }
- // If this wasn't handled by a behavior above then pass along to the parent DynamicConsoleMethodComponent
- // to deal with it. If the parent cannot handle the message it will return an error string.
- if (!handled)
- {
- result = Parent::callOnBehaviors( argc, argv );
- }
- // Clean up.
- FrameAllocator::setWaterMark( strdupWatermark );
- return result;
- }
- //-----------------------------------------------------------------------------
- const char *BehaviorComponent::_callMethod( U32 argc, const char *argv[], bool callThis /* = true */ )
- {
- if( mBehaviors.empty() )
- return Parent::_callMethod( argc, argv, callThis );
-
- // Copy the arguments to avoid weird clobbery situations.
- FrameTemp<char *> argPtrs (argc);
-
- U32 strdupWatermark = FrameAllocator::getWaterMark();
- for( U32 i = 0; i < argc; i++ )
- {
- argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
- dStrcpy( argPtrs[i], argv[i] );
- }
- for( SimSet::iterator i = mBehaviors.begin(); i != mBehaviors.end(); i++ )
- {
- BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
- AssertFatal( pBehavior, "BehaviorComponent::_callMethod - Bad behavior instance in list." );
- AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
- // Use the BehaviorInstance's namespace
- Namespace *pNamespace = pBehavior->getNamespace();
- if(!pNamespace)
- continue;
- // Lookup the Callback Namespace entry and then splice callback
- const char *cbName = StringTable->insert(argv[0]);
- Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
- if( pNSEntry )
- {
- // Set %this to our BehaviorInstance's Object ID
- argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
- // Change the Current Console object, execute, restore Object
- SimObject *save = gEvalState.thisObject;
- gEvalState.thisObject = pBehavior;
- pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
- gEvalState.thisObject = save;
- }
- }
- // Pass this up to the parent since a BehaviorComponent is still a DynamicConsoleMethodComponent
- // it needs to be able to contain other components and behave properly
- const char* fnRet = Parent::_callMethod( argc, argv, callThis );
- // Clean up.
- FrameAllocator::setWaterMark( strdupWatermark );
- return fnRet;
- }
- //-----------------------------------------------------------------------------
- void BehaviorComponent::onTamlCustomWrite( TamlCustomNodes& customNodes )
- {
- // Call parent.
- Parent::onTamlCustomWrite( customNodes );
- // Fetch behavior count.
- const U32 behaviorCount = (U32)mBehaviors.size();
- // Finish if no behaviors.
- if( behaviorCount == 0 )
- return;
- // Fetch behavior template asset field type.
- StringTableEntry behaviorTemplateAssetFieldType = StringTable->insert( behaviorTemplateAssetName );
- // Add custom behaviors node.
- TamlCustomNode* pCustomBehaviorNode = customNodes.addNode( behaviorNodeName );
- // Iterate behaviors.
- for( SimSet::iterator behaviorItr = mBehaviors.begin(); behaviorItr != mBehaviors.end(); ++behaviorItr )
- {
- // Fetch behavior.
- BehaviorInstance* pBehaviorInstance = dynamic_cast<BehaviorInstance*>( *behaviorItr );
- // Fetch template.
- BehaviorTemplate* pBehaviorTemplate = pBehaviorInstance->getTemplate();
- // Add behavior node.
- TamlCustomNode* pBehaviorNode = pCustomBehaviorNode->addNode( pBehaviorInstance->getTemplateName() );
- // Add behavior Id field.
- pBehaviorNode->addField( behaviorIdFieldName, pBehaviorInstance->getBehaviorId() );
- // Fetch field count,
- const U32 behaviorFieldCount = pBehaviorTemplate->getBehaviorFieldCount();
- // Write out the fields which the behavior template knows about.
- for( U32 fieldIndex = 0; fieldIndex < behaviorFieldCount; ++fieldIndex )
- {
- // Fetch field.
- BehaviorTemplate::BehaviorField* pBehaviorField = pBehaviorTemplate->getBehaviorField( fieldIndex );
-
- // Set default field type.
- S32 fieldType = -1;
- // Is this an asset field type?
- if ( pBehaviorField != NULL && pBehaviorField->mType == behaviorTemplateAssetFieldType )
- {
- // Yes, so update field type.
- fieldType = TypeAssetId;
- }
- // Fetch field value.
- const char* pFieldValue = pBehaviorInstance->getPrefixedDynamicDataField( pBehaviorField->mName, NULL, fieldType );
- // Add behavior field.
- pBehaviorNode->addField( pBehaviorField->mName, pFieldValue );
- }
- }
- // Fetch behavior connection count.
- const U32 behaviorConnectionCount = (U32)mBehaviorConnections.size();
- // Finish if no behavior connections.
- if ( behaviorConnectionCount == 0 )
- return;
-
- // Iterate instance connections.
- for( typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.begin(); instanceItr != mBehaviorConnections.end(); ++instanceItr )
- {
- // Fetch output name connection(s).
- typeOutputNameConnectionHash* pOutputNameConnection = instanceItr->value;
- // Iterate output name connections.
- for( typeOutputNameConnectionHash::iterator outputItr = pOutputNameConnection->begin(); outputItr != pOutputNameConnection->end(); ++outputItr )
- {
- // Fetch port connection(s).
- typePortConnectionVector* pPortConnections = outputItr->value;
- // Iterate input connections.
- for( typePortConnectionVector::iterator connectionItr = pPortConnections->begin(); connectionItr != pPortConnections->end(); ++connectionItr )
- {
- // Fetch connection.
- BehaviorPortConnection* pConnection = connectionItr;
- // Add connectionnode.
- TamlCustomNode* pConnectionNode = pCustomBehaviorNode->addNode( behaviorConnectionTypeName );
- // Add behavior field.
- pConnectionNode->addField( pConnection->mOutputName, pConnection->mOutputInstance->getBehaviorId() );
- pConnectionNode->addField( pConnection->mInputName, pConnection->mInputInstance->getBehaviorId() );
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- void BehaviorComponent::onTamlCustomRead( const TamlCustomNodes& customNodes )
- {
- // Call parent.
- Parent::onTamlCustomRead( customNodes );
- // Find custom behaviors node.
- const TamlCustomNode* pCustomBehaviorNode = customNodes.findNode( behaviorNodeName );
- // Do we have the property?
- if ( pCustomBehaviorNode != NULL )
- {
- // Yes, so reset maximum behavior Id.
- S32 maximumBehaviorId = 0;
- // Fetch behavior Id field name.
- StringTableEntry behaviorFieldIdName = StringTable->insert( behaviorIdFieldName );
- // Fetch behavior template asset field type.
- StringTableEntry behaviorTemplateAssetFieldType = StringTable->insert( behaviorTemplateAssetName );
- // Fetch children behavior nodes.
- const TamlCustomNodeVector& behaviorNodes = pCustomBehaviorNode->getChildren();
- // Iterate behavior nodes.
- for( TamlCustomNodeVector::const_iterator behaviorNodeItr = behaviorNodes.begin(); behaviorNodeItr != behaviorNodes.end(); ++behaviorNodeItr )
- {
- // Fetch behavior node.
- TamlCustomNode* pBehaviorNode = *behaviorNodeItr;
- if ( pBehaviorNode->getNodeName() == behaviorConnectionTypeName )
- {
- // Fetch field nodes.
- const TamlCustomFieldVector& connectionFieldNodes = pBehaviorNode->getFields();
- // Are there two properties?
- if ( connectionFieldNodes.size() != 2 )
- {
- // No, so warn.
- Con::warnf( "BehaviorComponent::onTamlCustomRead() - Encountered a behavior connection with more than two connection fields." );
- continue;
- }
- // Fetch property field #1.
- TamlCustomField* pPropertyField1 = *connectionFieldNodes.begin();
- TamlCustomField* pPropertyField2 = *(connectionFieldNodes.begin()+1);
-
- // Fetch behavior instances #1.
- BehaviorInstance* pBehaviorInstance1 = getBehaviorByInstanceId( dAtoi( pPropertyField1->getFieldValue() ) );
- // Did we find the behavior?
- if ( pBehaviorInstance1 == NULL )
- {
- // No, so warn.
- Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior instance Id '%s=%s'.",
- pPropertyField1->getFieldName(), pPropertyField1->getFieldValue() );
- continue;
- }
- // Fetch behavior instances #2.
- BehaviorInstance* pBehaviorInstance2 = getBehaviorByInstanceId( dAtoi( pPropertyField2->getFieldValue() ) );
- // Did we find the behavior?
- if ( pBehaviorInstance2 == NULL )
- {
- // No, so warn.
- Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior instance Id '%s=%s'.",
- pPropertyField2->getFieldName(), pPropertyField2->getFieldValue() );
- continue;
- }
- // Fetch behavior fields.
- StringTableEntry behaviorFieldName1 = pPropertyField1->getFieldName();
- StringTableEntry behaviorFieldName2 = pPropertyField2->getFieldName();
- BehaviorInstance* pOutputInstance;
- BehaviorInstance* pInputInstance;
- StringTableEntry outputName;
- StringTableEntry inputName;
- // Is the output on behavior instance #1?
- if ( pBehaviorInstance1->getTemplate()->hasBehaviorOutput( behaviorFieldName1 ) )
- {
- // Yes, so has behavior instance #2 got the input?
- if ( !pBehaviorInstance2->getTemplate()->hasBehaviorInput( behaviorFieldName2 ) )
- {
- // No, so warn.
- Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior input '%s' on behavior '%s'.",
- behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
- continue;
- }
- // Assign output/input appropriately.
- pOutputInstance = pBehaviorInstance1;
- pInputInstance = pBehaviorInstance2;
- outputName = behaviorFieldName1;
- inputName = behaviorFieldName2;
- }
- // Is the output on behavior instance #2?
- else if ( pBehaviorInstance2->getTemplate()->hasBehaviorOutput( behaviorFieldName2 ) )
- {
- // Yes, so has behavior instance #1 got the input?
- if ( !pBehaviorInstance1->getTemplate()->hasBehaviorInput( behaviorFieldName1 ) )
- {
- // No, so warn.
- Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior input '%s' on behavior '%s'.",
- behaviorFieldName1, pBehaviorInstance1->getTemplateName() );
- continue;
- }
- // Assign output/input appropriately.
- pOutputInstance = pBehaviorInstance2;
- pInputInstance = pBehaviorInstance1;
- outputName = behaviorFieldName2;
- inputName = behaviorFieldName1;
- }
- else
- {
- // Warn.
- Con::warnf( "BehaviorComponent::onTamlCustomRead() - Invalid output/input on behavior connection '%s=%s' & '%s=%s''.",
- behaviorFieldName1, pBehaviorInstance1->getTemplateName(),
- behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
- continue;
- }
- // Can we connect?
- if ( !connect( pOutputInstance, pInputInstance, outputName, inputName ) )
- {
- // No, so warn.
- Con::warnf( "BehaviorComponent::onTamlCustomRead() - Failed to connect behaviors '%s=%s' & '%s=%s''.",
- behaviorFieldName1, pBehaviorInstance1->getTemplateName(),
- behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
- continue;
- }
- }
- else
- {
- // Fetch template.
- BehaviorTemplate* pTemplate = dynamic_cast<BehaviorTemplate *>( Sim::findObject( pBehaviorNode->getNodeName() ) );
- // Find template?
- if( pTemplate == NULL )
- {
- // No, so warn appropriately.
- Con::warnf( "BehaviorComponent::onTamlCustomRead() - Missing Behavior '%s'", pBehaviorNode->getNodeName() );
- if( isMethod( "onBehaviorMissing" ) )
- Con::executef( this, 2, "onBehaviorMissing", pBehaviorNode->getNodeName() );
- // Skip it.
- continue;
- }
- // Create an instance of the template.
- BehaviorInstance* pBehaviorInstance = pTemplate->createInstance();
- // Did we create a behavior instance?
- if ( pBehaviorInstance == NULL )
- {
- // No, so warn appropriately.
- Con::warnf( "BehaviorComponent::onTamlCustomRead() - Found behavior could not create an instance '%s'", pBehaviorNode->getNodeName() );
- if( isMethod( "onBehaviorMissing" ) )
- Con::executef( this, 2, "onBehaviorMissing", pBehaviorNode->getNodeName() );
- // Skip it.
- continue;
- }
- S32 behaviorId = 0;
- // Fetch field nodes.
- const TamlCustomFieldVector& fields = pBehaviorNode->getFields();
- // Iterate fields.
- for ( TamlCustomFieldVector::const_iterator nodeFieldItr = fields.begin(); nodeFieldItr != fields.end(); ++nodeFieldItr )
- {
- // Fetch field.
- TamlCustomField* pField = *nodeFieldItr;
- // Fetch field name.
- const char* pFieldName = pField->getFieldName();
- // Fetch field value.
- const char* pFieldValue = pField->getFieldValue();
- // Is this the behavior field Id name?
- if ( pFieldName == behaviorFieldIdName )
- {
- // Yes, so assign it.
- behaviorId = dAtoi( pFieldValue );
- // Is the behavior Id valid?
- if ( behaviorId < 1 )
- {
- // No, so warn.
- Con::warnf( "BehaviorComponent::onTamlCustomRead() - Encountered an invalid behavior Id of '%d' on behavior '%s'.",
- behaviorId,
- pBehaviorNode->getNodeName() );
- }
- // Update maximum behavior Id found.
- if ( behaviorId > maximumBehaviorId )
- maximumBehaviorId = behaviorId;
- /// Skip it.
- continue;
- }
- // Fetch behavior field.
- BehaviorTemplate::BehaviorField* pBehaviorField = pTemplate->getBehaviorField( pFieldName );
- // Set default field type.
- S32 fieldType = -1;
- // Is this an asset field type?
- if ( pBehaviorField != NULL && pBehaviorField->mType == behaviorTemplateAssetFieldType )
- {
- // Yes, so update field type.
- fieldType = TypeAssetId;
- }
- // Set field.
- pBehaviorInstance->setPrefixedDynamicDataField( pField->getFieldName(), NULL, pField->getFieldValue(), fieldType );
- }
- // Add behavior.
- addBehavior( pBehaviorInstance );
- // Override the automatically allocated behavior Id if the Id field is already defined in the TAML file.
- // NOTE: This must be done after adding the behavior.
- if (behaviorId != 0)
- {
- pBehaviorInstance->setBehaviorId( behaviorId );
- }
- }
- }
- // Set master as next behavior id.
- mMasterBehaviorId = (U32)maximumBehaviorId+1;
- }
- }
- //-----------------------------------------------------------------------------
- static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
- {
- // Sanity!
- AssertFatal( pClassRep != NULL, "BehaviorComponent::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
- AssertFatal( pParentElement != NULL, "BehaviorComponent::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
- // Write an unrestricted custom Taml schema.
- Taml::WriteUnrestrictedCustomTamlSchema( behaviorNodeName, pClassRep, pParentElement );
- }
- //-----------------------------------------------------------------------------
- IMPLEMENT_CONOBJECT_SCHEMA( BehaviorComponent, WriteCustomTamlSchema );
|