//----------------------------------------------------------------------------- // 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 "platform/platform.h" #include "sim/simBase.h" #include "console/consoleTypes.h" #include "component/simComponent.h" #include "io/stream.h" #include "behaviors/behaviorTemplate.h" SimComponent::SimComponent() : mOwner( NULL ) { mComponentList.clear(); mMutex = Mutex::createMutex(); mEnabled = true; } SimComponent::~SimComponent() { Mutex::destroyMutex( mMutex ); mMutex = NULL; } IMPLEMENT_CONOBJECT(SimComponent); bool SimComponent::onAdd() { if( !Parent::onAdd() ) return false; if( !_registerComponents( this ) ) return false; return true; } bool SimComponent::_registerComponents( SimComponent *owner ) { // This method will return true if the object contains no components. See the // documentation for SimComponent::onComponentRegister for more information // on this behavior. bool ret = true; // If this doesn't contain components, don't even lock the list. if( hasComponents() ) { VectorPtr &components = lockComponentList(); for( SimComponentIterator i = components.begin(); i != components.end(); i++ ) { if( !(*i)->onComponentRegister( owner ) ) { ret = false; break; } AssertFatal( (*i)->mOwner == owner, "Component failed to call parent onComponentRegister!" ); // Recurse if( !(*i)->_registerComponents( owner ) ) { ret = false; break; } } unlockComponentList(); } return ret; } void SimComponent::_unregisterComponents() { if( !hasComponents() ) return; VectorPtr &components = lockComponentList(); for( SimComponentIterator i = components.begin(); i != components.end(); i++ ) { (*i)->onComponentUnRegister(); AssertFatal( (*i)->mOwner == NULL, "Component failed to call parent onUnRegister" ); // Recurse (*i)->_unregisterComponents(); } unlockComponentList(); } void SimComponent::onRemove() { _unregisterComponents(); // Delete all components VectorPtr&componentList = lockComponentList(); while(componentList.size() > 0) { SimComponent *c = componentList[0]; componentList.erase( componentList.begin() ); if( c->isProperlyAdded() ) c->deleteObject(); else if( !c->isRemoved() && !c->isDeleted() ) delete c; // else, something else is deleting this, don't mess with it } unlockComponentList(); Parent::onRemove(); } ////////////////////////////////////////////////////////////////////////// bool SimComponent::processArguments(S32 argc, const char **argv) { for(S32 i = 0; i < argc; i++) { SimComponent *obj = dynamic_cast (Sim::findObject(argv[i]) ); if(obj) addComponent(obj); else Con::printf("SimComponent::processArguments - Invalid Component Object \"%s\"", argv[i]); } return true; } ////////////////////////////////////////////////////////////////////////// void SimComponent::initPersistFields() { addProtectedField( "Enabled", TypeBool, Offset(mEnabled, SimComponent), &setEnabled, &defaultProtectedGetFn, &writeEnabled, "" ); Parent::initPersistFields(); } // Add Component to this one bool SimComponent::addComponent( SimComponent *component ) { AssertFatal( dynamic_cast(component), "SimComponent - Cannot add non SimObject derived components!" ); MutexHandle mh; if( mh.lock( mMutex, true ) ) { for( SimComponentIterator nItr = mComponentList.begin(); nItr != mComponentList.end(); nItr++ ) { SimComponent *pComponent = dynamic_cast(*nItr); AssertFatal( pComponent, "SimComponent::addComponent - NULL component in list!" ); if( pComponent == component ) return true; } if(component->onComponentAdd(this)) { component->mOwner = this; mComponentList.push_back( component ); return true; } } return false; } // Remove Component from this one bool SimComponent::removeComponent( SimComponent *component ) { MutexHandle mh; if( mh.lock( mMutex, true ) ) { for( SimComponentIterator nItr = mComponentList.begin(); nItr != mComponentList.end(); nItr++ ) { SimComponent *pComponent = dynamic_cast(*nItr); AssertFatal( pComponent, "SimComponent::removeComponent - NULL component in list!" ); if( pComponent == component ) { AssertFatal( component->mOwner == this, "Somehow we contain a component who doesn't think we are it's owner." ); (*nItr)->onComponentRemove(this); component->mOwner = NULL; mComponentList.erase( nItr ); return true; } } } return false; } ////////////////////////////////////////////////////////////////////////// bool SimComponent::onComponentAdd(SimComponent *target) { Con::executef(this, 2, "onComponentAdd", Con::getIntArg(target->getId())); return true; } void SimComponent::onComponentRemove(SimComponent *target) { Con::executef(this, 2, "onComponentRemove", Con::getIntArg(target->getId())); } ////////////////////////////////////////////////////////////////////////// bool SimComponent::writeField(StringTableEntry fieldname, const char* value) { if (!Parent::writeField(fieldname, value)) return false; if( fieldname == StringTable->insert("owner") ) return false; return true; } void SimComponent::write(Stream &stream, U32 tabStop, U32 flags /* = 0 */) { #if 1 Parent::write( stream, tabStop, flags ); #else MutexHandle handle; handle.lock(mMutex); // When this goes out of scope, it will unlock it // export selected only? if((flags & SelectedOnly) && !isSelected()) { for(U32 i = 0; i < mComponentList.size(); i++) mComponentList[i]->write(stream, tabStop, flags); return; } stream.writeTabs(tabStop); char buffer[1024]; dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() ? getName() : ""); stream.write(dStrlen(buffer), buffer); writeFields(stream, tabStop + 1); if(mComponentList.size()) { stream.write(2, "\r\n"); stream.writeTabs(tabStop+1); stream.writeLine((U8 *)"// Note: This is a list of behaviors, not arbitrary SimObjects as in a SimGroup or SimSet.\r\n"); for(U32 i = 0; i < mComponentList.size(); i++) mComponentList[i]->write(stream, tabStop + 1, flags); } stream.writeTabs(tabStop); stream.write(4, "};\r\n"); #endif } ////////////////////////////////////////////////////////////////////////// bool SimComponent::callMethodOnComponents( U32 argc, const char* argv[], const char** result ) { const char *cbName = StringTable->insert(argv[0]); if (isEnabled()) { if(isMethod(cbName)) { // This component can handle the given method *result = Con::execute( this, argc, argv, true ); return true; } else if( getComponentCount() > 0 ) { // Need to try the component's children bool handled = false; VectorPtr&componentList = lockComponentList(); for( SimComponentIterator nItr = (componentList.end()-1); nItr >= componentList.begin(); nItr-- ) { argv[0] = cbName; SimComponent *pComponent = (*nItr); AssertFatal( pComponent, "SimComponent::callMethodOnComponents - NULL component in list!" ); // Call on children handled = pComponent->callMethodOnComponents( argc, argv, result ); if (handled) break; } unlockComponentList(); if (handled) return true; } } return false; } ////////////////////////////////////////////////////////////////////////// // Console Methods ////////////////////////////////////////////////////////////////////////// ConsoleMethod( SimComponent, addComponents, bool, 3, 64, "%obj.addComponents( %compObjName, %compObjName2, ... );\n" "Adds additional components to current list.\n" "@param Up to 62 component names\n" "@return Returns true on success, false otherwise.") { for(S32 i = 2; i < argc; i++) { SimComponent *obj = dynamic_cast (Sim::findObject(argv[i]) ); if(obj) object->addComponent(obj); else Con::printf("SimComponent::addComponents - Invalid Component Object \"%s\"", argv[i]); } return true; } ConsoleMethod( SimComponent, removeComponents, bool, 3, 64, "%obj.removeComponents( %compObjName, %compObjName2, ... );\n" "Removes components by name from current list.\n" "@param objNamex Up to 62 component names\n" "@return Returns true on success, false otherwise.") { for(S32 i = 2; i < argc; i++) { SimComponent *obj = dynamic_cast (Sim::findObject(argv[i]) ); if(obj) object->removeComponent(obj); else Con::printf("SimComponent::removeComponents - Invalid Component Object \"%s\"", argv[i]); } return true; } ConsoleMethod( SimComponent, getComponentCount, S32, 2, 2, "() Get the current component count\n" "@return The number of components in the list as an integer") { return object->getComponentCount(); } ConsoleMethod( SimComponent, getComponent, S32, 3, 3, "(idx) Get the component corresponding to the given index.\n" "@param idx An integer index value corresponding to the desired component.\n" "@return The id of the component at the given index as an integer") { S32 idx = dAtoi(argv[2]); if(idx < 0 || idx >= (S32)object->getComponentCount()) { Con::errorf("SimComponent::getComponent - Invalid index %d", idx); return 0; } SimComponent *c = object->getComponent(idx); return c ? c->getId() : 0; } ConsoleMethod(SimComponent, setEnabled, void, 3, 3, "(enabled) Sets or unsets the enabled flag\n" "@param enabled Boolean value\n" "@return No return value") { object->setEnabled(dAtob(argv[2])); } ConsoleMethod(SimComponent, isEnabled, bool, 2, 2, "() Check whether SimComponent is currently enabled\n" "@return true if enabled and false if not") { return object->isEnabled(); }