/*==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==*/
#include "plNetObjectDebugger.h"
#include "hsResMgr.h"
#include "hsTemplates.h"
#include "pnUtils/pnUtils.h"
#include "pnKeyedObject/hsKeyedObject.h"
#include "plStatusLog/plStatusLog.h"
#include "plResMgr/plKeyFinder.h"
#include "plNetClient/plNetClientMgr.h"
#include "plAgeLoader/plAgeLoader.h"
plNetObjectDebugger::DebugObject::DebugObject(const char* objName, plLocation& loc, UInt32 flags) :
fLoc(loc),
fFlags(flags)
{
std::string tmp = objName;
hsStrLower((char*)tmp.c_str());
fObjName = tmp;
}
//
// return true if string matches objName according to flags
//
bool plNetObjectDebugger::DebugObject::StringMatches(const char* str) const
{
if (!str)
return false;
if (fFlags & kExactStringMatch)
return !stricmp(str, fObjName.c_str());
if (fFlags & kEndStringMatch)
{
int len=strlen(str);
if (len>fObjName.size())
return false;
return !stricmp(str, fObjName.c_str()+fObjName.size()-len);
}
if (fFlags & kStartStringMatch)
{
int len=strlen(str);
if (len>fObjName.size())
return false;
return !strnicmp(str, fObjName.c_str(), strlen(str));
}
if (fFlags & kSubStringMatch)
{
std::string tmp = str;
hsStrLower((char*)tmp.c_str());
return (strstr(tmp.c_str(), fObjName.c_str()) != nil);
}
hsAssert(false, "missing flags");
return false;
}
//
// if both objName and pageName are provided, and this object has page info,
// return true if object matches both string and location.
// else just return true if object matches string
//
bool plNetObjectDebugger::DebugObject::ObjectMatches(const char* objName, const char* pageName)
{
if (!objName)
return false;
if (!pageName || (fFlags & kPageMatch)==0)
{
// only have enough info to match by objName
return StringMatches(objName);
}
plLocation loc;
loc = plKeyFinder::Instance().FindLocation(NetCommGetAge()->ageDatasetName, pageName);
return (StringMatches(objName) && loc==fLoc);
}
//
// try to match by plLocation
//
bool plNetObjectDebugger::DebugObject::ObjectMatches(const hsKeyedObject* obj)
{
if (!obj || !obj->GetKey())
return false;
if ((fFlags & kPageMatch)==0)
{
// match based on object name only
return StringMatches(obj->GetKeyName());
}
return (obj->GetKey()->GetUoid().GetLocation()==fLoc);
}
/////////////////////////////////////////////////////////////////
// plNetObjectDebugger
/////////////////////////////////////////////////////////////////
plNetObjectDebugger::plNetObjectDebugger() : fStatusLog(nil), fDebugging(false)
{
}
plNetObjectDebugger::~plNetObjectDebugger()
{
ClearAllDebugObjects();
delete fStatusLog;
}
//
// STATIC
//
plNetObjectDebugger* plNetObjectDebugger::GetInstance()
{
static plNetObjectDebugger gNetObjectDebugger;
if (plNetObjectDebuggerBase::GetInstance()==nil)
plNetObjectDebuggerBase::SetInstance(&gNetObjectDebugger);
return &gNetObjectDebugger;
}
//
// create StatusLog if necessary
//
void plNetObjectDebugger::ICreateStatusLog() const
{
if (!fStatusLog)
{
fStatusLog = plStatusLogMgr::GetInstance().CreateStatusLog(40, "NetObject.log",
plStatusLog::kFilledBackground | plStatusLog::kAlignToTop | plStatusLog::kTimestamp );
}
}
bool plNetObjectDebugger::AddDebugObject(const char* objName, const char* pageName)
{
if (!objName)
return false;
int size=strlen(objName)+1;
hsTempArray tmpObjName(size);
memset(tmpObjName, 0, size);
//
// set string matching flags
//
int len = strlen(objName);
UInt32 flags=0;
if (objName[0]=='*')
{
if (objName[len-1]=='*')
{
flags = kSubStringMatch; // *foo*
strncpy(tmpObjName, objName+1, strlen(objName)-2);
}
else
{
flags = kEndStringMatch; // *foo
strncpy(tmpObjName, objName+1, strlen(objName)-1);
}
}
if (!flags && objName[len-1]=='*')
{
flags = kStartStringMatch; // foo*
strncpy(tmpObjName, objName, strlen(objName)-1);
}
if (!flags)
{
flags = kExactStringMatch;
strcpy(tmpObjName, objName);
}
//
// set plLocation
//
plLocation loc;
if (pageName)
{
loc = plKeyFinder::Instance().FindLocation(NetCommGetAge()->ageDatasetName, pageName);
flags |= kPageMatch;
}
fDebugObjects.push_back(TRACKED_NEW DebugObject(tmpObjName, loc, flags));
ICreateStatusLog();
return true;
}
bool plNetObjectDebugger::RemoveDebugObject(const char* objName, const char* pageName)
{
bool didIt=false;
if (!pageName)
{
DebugObjectList::iterator it =fDebugObjects.begin();
for( ; it != fDebugObjects.end(); )
{
if ( (*it) && (*it)->ObjectMatches(objName, pageName))
{
delete *it;
it = fDebugObjects.erase(it);
didIt=true;
}
else
it++;
}
}
return didIt;
}
void plNetObjectDebugger::ClearAllDebugObjects()
{
DebugObjectList::iterator it =fDebugObjects.begin();
for( ; it != fDebugObjects.end(); it++)
{
delete *it;
}
fDebugObjects.clear();
}
//
// write to status log if there's a string match
//
void plNetObjectDebugger::LogMsgIfMatch(const char* msg) const
{
if (GetNumDebugObjects()==0 || !msg)
return;
// extract object name from msg, expects '...object:foo,...'
std::string tmp = msg;
hsStrLower((char*)tmp.c_str());
std::string objTag="object";
const char* c=strstr(tmp.c_str(), objTag.c_str());
if (c && c != tmp.c_str())
{
c+=objTag.size();
// move past spaces
while ( *c || *c==' ' )
c++;
char objName[128];
int i=0;
// copy objName token
while(*c && *c != ',' && *c != ' ' && i<127)
objName[i++] = *c++;
objName[i]=0;
DebugObjectList::const_iterator it = fDebugObjects.begin();
for( objName[0]; it != fDebugObjects.end(); it++)
{
if ((*it) && (*it)->StringMatches(objName))
{
LogMsg(msg);
break;
}
}
}
}
void plNetObjectDebugger::LogMsg(const char* msg) const
{
DEBUG_MSG(msg);
}
bool plNetObjectDebugger::IsDebugObject(const hsKeyedObject* obj) const
{
DebugObjectList::const_iterator it =fDebugObjects.begin();
for( ; it != fDebugObjects.end(); it++)
if ((*it) && (*it)->ObjectMatches(obj))
{
return true;
}
return false;
}