You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
514 lines
16 KiB
514 lines
16 KiB
/*==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 <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
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==*/ |
|
#include "plKeyFinder.h" |
|
|
|
#include "hsTemplates.h" |
|
#include "hsStlUtils.h" |
|
|
|
#include "hsResMgr.h" |
|
#include "plResManager.h" |
|
|
|
#include "plRegistryHelpers.h" |
|
#include "plRegistryNode.h" |
|
#include "plRegistryKeyList.h" |
|
#include "plPageInfo.h" |
|
#include "pnFactory/plFactory.h" |
|
#include "hsUtils.h" |
|
#include "plCreatableIndex.h" |
|
|
|
plResManager* IGetResMgr() { return (plResManager*)hsgResMgr::ResMgr(); } |
|
|
|
plKeyFinder& plKeyFinder::Instance() |
|
{ |
|
static plKeyFinder theInstance; |
|
return theInstance; |
|
} |
|
|
|
const char* plKeyFinder::GetLastErrorString() // For Console display |
|
{ |
|
// For Console display |
|
static const char* KeyFinderErrors[] = |
|
{ |
|
"Ok", |
|
"Age not found", |
|
"Page not found", |
|
"Invalid class", |
|
"None of those classes in this page", |
|
"Object not found" |
|
}; |
|
return KeyFinderErrors[fLastError]; |
|
} |
|
|
|
// |
|
// Does name string compare with potentially mangled (ie. [1 0 0]foo) names |
|
// |
|
hsBool NameMatches(const char* obName, const char* pKName, hsBool subString) |
|
{ |
|
if (!obName || !pKName) |
|
return false; |
|
|
|
const char *o = obName; |
|
const char *p = pKName; |
|
|
|
// If names are mangled, unmangle |
|
if (*o != '[' || *p != '[') |
|
{ |
|
// skip past ']' in both names in case mangled |
|
while (*o && *o != ']') |
|
o++; |
|
o = (*o==']') ? o+1 : obName; |
|
|
|
while (*p && *p != ']') |
|
p++; |
|
p = (*p==']') ? p+1 : pKName; |
|
} |
|
|
|
if (!subString) |
|
{ |
|
if (!stricmp(o, p)) |
|
return true; // FOUND IT!!!!!!!!!!!!!!!!!!! |
|
} |
|
else |
|
{ |
|
char oCopy[256], pCopy[256]; |
|
strcpy(oCopy, o); |
|
strcpy(pCopy, p); |
|
hsStrLower(oCopy); |
|
hsStrLower(pCopy); |
|
if (strstr(pCopy, oCopy)) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
plKey plKeyFinder::StupidSearch(const char * age, const char * rm, |
|
const char *className, const char *obName, hsBool subString) |
|
{ |
|
UInt16 ty = plFactory::FindClassIndex(className); |
|
return StupidSearch(age, rm, ty, obName, subString); |
|
} |
|
|
|
class plKeyFinderIter : public plRegistryKeyIterator, public plRegistryPageIterator |
|
{ |
|
protected: |
|
UInt16 fClassType; |
|
const char *fObjName; |
|
hsBool fSubstr; |
|
plKey fFoundKey; |
|
const char *fAgeName; |
|
|
|
public: |
|
plKey GetFoundKey( void ) const { return fFoundKey; } |
|
|
|
plKeyFinderIter( UInt16 classType, const char *obName, hsBool substr ) |
|
: fFoundKey( nil ), fClassType( classType ), fObjName( obName ), fSubstr( substr ) { } |
|
|
|
plKeyFinderIter( UInt16 classType, const char *obName, hsBool substr, const char *ageName ) |
|
: fFoundKey( nil ), fClassType( classType ), fObjName( obName ), fSubstr( substr ), |
|
fAgeName( ageName ) {} |
|
|
|
virtual hsBool EatKey( const plKey& key ) |
|
{ |
|
if( key->GetUoid().GetClassType() == fClassType && |
|
NameMatches( fObjName, key->GetUoid().GetObjectName(), fSubstr ) ) |
|
{ |
|
fFoundKey = key; |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
virtual hsBool EatPage( plRegistryPageNode *pageNode ) |
|
{ |
|
#ifndef _DEBUG |
|
try |
|
{ |
|
#endif |
|
if( stricmp( pageNode->GetPageInfo().GetAge(), fAgeName ) == 0 ) |
|
{ |
|
// Try loading and searching thru this page |
|
hsTArray<plKey> keyRefs; |
|
|
|
IGetResMgr()->LoadPageKeys( pageNode ); |
|
plKeyCollector coll( keyRefs ); |
|
pageNode->IterateKeys( &coll ); |
|
|
|
if( !pageNode->IterateKeys( this ) ) |
|
return false; |
|
} |
|
#ifndef _DEBUG |
|
} catch (...) |
|
{ |
|
} |
|
#endif |
|
return true; |
|
} |
|
}; |
|
|
|
plKey plKeyFinder::StupidSearch(const char * age, const char * rm, |
|
UInt16 classType, const char *obName, hsBool subString) |
|
{ |
|
if (!obName) |
|
return nil; |
|
|
|
plUoid newOid; |
|
|
|
fLastError = kOk; |
|
|
|
UInt16 maxClasses = plFactory::GetNumClasses(); |
|
|
|
UInt16 ty = classType; |
|
if (ty == maxClasses) // error |
|
{ fLastError = kInvalidClass; |
|
return nil; |
|
} |
|
|
|
if( age != nil && rm != nil ) |
|
{ |
|
const plLocation &loc = IGetResMgr()->FindLocation( age, rm ); |
|
if( !loc.IsValid() ) |
|
{ |
|
fLastError = kPageNotFound; |
|
return nil; |
|
} |
|
|
|
plKeyFinderIter keyFinder( classType, obName, subString ); |
|
|
|
if( !IGetResMgr()->IterateKeys( &keyFinder, loc ) ) |
|
// Return value of false means it stopped somewhere, i.e. found something |
|
return keyFinder.GetFoundKey(); |
|
} |
|
else if( age != nil ) |
|
{ |
|
plKeyFinderIter keyFinder(classType, obName, subString, age); |
|
|
|
if( !IGetResMgr()->IterateAllPages( &keyFinder ) ) |
|
return keyFinder.GetFoundKey(); |
|
} |
|
else |
|
{ |
|
plKeyFinderIter keyFinder( classType, obName, subString ); |
|
|
|
if( !IGetResMgr()->IterateKeys( &keyFinder ) ) |
|
// Return value of false means it stopped somewhere, i.e. found something |
|
return keyFinder.GetFoundKey(); |
|
} |
|
|
|
fLastError = kObjectNotFound; |
|
return nil; |
|
} |
|
|
|
void plKeyFinder::ReallyStupidResponderSearch(const char *name, std::vector<plKey>& foundKeys, const plLocation &hintLocation ) |
|
{ |
|
ReallyStupidSubstringSearch(name, CLASS_INDEX_SCOPED(plResponderModifier), foundKeys, hintLocation); |
|
} |
|
|
|
void plKeyFinder::ReallyStupidActivatorSearch(const char *name, std::vector<plKey>& foundKeys, const plLocation &hintLocation) |
|
{ |
|
// use the createable macro so we don't have to pull in all of Python |
|
ReallyStupidSubstringSearch(name, CLASS_INDEX_SCOPED(plLogicModifier), foundKeys, hintLocation); |
|
ReallyStupidSubstringSearch(name, CLASS_INDEX_SCOPED(plPythonFileMod), foundKeys, hintLocation); |
|
ReallyStupidSubstringSearch(name, CLASS_INDEX_SCOPED(plSittingModifier), foundKeys, hintLocation); |
|
} |
|
|
|
void plKeyFinder::IGetNames(std::vector<std::string>& names, const char* searchName, int index) |
|
{ |
|
// Not really searching for any particular key, just need all the logic mods |
|
std::vector<plKey> keys; |
|
ReallyStupidSubstringSearch(searchName, index, keys); |
|
|
|
for (int i = 0; i < keys.size(); i++) |
|
{ |
|
// Only allow loaded ones to cut down on the crap |
|
plKey key = keys[i]; |
|
if (key->ObjectIsLoaded()) |
|
names.push_back(key->GetName()); |
|
} |
|
} |
|
|
|
void plKeyFinder::GetResponderNames(std::vector<std::string>& names) |
|
{ |
|
IGetNames(names, "", CLASS_INDEX_SCOPED(plResponderModifier)); |
|
} |
|
|
|
void plKeyFinder::GetActivatorNames(std::vector<std::string>& names) |
|
{ |
|
IGetNames(names, "", CLASS_INDEX_SCOPED(plLogicModifier)); |
|
} |
|
|
|
class plKeyFinderIterator : public plRegistryKeyIterator, public plRegistryPageIterator |
|
{ |
|
protected: |
|
|
|
UInt16 fClassType; |
|
const char *fObjName; |
|
|
|
std::vector<plKey> &fFoundKeys; |
|
|
|
public: |
|
|
|
plKeyFinderIterator( UInt16 classType, const char *obName, std::vector<plKey>& foundKeys ) |
|
: fClassType( classType ), fObjName( obName ), fFoundKeys( foundKeys ) { } |
|
|
|
virtual hsBool EatKey( const plKey& key ) |
|
{ |
|
if( key->GetUoid().IsValid() && key->GetUoid().GetClassType() == fClassType && |
|
strstr( key->GetUoid().GetObjectName(), fObjName ) ) |
|
{ |
|
fFoundKeys.push_back( key ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
virtual hsBool EatPage( plRegistryPageNode *page ) |
|
{ |
|
hsBool ret = page->IterateKeys( this ); |
|
return ret; |
|
} |
|
}; |
|
|
|
void plKeyFinder::ReallyStupidSubstringSearch(const char *name, UInt16 objType, std::vector<plKey>& foundKeys, const plLocation &hintLocation ) |
|
{ |
|
if (!name) |
|
return; |
|
|
|
plKeyFinderIterator collector( objType, name, foundKeys ); |
|
if( hintLocation.IsValid() ) |
|
{ |
|
plRegistryPageNode *hintPage = IGetResMgr()->FindPage( hintLocation ); |
|
if( hintPage != nil ) |
|
{ |
|
// Try all pages in the same age as that page |
|
IGetResMgr()->IteratePages( &collector, hintPage->GetPageInfo().GetAge() ); |
|
} |
|
|
|
if (foundKeys.size() > 0) |
|
{ |
|
return; |
|
} |
|
} |
|
|
|
//fpReg->IterateKeys( &collector ); |
|
IGetResMgr()->IterateAllPages( &collector ); |
|
} |
|
|
|
//// Helper Class for FindSceneNodeKey /////////////////////////////////////// |
|
|
|
class plPageFinder : public plRegistryPageIterator |
|
{ |
|
protected: |
|
|
|
plRegistryPageNode **fPagePtr; |
|
const char *fFindString, *fAgeString; |
|
|
|
public: |
|
|
|
plPageFinder( plRegistryPageNode **page, const char *find ) : fPagePtr( page ), fFindString( find ), fAgeString( nil ) |
|
{ *fPagePtr = nil; } |
|
|
|
plPageFinder( plRegistryPageNode **page, const char *ageS, const char *pageS ) : fPagePtr( page ), fFindString( pageS ), fAgeString( ageS ) |
|
{ *fPagePtr = nil; } |
|
|
|
virtual hsBool EatPage( plRegistryPageNode *node ) |
|
{ |
|
static char str[ 512 ]; |
|
const plPageInfo &info = node->GetPageInfo(); |
|
|
|
// Are we searching by age/page? |
|
if( fAgeString != nil ) |
|
{ |
|
if( stricmp( info.GetAge(), fAgeString ) == 0 && |
|
stricmp( info.GetPage(), fFindString ) == 0 ) |
|
{ |
|
*fPagePtr = node; |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
// Try for page only |
|
if( stricmp( info.GetPage(), fFindString ) == 0 ) |
|
{ |
|
*fPagePtr = node; |
|
return false; |
|
} |
|
|
|
// Try for full location |
|
sprintf( str, "%s_%s_%s", info.GetAge(), info.GetPage() ); |
|
if( stricmp( str, fFindString ) == 0 ) |
|
{ |
|
*fPagePtr = node; |
|
return false; |
|
} |
|
|
|
return true; // Keep searching |
|
} |
|
}; |
|
|
|
//// FindSceneNodeKey //////////////////////////////////////////////////////// |
|
// Given a string for either a page name or a fully qualified location name, |
|
// finds the page and then returns the key for the sceneNode in that page. |
|
// Note: in our case, we want to force the page's keys to load if necessary, |
|
// since the only time we call this function will be to actually load |
|
// the darned thing. |
|
|
|
plKey plKeyFinder::FindSceneNodeKey( const char *pageOrFullLocName ) const |
|
{ |
|
plRegistryPageNode *pageNode; |
|
plPageFinder pageFinder( &pageNode, pageOrFullLocName ); |
|
|
|
|
|
// Use our own page finder, since we want to do nifty things like partial |
|
// matches, etc. |
|
if( IGetResMgr()->IterateAllPages( &pageFinder ) || pageNode == nil ) |
|
return nil; |
|
|
|
return IFindSceneNodeKey( pageNode ); |
|
} |
|
|
|
//// FindSceneNodeKey //////////////////////////////////////////////////////// |
|
// Age/page pair version |
|
|
|
plKey plKeyFinder::FindSceneNodeKey( const char *ageName, const char *pageName ) const |
|
{ |
|
plRegistryPageNode *pageNode; |
|
plPageFinder pageFinder( &pageNode, ageName, pageName ); |
|
|
|
// Use our own page finder, since we want to do nifty things like partial |
|
// matches, etc. |
|
if (IGetResMgr()->IterateAllPages(&pageFinder) || pageNode == nil) |
|
return nil; |
|
|
|
return IFindSceneNodeKey( pageNode ); |
|
} |
|
|
|
//// FindSceneNodeKey //////////////////////////////////////////////////////// |
|
// plLocation version |
|
|
|
plKey plKeyFinder::FindSceneNodeKey(const plLocation& location) const |
|
{ |
|
plRegistryPageNode* pageNode = IGetResMgr()->FindPage(location); |
|
if (pageNode == nil) |
|
return nil; |
|
|
|
return IFindSceneNodeKey(pageNode); |
|
} |
|
|
|
//// IFindSceneNodeKey /////////////////////////////////////////////////////// |
|
|
|
|
|
plKey plKeyFinder::IFindSceneNodeKey(plRegistryPageNode* page) const |
|
{ |
|
// Got the pageNode, try a find before loading |
|
plRegistryKeyList* keyList = page->IGetKeyList(CLASS_INDEX_SCOPED(plSceneNode)); |
|
if (keyList) |
|
{ |
|
if (keyList->fStaticKeys.size() == 1) |
|
{ |
|
return plKey::Make((plKeyData*)keyList->fStaticKeys[0]); |
|
} |
|
else if (keyList->fDynamicKeys.size() == 1) // happens during export |
|
{ |
|
plRegistryKeyList::DynSet::const_iterator it = keyList->fDynamicKeys.begin(); |
|
plKeyImp* keyImp = *it; |
|
return plKey::Make(keyImp); |
|
} |
|
} |
|
|
|
// Try loading and see if that helps |
|
if (page->IsFullyLoaded()) |
|
return nil; |
|
|
|
IGetResMgr()->LoadPageKeys(page); |
|
|
|
// Get the list of all sceneNodes |
|
plKey retVal(nil); |
|
keyList = page->IGetKeyList(CLASS_INDEX_SCOPED(plSceneNode)); |
|
if (keyList && keyList->fStaticKeys.size() == 1) |
|
{ |
|
retVal = plKey::Make((plKeyData*)keyList->fStaticKeys[0]); |
|
} |
|
// If we just loaded up all the keys for this page, then we |
|
// may have a bunch of keys with a refcount of 0. For any of |
|
// these keys that nothing else refs (yes, we have unused objects |
|
// in the data), they don't get deleted because the refcount never |
|
// rises above zero or falls back to zero. So we'll go ahead and |
|
// ref and unref all of them. The ones in use stay put, the ones |
|
// not being used go away. This is less than ideal. |
|
IGetResMgr()->DumpUnusedKeys(page); |
|
|
|
return retVal; |
|
} |
|
|
|
//// FindLocation //////////////////////////////////////////////////////////// |
|
|
|
const plLocation &plKeyFinder::FindLocation( const char *age, const char *page ) const |
|
{ |
|
if (age == nil) |
|
{ |
|
static plLocation invalidLoc; |
|
plRegistryPageNode *pageNode; |
|
plPageFinder pageFinder( &pageNode, page ); |
|
|
|
if( IGetResMgr()->IterateAllPages( &pageFinder ) || pageNode == nil ) |
|
return invalidLoc; |
|
|
|
return pageNode->GetPageInfo().GetLocation(); |
|
} |
|
|
|
return IGetResMgr()->FindLocation( age, page ); |
|
} |
|
|
|
//// GetLocationInfo ///////////////////////////////////////////////////////// |
|
|
|
const plPageInfo* plKeyFinder::GetLocationInfo( const plLocation &loc ) const |
|
{ |
|
plRegistryPageNode *node = IGetResMgr()->FindPage( loc ); |
|
if (node) |
|
return &node->GetPageInfo(); |
|
else |
|
return nil; |
|
} |
|
|
|
|