/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #define PLFACTORY_PRIVATE #include "hsTypes.h" #include "plFactory.h" #include "hsStream.h" #include "plCreatable.h" #include "plCreator.h" #include "hsUtils.h" // For class names #include "../NucleusLib/inc/plCreatableStrings.h" static plFactory* theFactory = nil; plFactory::plFactory() { fCreators.SetCountAndZero(plCreatableIndex::plNumClassIndices); } plFactory::~plFactory() { } hsBool plFactory::ICreateTheFactory() { if( theFactory ) return true; theFactory = TRACKED_NEW plFactory; return theFactory != nil; } UInt16 plFactory::IGetNumClasses() { return plCreatableIndex::plNumClassIndices; } void plFactory::IForceShutdown() { int i; for( i = 0; i < fCreators.GetCount(); i++ ) { if( fCreators[i] ) { hsRefCnt_SafeUnRef(this); fCreators[i] = nil; } } } void plFactory::IShutdown() { delete theFactory; theFactory = nil; } UInt16 plFactory::IRegister(UInt16 hClass, plCreator* worker) { delete fCreators[hClass]; fCreators[hClass] = worker; return hClass; } // // return true if creator exists // bool plFactory::CanCreate(UInt16 hClass) { if( hClass & 0x8000 ) // nil creatable return false; if( !theFactory && !ICreateTheFactory() ) // no factory return false; if( hClass >= theFactory->IGetNumClasses() ) // invalid index return false; return ( theFactory->fCreators[ hClass ] != nil ); // check creator } plCreatable* plFactory::ICreate(UInt16 hClass) { if (CanCreate(hClass)) { return fCreators[hClass]->Create(); } if (!(hClass & 0x8000)) { hsAssert( false, "Invalid class index or nil creator : plFactory::Create()" ); } return nil; } void plFactory::UnRegister(UInt16 hClass, plCreator* worker) { if( theFactory ) { theFactory->IUnRegister(hClass); hsRefCnt_SafeUnRef(theFactory); if( theFactory->RefCnt() < 2 ) IShutdown(); } } void plFactory::IUnRegister(UInt16 hClass) { fCreators[hClass] = nil; } UInt16 plFactory::Register(UInt16 hClass, plCreator* worker) { if( !theFactory && !ICreateTheFactory() ) return nil; hsRefCnt_SafeRef(theFactory); return theFactory->IRegister(hClass, worker); } plCreatable* plFactory::Create(UInt16 hClass) { if( !theFactory && !ICreateTheFactory() ) return nil; return theFactory->ICreate(hClass); } UInt16 plFactory::GetNumClasses() { if( !theFactory && !ICreateTheFactory() ) return 0; return theFactory->IGetNumClasses(); } hsBool plFactory::IDerivesFrom(UInt16 hBase, UInt16 hDer) { if( hDer >= fCreators.GetCount() ) return false; return fCreators[hDer] ? fCreators[hDer]->HasBaseClass(hBase) : false; } hsBool plFactory::DerivesFrom(UInt16 hBase, UInt16 hDer) { if( !theFactory && !ICreateTheFactory() ) return 0; return theFactory->IDerivesFrom(hBase, hDer); } // slow lookup for things like console UInt16 plFactory::FindClassIndex(const char* className) { int numClasses=GetNumClasses(); if (className && theFactory) { int i; for( i = 0; i < theFactory->fCreators.GetCount(); i++ ) { if( theFactory->fCreators[i] && !_stricmp(className, theFactory->fCreators[i]->ClassName()) ) { return theFactory->fCreators[i]->ClassIndex(); } } } return numClasses; // err } hsBool plFactory::IIsValidClassIndex(UInt16 hClass) { return ( hClass < fCreators.GetCount() ); } hsBool plFactory::IsValidClassIndex(UInt16 hClass) { return theFactory->IIsValidClassIndex(hClass); } void plFactory::SetTheFactory(plFactory* fac) { // There are four cases here. // 1) Our factory is nil, and we're being given one to use // Just take it and ref it. // 2) Our factory is non-nil, and we're being given on to use // Ours is bogus, pitch it and use the new one. // 3) Our factory is non-nil, and we're being given a nil one // Means we're being shut down. Unref the old one. If // the refcnt drops to one, we're the last one out, so // go ahead and delete it. // 4) Our factory is nil and the new one is nil // Shouldn't happen, but if it does, just ignore it. if( !theFactory && fac ) { hsRefCnt_SafeAssign(theFactory, fac); } else if( theFactory && fac ) { theFactory->IForceShutdown(); hsRefCnt_SafeAssign(theFactory, fac); } else if( theFactory && !fac ) { hsRefCnt_SafeUnRef(theFactory); if( theFactory->RefCnt() < 2 ) delete theFactory; theFactory = nil; } } plFactory* plFactory::GetTheFactory() { if( !theFactory && !ICreateTheFactory() ) return nil; return theFactory; } // For my own nefarious purposes... hsStatusMessage plCreatableIndex const char *plFactory::GetNameOfClass(UInt16 type) { if( type < GetNumClasses() ) { if( theFactory->fCreators[ type ] ) return theFactory->fCreators[ type ]->ClassName(); static int keyedStringsSize = sizeof(plCreatableStrings::fKeyedStrings)/4; // If we don't have a creator yet, try falling back on plCreatableStrings if( type < KEYED_OBJ_DELINEATOR && type= KEYED_OBJ_DELINEATOR && theFactory->fCreators[iter]) { char Buffer[512]; sprintf(Buffer, "Object %s is a hsKeyedObject, Must appear before 'KEYED_OBJ_DELINEATOR' in plCreatableIndex.h\n",GetNameOfClass(iter)); hsStatusMessage(Buffer); bogus = true; } } else { if(iter < KEYED_OBJ_DELINEATOR && theFactory->fCreators[iter]) { char Buffer[512]; sprintf(Buffer, "Object %s is NOT a hsKeyedObject, Must appear after 'KEYED_OBJ_DELINEATOR' in plCreatableIndex.h\n",GetNameOfClass(iter)); hsStatusMessage(Buffer); bogus = true; } } } hsAssert(!bogus,"The class(s) you just added to plCreatableIndex.h in wrong spot, see output window"); } void plFactory::Validate(UInt16 keyIndex) { theFactory->IValidate(keyIndex); } #endif