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.
 
 
 
 
 

550 lines
13 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/>.
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 "hsTypes.h"
#include "hsConverterUtils.h"
#include "hsResMgr.h"
#include "MaxMain/MaxCompat.h"
#if HS_BUILD_FOR_WIN32
#include <math.h>
#include "hsMaxLayerBase.h"
#include "plInterp/plController.h"
#include "MaxExport/plErrorMsg.h"
#include "UserPropMgr.h"
#include "hsStringTokenizer.h"
//#include "hsDXTDirectXCodec.h"
//#include "hsDXTSoftwareCodec.h"
#include "plGImage/hsCodecManager.h"
///#include "SwitchUtil.h"
#include "hsExceptionStack.h"
#include "hsHashTable.h"
#include "pnKeyedObject/plKey.h"
#include "pnKeyedObject/hsKeyedObject.h"
const char hsConverterUtils::fTagSeps[] = " ,\t\n=:;";
extern UserPropMgr gUserPropMgr;
namespace {
class ObjectInstancedEnumProc : public DependentEnumProc
{
public:
ObjectInstancedEnumProc() : fInstanceCount(0) { }
int proc(ReferenceMaker *rmaker)
{
hsGuardBegin("ObjectInstancedEnumProc::proc");
if (rmaker->SuperClassID()==BASENODE_CLASS_ID)
{
fInstanceCount++;
}
return 0;
hsGuardEnd;
}
Int32 GetInstanceCount() { return fInstanceCount; }
private:
Int32 fInstanceCount;
};
}
hsConverterUtils& hsConverterUtils::Instance()
{
static hsConverterUtils the_instance;
return the_instance;
}
hsConverterUtils::hsConverterUtils() :
fInterface(GetCOREInterface()),
fErrorMsg(nil),
fSuppressMangling(false),
fWarned(0)
{
}
void hsConverterUtils::Init(hsBool save, plErrorMsg *msg)
{
hsGuardBegin("hsConverterUtils::Init");
fErrorMsg = msg;
fSuppressMangling = false;
fWarned = 0;
fSave = save;
hsGuardEnd;
}
TimeValue hsConverterUtils::GetTime(Interface *gi)
{
hsGuardBegin("hsConverterUtils::GetTime");
return ((TimeValue)0);
hsGuardEnd;
// return gi->GetTime();
// return theSceneEnum->time;
}
hsBool hsConverterUtils::IsEnvironHolder(INode *node)
{
hsGuardBegin("hsConverterUtils::IsEnvironHolder");
return (gUserPropMgr.UserPropExists(node, "EnvironMap"));
hsGuardEnd;
}
hsBool hsConverterUtils::AutoStartDynamics(INode *node)
{
hsGuardBegin("hsConverterUtils::AutoStartDynamics");
return (gUserPropMgr.UserPropExists(node,"AutoStart") || gUserPropMgr.UserPropExists(node,"aud"));
hsGuardEnd;
}
hsBool hsConverterUtils::RandomStartDynamics(INode *node)
{
hsGuardBegin("hsConverterUtils::RandomStartDynamics");
return (gUserPropMgr.UserPropExists(node,"RandomStart"));
hsGuardEnd;
}
void hsConverterUtils::StripOffTail(char* path)
{
hsGuardBegin("hsConverterUtils::StripOffTail");
int i = strlen(path)-1;
while(path[i] != '\\')
i--;
path[i+1] = 0;
hsGuardEnd;
}
void hsConverterUtils::StripOffPath(char* fileName)
{
hsGuardBegin("hsConverterUtils::StripOffPath");
char tmp[256];
// Remove preceding path
int i = strlen(fileName)-1;
while(fileName[i] != '\\')
i--;
strcpy(tmp, fileName+i+1);
strcpy(fileName, tmp);
hsGuardEnd;
}
//
// static
//
hsBool hsConverterUtils::IsReservedKeyword(const char* nodeName)
{
hsGuardBegin("hsConverterUtils::IsReservedKeyword");
return (nodeName!=nil &&
( !_stricmp(nodeName, "theplayer")
|| !_stricmp(nodeName, "the_player")
|| !_stricmp(nodeName, "thecamera")
|| !_stricmp(nodeName, "the_camera")
|| !_stricmp(nodeName, "thedetector")
|| !_stricmp(nodeName, "the_detector")
|| !_stricmp(nodeName, "themonitor")
|| !_stricmp(nodeName, "the_monitor")
|| !_stricmp(nodeName, "thedetectorshape")
|| !_stricmp(nodeName, "the_detector_shape")) );
hsGuardEnd;
}
char *hsConverterUtils::MangleReference(char *mangName, const char *nodeName, const char* defRoom)
{
hsGuardBegin("hsConverterUtils::MangleReference");
//hsAssert(nodeName, "No node name in hsConverterUtils::MangleReference.");
if(!nodeName)
{
fErrorMsg->Set(true, "Mangle Reference Error", "No node name in hsConverterUtils::MangleReference.").Show();
fErrorMsg->Set();
return mangName;
}
if (!*nodeName)
return hsStrcpy(mangName, nodeName);
// doesn't want to be mangled
if (('.' == nodeName[0])&&('.' == nodeName[1]))
return hsStrcpy(mangName, nodeName + 2);
// already mangled or reserved
if (strstr(nodeName, "..") || IsReservedKeyword(nodeName))
return hsStrcpy(mangName, nodeName);
INode *node = GetINodeByName(nodeName);
if (!node)
{
// no room so make global
// Default is to make it global, but you can set another default (like same
// room as referencer) with defRoom.
char tempName[256];
sprintf(tempName, "%s..%s", defRoom, nodeName);
return hsStrcpy(mangName, tempName);
}
return MangleReference(mangName, node);
hsGuardEnd;
}
char *hsConverterUtils::MangleReference(char *mangName, INode *node, const char* defRoom)
{
hsGuardBegin("hsConverterUtils::MangleReference");
if (!node)
return nil;
char tempName[256];
char *nodeName = node->GetName();
char *roomName = nil;
TSTR sdata;
hsStringTokenizer toker;
if (gUserPropMgr.GetUserPropString(node, "Rooms", sdata))
{
toker.Reset(sdata, fTagSeps);
roomName = toker.next();
}
if (fSuppressMangling)
{
return hsStrcpy(mangName, nodeName);
}
if (('.' == nodeName[0])&&('.' == nodeName[1]))
hsStrcpy(tempName, nodeName + 2);
else if (!*nodeName
|| strstr(nodeName, "..")
|| IsReservedKeyword(nodeName)
)
hsStrcpy(tempName, nodeName);
else if (roomName && *roomName)
sprintf(tempName, "%s..%s", roomName, nodeName);
else
sprintf(tempName, "%s..%s", defRoom, nodeName);
return hsStrcpy(mangName, tempName);
hsGuardEnd;
}
char *hsConverterUtils::MangleRefWithRoom(char *mangName, const char *nodeName, const char* roomName)
{
hsGuardBegin("hsConverterUtils::MangleRefWithRoom");
//hsAssert(nodeName && roomName, "No node or room name in hsConverterUtils::MangleRefWithRoom.");
if(!(nodeName && roomName))
{
fErrorMsg->Set(true, "Mangle Room Reference Error", "No node or room name in hsConverterUtils::MangleRefWithRoom.").Show();
fErrorMsg->Set();
return mangName;
}
if (!*nodeName)
return hsStrcpy(mangName,nodeName);
// doesn't want to be mangled
if (('.' == nodeName[0])&&('.' == nodeName[1]))
return hsStrcpy(mangName, nodeName + 2);
// already mangled or reserved
if (strstr(nodeName, "..") || IsReservedKeyword(nodeName))
return hsStrcpy(mangName, nodeName);
sprintf(mangName, "%s..%s", roomName, nodeName);
return mangName;
hsGuardEnd;
}
INode* hsConverterUtils::FindINodeFromMangledName(const char* mangName)
{
hsGuardBegin("hsConverterUtils::FindINodeFromMangledName");
if( !(mangName && *mangName) )
return nil;
const char* nodeName = mangName;
char* p;
while( p = strstr((char*)nodeName, "..") )
{
nodeName = p + 2;
}
if( !(nodeName && *nodeName) )
nodeName = mangName;
return GetINodeByName(nodeName);
hsGuardEnd;
}
INode* hsConverterUtils::FindINodeFromKeyedObject(hsKeyedObject* obj)
{
hsGuardBegin("hsConverterUtils::FindINodeFromKeyedObject");
INode* retVal = FindINodeFromMangledName(obj->GetKey()->GetName());
if( retVal )
return (retVal);
/* No more other Keys plasma 2.0
int i;
for( i = 0; i < obj->GetNumOtherKeys(); i++ )
{
retVal = FindINodeFromMangledName(obj->GetOtherKey(i)->GetName());
if( retVal )
return retVal;
}
*/
return nil;
hsGuardEnd;
}
// Uses MangleRef so all mangling happens in one place. Compares the name with a mangled version of it
hsBool hsConverterUtils::IsMangled(const char *name)
{
hsGuardBegin("hsConverterUtils::IsMangled");
char mang[255];
return !strcmp(name,MangleReference(mang,name));
hsGuardEnd;
}
// Undoes the process of mangling. This includes taking a "name" back to "..name"
char *hsConverterUtils::UnMangleReference(char *dest, const char *name)
{
hsGuardBegin("hsConverterUtils::IsMangled");
char *u = strstr((char*)name,"..");
if (u)
{
u+=2;
strcpy(dest,u);
}
else if (!IsMangled(name))
{
strcpy(dest,"..");
strcat(dest,name);
}
else
{
strcpy(dest,name);
}
return dest;
hsGuardEnd;
}
// Similar to UnMangle but doesn't take "name" back to "..name"
char* hsConverterUtils::StripMangledReference(char* dest, const char* name)
{
hsGuardBegin("hsConverterUtils::StripMangledReference");
char *u = strstr((char*)name,"..");
if (u)
{
u+=2;
strcpy(dest,u);
}
else
{
strcpy(dest,name);
}
return dest;
hsGuardEnd;
}
Int32 hsConverterUtils::FindNamedSelSetFromName(const char *name)
{
hsGuardBegin("hsConverterUtils::FindNamedSelSetFromName");
for (Int32 i=0; i<fInterface->GetNumNamedSelSets(); i++)
{
if (!_stricmp(name, fInterface->GetNamedSelSetName(i)))
return (i);
}
return (-1);
hsGuardEnd;
}
hsBool hsConverterUtils::IsInstanced(Object* maxObject)
{
hsGuardBegin("hsConverterUtils::IsInstanced");
if (!maxObject)
{
return false;
}
ObjectInstancedEnumProc instProc;
ENUMDEPENDENTS(maxObject, &instProc);
return (instProc.GetInstanceCount() > 1);
hsGuardEnd;
}
INode* hsConverterUtils::IGetINodeByNameRecur(INode* node, const char* wantName)
{
hsGuardBegin("hsConverterUtils::IGetINodeByNameRecur");
if (!node || !node->GetName())
return nil;
char* nodeName=node->GetName();
if (!_stricmp(nodeName, wantName))
return node;
// Process children
int num = node->NumberOfChildren();
int i;
for(i=0; i<num; i++)
{
INode* ret;
if ((ret=IGetINodeByNameRecur(node->GetChildNode(i), wantName)))
return ret;
}
return nil;
hsGuardEnd;
}
//
// Matches name against node's name, case-insensitive,
//
INode* hsConverterUtils::GetINodeByName(const char* name, hsBool caseSensitive)
{
hsGuardBegin("hsConverterUtils::GetINodeByName");
if (!name)
{
return nil;
}
if (fNodeSearchCache)
{
CacheNode cNode(name);
cNode.SetCaseSensitive(caseSensitive);
hsHashTableIterator<CacheNode> it = fNodeSearchCache->find(cNode);
return it->GetNode();
}
//hsAssert(fInterface, "nil fInterface in hsConverterUtils::GetINodeByName()");
if(!fInterface)
{
fErrorMsg->Set(true, "Get INode by Name Error", "nil fInterface in hsConverterUtils::GetINodeByName()").Show();
fErrorMsg->Set();
return NULL;
}
if (caseSensitive)
{
return fInterface->GetINodeByName(name);
}
return IGetINodeByNameRecur(fInterface->GetRootNode(), name);
hsGuardEnd;
}
void hsConverterUtils::CreateNodeSearchCache()
{
if (!fNodeSearchCache)
{
fNodeSearchCache = TRACKED_NEW hsHashTable<CacheNode>();
}
fNodeSearchCache->clear();
IBuildNodeSearchCacheRecur(fInterface->GetRootNode());
}
void hsConverterUtils::DestroyNodeSearchCache()
{
delete fNodeSearchCache;
fNodeSearchCache = nil;
}
void hsConverterUtils::IBuildNodeSearchCacheRecur(INode* node)
{
if (!node || !node->GetName())
return ;
CacheNode cNode(node);
fNodeSearchCache->insert(cNode);
// Process children
int num = node->NumberOfChildren();
int i;
for(i=0; i<num; i++)
{
IBuildNodeSearchCacheRecur(node->GetChildNode(i));
}
}
UInt32 hsConverterUtils::CacheNode::GetHash() const
{
const char* k = GetName();
int len = k ? strlen(k) : 0;
int h;
for (h=len; len--;)
{
h = ((h<<5)^(h>>27))^tolower(*k++);
}
return h;
}
bool hsConverterUtils::CacheNode::operator==(const CacheNode& other) const
{
const char* k1 = GetName();
const char* k2 = other.GetName();
if (other.fCaseSensitive || fCaseSensitive)
return !strcmp(k1,k2);
else
return !_stricmp(k1,k2);
}
#endif // HS_BUILD_FOR_WIN32