|
|
|
/*==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 "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_t 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().c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
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<char> tmpObjName(size);
|
|
|
|
memset(tmpObjName, 0, size);
|
|
|
|
|
|
|
|
//
|
|
|
|
// set string matching flags
|
|
|
|
//
|
|
|
|
int len = strlen(objName);
|
|
|
|
uint32_t 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(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;
|
|
|
|
}
|