khanat-opennel-code/code/ryzom/server/src/ai_data_service/aids_actions.cpp

261 lines
8.1 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//----------------------------------------------------------------------------
#include "nel/misc/command.h"
#include "nel/misc/debug.h"
#include "nel/misc/config_file.h"
#include "nel/misc/path.h"
#include "nel/net/service.h"
#include "aids_actions.h"
using namespace NLMISC;
using namespace NLNET;
using namespace std;
//----------------------------------------------------------------------------
// Stuff for debug message logging
//----------------------------------------------------------------------------
static bool verboseLog=false;
#define TAB toString("%*s",CurrentMgrDfnNodes.size()*4,"").c_str()
#define TAB1 toString("%*s",CurrentMgrDfnNodes.size()*4-4,"").c_str()
#define LOG if (!verboseLog) {} else nlinfo
NLMISC_COMMAND(verboseAIDSActionLog,"Turn on or off or check the state of verbose AIDSAction parser logging","")
{
if(args.size()>1)
return false;
if(args.size()==1)
StrToBool (verboseLog, args[0]);
nlinfo("verboseAIDSActionLogging is %s",verboseLog?"ON":"OFF");
return true;
}
//----------------------------------------------------------------------------
// Singleton data instantiation
//----------------------------------------------------------------------------
CAIDSActions *CAIDSActions::Instance=NULL;
uint CAIDSActions::CurrentManager=0;
//----------------------------------------------------------------------------
// Local utility functions and variables
//----------------------------------------------------------------------------
static uint BadParseDepth=0;
static CAIManager::SMgrDfnNode DefaultNode;
static std::vector<CAIManager::SMgrDfnNode *> CurrentMgrDfnNodes;
static bool FoundAIData=false;
static std::string FileName;
static void Prepare(CAIManager::SMgrDfnNode &node)
{
// recurse through children
for (uint i=0;i<node.Child.size();++i)
Prepare(*node.Child[i]);
// deal with self
node.Visited=false;
node.Data.clear();
}
static void Clean(CAIManager::SMgrDfnNode &node)
{
// recurse through children
for (uint i=0;i<node.Child.size();++i)
Clean(*node.Child[i]);
// deal with self
if (!node.Visited)
{
node.Child.clear();
node.Name.clear(); // clearing the name makes the slot re-usable next compile
}
}
//----------------------------------------------------------------------------
// Public methods
//----------------------------------------------------------------------------
void CAIDSActions::openFile(const std::string &fileName)
{
LOG("Scanning file: %s",fileName.c_str());
// setup local vars
BadParseDepth=0;
DefaultNode.Child.clear();
DefaultNode.Data.clear();
CurrentMgrDfnNodes.clear();
FoundAIData=false;
}
void CAIDSActions::closeFile(const std::string &fileName)
{
// if the primitive file didn't contain anything interesting then add it to the ignore list
if (!FoundAIData)
{
nlinfo("No manager found in primitive file: %s - adding to ignore list",fileName.c_str());
// lookup the ignore files in the config file and copy into a temp vector
CConfigFile::CVar *varPtr=IService::getInstance()->ConfigFile.getVarPtr(std::string("IgnorePrimitives"));
std::vector<std::string> ignoreFiles;
for (uint i=0;i<varPtr->size();++i)
ignoreFiles.push_back(CFile::getFilenameWithoutExtension(varPtr->asString(i)));
//append this file to the vector and pass it back to the config file manager for storage
ignoreFiles.push_back(NLMISC::CFile::getFilenameWithoutExtension(fileName));
varPtr->setAsString(ignoreFiles);
IService::getInstance()->ConfigFile.save();
}
}
void CAIDSActions::begin(const std::string &contextName)
{
LOG("%s{ // %s",TAB,contextName.c_str());
uint i;
// if we've encountered a parse problem just count levels of indentation
if (BadParseDepth)
{
++BadParseDepth;
return;
}
// if the CurrentMgrDfnNodes vector is empty then we must be parsing a new manager
if (CurrentMgrDfnNodes.empty())
{
nlinfo("- Parsing: %s",contextName.c_str());
// update variables used in this source file (AIDS_ACTIONS.CPP)
FoundAIData=true;
CurrentMgrDfnNodes.push_back(&(CAIManager::getManagerById(CurrentManager)->MgrDfnRootNode));
CurrentMgrDfnNodes[0]->Name=contextName;
// reset the 'visited' flags for the manager's data tree
Prepare(*CurrentMgrDfnNodes[0]);
CurrentMgrDfnNodes[0]->Visited=true;
// copy the default dfn nodes to the current node and add a 'set_slot' action
CAIManager::SMgrDfnNode *curNode=CurrentMgrDfnNodes[CurrentMgrDfnNodes.size()-1];
for (uint i=0;i<DefaultNode.Data.size();++i)
curNode->Data.push_back(DefaultNode.Data[i]);
// add a set_slot action with value uint slot id = CurrentManager
std::vector <CAIActions::CArg> args;
args.push_back(CAIActions::CArg(CurrentManager));
curNode->Data.push_back(CAIManager::SMgrDfnElm(*(uint64*)"SET_SLOT",args));
}
else
{
CAIManager::SMgrDfnNode *curNode=CurrentMgrDfnNodes[CurrentMgrDfnNodes.size()-1];
// try to find a node with the name matching contextName
// if there are a number of nodes with the same name then this code should work ok as
// it uses the 'visited' flags to avoid multi-use of same node slot
CAIManager::SMgrDfnNode *node=NULL;
for (i=0;i<curNode->Child.size();++i)
if ((curNode->Child[i]->Name.empty() || curNode->Child[i]->Name==contextName) && !curNode->Child[i]->Visited)
{
node=(curNode->Child[i]);
break;
}
// if need be allocate a new data node
if (i==curNode->Child.size())
{
curNode->Child.push_back(new CAIManager::SMgrDfnNode(contextName));
node=curNode->Child[i];
}
// add a set_slot action with value uint slot id = i
std::vector <CAIActions::CArg> args;
args.push_back(CAIActions::CArg(i));
curNode->Child[i]->Data.push_back(CAIManager::SMgrDfnElm(*(uint64*)"SET_SLOT",args));
// update variables used in this source file (AIDS_ACTIONS.CPP)
CurrentMgrDfnNodes.push_back(node);
node->Visited=true;
}
}
void CAIDSActions::end(const std::string &contextName)
{
LOG("%s} // %s",TAB1,contextName.c_str());
// if we've encountered a parse problem just count levels of indentation
if (BadParseDepth)
{
--BadParseDepth;
return;
}
// make sure the name of the context that we're closing matches the name of the context that we opened
CAIManager::SMgrDfnNode *curNode=CurrentMgrDfnNodes[CurrentMgrDfnNodes.size()-1];
nlassert(contextName==curNode->Name);
// close this context
CurrentMgrDfnNodes.pop_back();
// if we've finished then do some housekeeping
if (CurrentMgrDfnNodes.empty())
{
// run back through tree stripping out unvisitted entries
Clean(*curNode);
}
}
void CAIDSActions::execute(uint64 action,const std::vector <CAIActions::CArg> &args)
{
// if we've encountered a parse problem don't execute...
if (BadParseDepth)
{
return;
}
// generate a string to describe the action
std::string txt;
txt+=toString("%-8.8s",&action);
txt+='(';
for (uint i=0;i<args.size();++i)
{
txt+=args[i].toString();
if (i<args.size()-1) txt+=", ";
}
txt+=')';
LOG("%s%s",TAB,txt.c_str());
CAIManager::SMgrDfnNode *curNode;
// if we havent yet opened our first context then store this data record in the default node
// otherwise store it in the node on the top of the CurrentMgrDfnNodes vector
if (CurrentMgrDfnNodes.empty())
curNode=&DefaultNode;
else
curNode=CurrentMgrDfnNodes[CurrentMgrDfnNodes.size()-1];
// add the data record to the top node on the CurrentMgrDfnNodes vector
curNode->Data.push_back(CAIManager::SMgrDfnElm(action,args));
}