12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418 |
- //-----------------------------------------------------------------------------
- // 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"
- //-----------------------------------------------------------------------------
- #define BEHAVIOR_ID_FIELD_NAME "Id"
- #define BEHAVIOR_NODE_NAME "Behaviors"
- #define BEHAVIOR_CONNECTION_TYPE_NAME "Connection"
- //-----------------------------------------------------------------------------
- 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( BEHAVIORTEMPLATE_ASSET_FIELDTYPE );
- // Add custom behaviors node.
- TamlCustomNode* pCustomBehaviorNode = customNodes.addNode( BEHAVIOR_NODE_NAME );
- // 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( BEHAVIOR_ID_FIELD_NAME, 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( BEHAVIOR_CONNECTION_TYPE_NAME );
- // 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( BEHAVIOR_NODE_NAME );
- // 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( BEHAVIOR_ID_FIELD_NAME );
- // Fetch behavior template asset field type.
- StringTableEntry behaviorTemplateAssetFieldType = StringTable->insert( BEHAVIORTEMPLATE_ASSET_FIELDTYPE );
- // 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() == BEHAVIOR_CONNECTION_TYPE_NAME )
- {
- // 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 when adding the behavior.
- // NOTE: This must be done after adding the behavior.
- 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( BEHAVIOR_NODE_NAME, pClassRep, pParentElement );
- }
- //-----------------------------------------------------------------------------
- IMPLEMENT_CONOBJECT_SCHEMA( BehaviorComponent, WriteCustomTamlSchema );
|