//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #pragma warning (disable:4786) //=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== // // The copyright to the contents herein is the property of Valve, L.L.C. // The contents may be used and/or copied only with the written permission of // Valve, L.L.C., or in accordance with the terms and conditions stipulated in // the agreement/contract under which the contents have been supplied. // // Purpose: Implementation of all the custom award trigger classes // // $Workfile: $ // $Date: $ // //------------------------------------------------------------------------------------------------------ // $Log: $ // // $NoKeywords: $ //============================================================================= #include "TFStatsApplication.h" #include "CustomAwardTriggers.h" #include "memdbg.h" #include "util.h" using namespace std; //------------------------------------------------------------------------------------------------------ // Function: CCustomAwardTrigger::readTrigger // Purpose: reads a trigger definition from the given rule file and returns a new trigger // Input: f - a pointer to the TextFile object that represents the rule file to read from // Output: CCustomAwardTrigger* //------------------------------------------------------------------------------------------------------ CCustomAwardTrigger* CCustomAwardTrigger::readTrigger(CTextFile& f) { CCustomAwardTrigger* retval=NULL; string type="fullsearch"; vector keys; int value = 1 ; int teamValue = 1; f.discard("{"); map extraProps; const char* token=f.getToken(); while (token) { if (stricmp(token,"value")==0) { f.discard("="); value=atoi(f.readString()); f.discard(";"); } else if (stricmp(token,"teamvalue")==0) { f.discard("="); teamValue=atoi(f.readString()); f.discard(";"); } else if (stricmp(token,"type")==0) { f.discard("="); type=f.readString(); f.discard(";"); } else if (stricmp(token,"key")==0) { f.discard("="); char lowerbuf[500]; Util::str2lowercase(lowerbuf,f.readString()); keys.push_back(lowerbuf); f.discard(";"); } else if (stricmp(token,"}")==0) { break; } else { f.discard("="); char lowerbuf[500]; char lowerbuf2[500]; //oops, have to do this first. CTextfile uses a static buffer to return strings Util::str2lowercase(lowerbuf2,token); Util::str2lowercase(lowerbuf,f.readString()); extraProps[lowerbuf2]=lowerbuf; f.discard(";"); } token=f.getToken(); } if (type=="broadcast") retval= new TRACKED CBroadcastTrigger(value,teamValue,keys,extraProps); else if (type=="goal") retval = new TRACKED CGoalTrigger(value,teamValue,keys,extraProps); else if (type=="fullsearch") retval = new TRACKED CFullSearchTrigger(value,teamValue,keys,extraProps); else g_pApp->fatalError("Invalid trigger type while parsing %s:\n\"%s\" is not a valid trigger type, please use \"broadcast\", \"goal\" or \"fullsearch\"",f.fileName().c_str(),type); return retval; } //------------------------------------------------------------------------------------------------------ // Function: CBroadcastTrigger::CBroadcastTrigger // Purpose: Constructor for CBroadcastTrigger // Input: value - the value of the trigger relative to other triggers // teamValue - the teamValue of the trigger (not used) // keys - strings to search for in the text of any broadcast event //------------------------------------------------------------------------------------------------------ CBroadcastTrigger::CBroadcastTrigger (int value, int teamValue, vector& keys,map extras) :CCustomAwardTrigger(value,teamValue,extras) { //this line works in win32, but not in G++... g++ doesn't seem to have vector::assign //broadcastStrings.assign(keys.begin(),keys.end()); //make a new temp object, and assign it to broadcastStrings broadcastStrings=vector(keys); } //------------------------------------------------------------------------------------------------------ // Function: CBroadcastTrigger::matches // Purpose: Determines if a given event is a broadcast and matches any of the keys // Input: le - the event we're testing // Output: Returns true if the given event triggers this trigger //------------------------------------------------------------------------------------------------------ bool CBroadcastTrigger::matches(const CLogEvent* le) { if (le->getType() == CLogEvent::NAMED_BROADCAST)// || le->getType() == CLogEvent::ANON_BROADCAST) { //broadcastID is arg0 string BroadID=le->getArgument(0)->getStringValue(); vector::iterator it; for (it=broadcastStrings.begin();it!=broadcastStrings.end();++it) { string s=*it; if (BroadID==*it) return true; } } return false; } //------------------------------------------------------------------------------------------------------ // Function: CGoalTrigger::CGoalTrigger // Purpose: Constructor for CGoalTrigger // Input: value - the value of the trigger relative to other triggers // teamValue - the teamValue of the trigger (not used) // keys - the names of goals that will cause this trigger to trigger //------------------------------------------------------------------------------------------------------ CGoalTrigger::CGoalTrigger(int value, int teamValue, vector& keys,map extras) :CCustomAwardTrigger(value,teamValue,extras) { //this line works in win32, but not in G++... g++ doesn't seem to have vector::assign //goalNames.assign(keys.begin(),keys.end()); //make a new temp object, and assign it to broadcastStrings //does this introduce a memory leak? goalNames=vector(keys); } //------------------------------------------------------------------------------------------------------ // Function: CGoalTrigger::matches // Purpose: Determines if a given event is a goal activation and matches any of the keys // Input: le - the event we're testing // Output: Returns true if the given event triggers this trigger //------------------------------------------------------------------------------------------------------ bool CGoalTrigger::matches(const CLogEvent* le) { if (le->getType() == CLogEvent::NAMED_GOAL_ACTIVATE) { string n=le->getArgument(1)->getStringValue(); vector::iterator it; for (it=goalNames.begin();it!=goalNames.end();++it) { int diff=strnicmp(n.c_str(),(*it).c_str(),(*it).length()); if (diff==0) return true; } } return false; } //------------------------------------------------------------------------------------------------------ // Function: CFullSearchTrigger::CFullSearchTrigger // Purpose: Constructor for CFullSearchTrigger // Input: value - the value of the trigger relative to other triggers // teamValue - the teamValue of the trigger (not used) // ks - the names of FullSearchs that will cause this trigger to trigger //------------------------------------------------------------------------------------------------------ CFullSearchTrigger::CFullSearchTrigger(int value, int teamValue, vector& ks,map extras) :CCustomAwardTrigger(value,teamValue,extras) { //this line works in win32, but not in G++... g++ doesn't seem to have vector::assign //FullSearchNames.assign(keys.begin(),keys.end()); //make a new temp object, and assign it to broadcastStrings winnerVar=extraProps["winnervar"]; keys=vector(ks); } bool killws(const char*& cs) { bool retval=false; while(isspace(*cs)) { retval=true; cs++; } return retval; } #include int regExprCompare(string sexpr,string scmp) { regex expression(sexpr); cmatch what; if(query_match(scmp.c_str(), scmp.c_str() + strlen(scmp.c_str()), what, expression)) { //matched! return 0; } else return 1; } bool CFullSearchTrigger::compare(string str_msg,string str_key,map& varmatches) { const char* msg=str_msg.c_str(); const char* key=str_key.c_str(); bool match=true; char varbuf[100]; char cmpbuf[100]; while (1) { if (!*msg) break; if (!*key) break; //get a variable. if (*key=='%') { int i=0; while(*key && *key!=' ') { varbuf[i++]=*(key++); } varbuf[i]=0; if (winnerVar=="") winnerVar=varbuf; killws(msg); if (*msg=='\"') { msg++; int i=0; while (*msg && *msg!='\"') { cmpbuf[i++]=*msg++; } cmpbuf[i]=0; msg++; //skip past last " } else { int i=0; while (*msg!=' ') { cmpbuf[i++]=*msg++; } cmpbuf[i]=0; } string matchexpr=extraProps[varbuf]; if (matchexpr=="") { //if blank, match any quote delimited string or space delimited word varmatches.insert(pair(varbuf,cmpbuf)); } else if (matchexpr.at(0)!='!' && matchexpr.at(1)!='!') { //do a normal string compare if (stricmp(matchexpr.c_str(),cmpbuf)==0) varmatches.insert(pair(varbuf,cmpbuf)); else return false; } else { //in tfstats, reg expressions start with !! so skip past that const char* rexpr=matchexpr.c_str()+2; string test=rexpr; if (regExprCompare(rexpr,cmpbuf)==0) varmatches.insert(pair(varbuf,cmpbuf)); else return false; } } bool movedptr1 = killws(msg); bool movedptr2 = killws(key); if (!movedptr1 && !movedptr2) { if (!*msg) break; if (*msg!=*key) { match=false; break; } msg++; key++; } if (!*msg) break; } return match; } //------------------------------------------------------------------------------------------------------ // Function: CFullSearchTrigger::matches // Purpose: // Input: le - the event we're testing // Output: Returns true if the given event triggers this trigger //------------------------------------------------------------------------------------------------------ bool CFullSearchTrigger::matches(const CLogEvent* le) { //test against full text //clear out the state from the last match attempt map varmatches; bool match=compare(le->getFullMessage(),keys[0],varmatches); #ifdef _CUSTOMDEBUG #ifdef _DEBUG if (match) { map::iterator it=varmatches.begin(); for (it;it!=varmatches.end();++it) { debug_printf("matched %s with %s\n",it->first.c_str(),it->second.c_str()); } } #endif #endif return match; } #include "pid.h" PID CFullSearchTrigger::plrIDFromEvent(const CLogEvent* ple) { #ifdef WIN32 if (winnerVar.compare(0,5,"%plr_")==0) #else if (winnerVar.at(0)=='%' && winnerVar.at(1)=='p' && winnerVar.at(2)=='l' && winnerVar.at(3)=='r' && winnerVar.at(4)=='_') #endif { map varmatches; compare(ple->getFullMessage(),keys[0],varmatches); string name=varmatches[winnerVar]; int svrID=Util::string2svrID(name); return pidMap[svrID]; } else return -1; } //this class does string CFullSearchTrigger::getTrackString(const CLogEvent* ple) { map varmatches; compare(ple->getFullMessage(),keys[0],varmatches); return varmatches[winnerVar]; }