Team Fortress 2 Source Code as on 22/4/2020
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.

398 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #pragma warning (disable:4786)
  9. //=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. ===========
  10. //
  11. // The copyright to the contents herein is the property of Valve, L.L.C.
  12. // The contents may be used and/or copied only with the written permission of
  13. // Valve, L.L.C., or in accordance with the terms and conditions stipulated in
  14. // the agreement/contract under which the contents have been supplied.
  15. //
  16. // Purpose: Implementation of all the custom award trigger classes
  17. //
  18. // $Workfile: $
  19. // $Date: $
  20. //
  21. //------------------------------------------------------------------------------------------------------
  22. // $Log: $
  23. //
  24. // $NoKeywords: $
  25. //=============================================================================
  26. #include "TFStatsApplication.h"
  27. #include "CustomAwardTriggers.h"
  28. #include "memdbg.h"
  29. #include "util.h"
  30. using namespace std;
  31. //------------------------------------------------------------------------------------------------------
  32. // Function: CCustomAwardTrigger::readTrigger
  33. // Purpose: reads a trigger definition from the given rule file and returns a new trigger
  34. // Input: f - a pointer to the TextFile object that represents the rule file to read from
  35. // Output: CCustomAwardTrigger*
  36. //------------------------------------------------------------------------------------------------------
  37. CCustomAwardTrigger* CCustomAwardTrigger::readTrigger(CTextFile& f)
  38. {
  39. CCustomAwardTrigger* retval=NULL;
  40. string type="fullsearch";
  41. vector<string> keys;
  42. int value = 1 ;
  43. int teamValue = 1;
  44. f.discard("{");
  45. map<string,string> extraProps;
  46. const char* token=f.getToken();
  47. while (token)
  48. {
  49. if (stricmp(token,"value")==0)
  50. {
  51. f.discard("=");
  52. value=atoi(f.readString());
  53. f.discard(";");
  54. }
  55. else if (stricmp(token,"teamvalue")==0)
  56. {
  57. f.discard("=");
  58. teamValue=atoi(f.readString());
  59. f.discard(";");
  60. }
  61. else if (stricmp(token,"type")==0)
  62. {
  63. f.discard("=");
  64. type=f.readString();
  65. f.discard(";");
  66. }
  67. else if (stricmp(token,"key")==0)
  68. {
  69. f.discard("=");
  70. char lowerbuf[500];
  71. Util::str2lowercase(lowerbuf,f.readString());
  72. keys.push_back(lowerbuf);
  73. f.discard(";");
  74. }
  75. else if (stricmp(token,"}")==0)
  76. {
  77. break;
  78. }
  79. else
  80. {
  81. f.discard("=");
  82. char lowerbuf[500];
  83. char lowerbuf2[500];
  84. //oops, have to do this first. CTextfile uses a static buffer to return strings
  85. Util::str2lowercase(lowerbuf2,token);
  86. Util::str2lowercase(lowerbuf,f.readString());
  87. extraProps[lowerbuf2]=lowerbuf;
  88. f.discard(";");
  89. }
  90. token=f.getToken();
  91. }
  92. if (type=="broadcast")
  93. retval= new TRACKED CBroadcastTrigger(value,teamValue,keys,extraProps);
  94. else if (type=="goal")
  95. retval = new TRACKED CGoalTrigger(value,teamValue,keys,extraProps);
  96. else if (type=="fullsearch")
  97. retval = new TRACKED CFullSearchTrigger(value,teamValue,keys,extraProps);
  98. else
  99. 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);
  100. return retval;
  101. }
  102. //------------------------------------------------------------------------------------------------------
  103. // Function: CBroadcastTrigger::CBroadcastTrigger
  104. // Purpose: Constructor for CBroadcastTrigger
  105. // Input: value - the value of the trigger relative to other triggers
  106. // teamValue - the teamValue of the trigger (not used)
  107. // keys - strings to search for in the text of any broadcast event
  108. //------------------------------------------------------------------------------------------------------
  109. CBroadcastTrigger::CBroadcastTrigger (int value, int teamValue, vector<string>& keys,map<string,string> extras)
  110. :CCustomAwardTrigger(value,teamValue,extras)
  111. {
  112. //this line works in win32, but not in G++... g++ doesn't seem to have vector::assign
  113. //broadcastStrings.assign(keys.begin(),keys.end());
  114. //make a new temp object, and assign it to broadcastStrings
  115. broadcastStrings=vector<string>(keys);
  116. }
  117. //------------------------------------------------------------------------------------------------------
  118. // Function: CBroadcastTrigger::matches
  119. // Purpose: Determines if a given event is a broadcast and matches any of the keys
  120. // Input: le - the event we're testing
  121. // Output: Returns true if the given event triggers this trigger
  122. //------------------------------------------------------------------------------------------------------
  123. bool CBroadcastTrigger::matches(const CLogEvent* le)
  124. {
  125. if (le->getType() == CLogEvent::NAMED_BROADCAST)// || le->getType() == CLogEvent::ANON_BROADCAST)
  126. {
  127. //broadcastID is arg0
  128. string BroadID=le->getArgument(0)->getStringValue();
  129. vector<string>::iterator it;
  130. for (it=broadcastStrings.begin();it!=broadcastStrings.end();++it)
  131. {
  132. string s=*it;
  133. if (BroadID==*it)
  134. return true;
  135. }
  136. }
  137. return false;
  138. }
  139. //------------------------------------------------------------------------------------------------------
  140. // Function: CGoalTrigger::CGoalTrigger
  141. // Purpose: Constructor for CGoalTrigger
  142. // Input: value - the value of the trigger relative to other triggers
  143. // teamValue - the teamValue of the trigger (not used)
  144. // keys - the names of goals that will cause this trigger to trigger
  145. //------------------------------------------------------------------------------------------------------
  146. CGoalTrigger::CGoalTrigger(int value, int teamValue, vector<string>& keys,map<string,string> extras)
  147. :CCustomAwardTrigger(value,teamValue,extras)
  148. {
  149. //this line works in win32, but not in G++... g++ doesn't seem to have vector::assign
  150. //goalNames.assign(keys.begin(),keys.end());
  151. //make a new temp object, and assign it to broadcastStrings
  152. //does this introduce a memory leak?
  153. goalNames=vector<string>(keys);
  154. }
  155. //------------------------------------------------------------------------------------------------------
  156. // Function: CGoalTrigger::matches
  157. // Purpose: Determines if a given event is a goal activation and matches any of the keys
  158. // Input: le - the event we're testing
  159. // Output: Returns true if the given event triggers this trigger
  160. //------------------------------------------------------------------------------------------------------
  161. bool CGoalTrigger::matches(const CLogEvent* le)
  162. {
  163. if (le->getType() == CLogEvent::NAMED_GOAL_ACTIVATE)
  164. {
  165. string n=le->getArgument(1)->getStringValue();
  166. vector<string>::iterator it;
  167. for (it=goalNames.begin();it!=goalNames.end();++it)
  168. {
  169. int diff=strnicmp(n.c_str(),(*it).c_str(),(*it).length());
  170. if (diff==0)
  171. return true;
  172. }
  173. }
  174. return false;
  175. }
  176. //------------------------------------------------------------------------------------------------------
  177. // Function: CFullSearchTrigger::CFullSearchTrigger
  178. // Purpose: Constructor for CFullSearchTrigger
  179. // Input: value - the value of the trigger relative to other triggers
  180. // teamValue - the teamValue of the trigger (not used)
  181. // ks - the names of FullSearchs that will cause this trigger to trigger
  182. //------------------------------------------------------------------------------------------------------
  183. CFullSearchTrigger::CFullSearchTrigger(int value, int teamValue, vector<string>& ks,map<string,string> extras)
  184. :CCustomAwardTrigger(value,teamValue,extras)
  185. {
  186. //this line works in win32, but not in G++... g++ doesn't seem to have vector::assign
  187. //FullSearchNames.assign(keys.begin(),keys.end());
  188. //make a new temp object, and assign it to broadcastStrings
  189. winnerVar=extraProps["winnervar"];
  190. keys=vector<string>(ks);
  191. }
  192. bool killws(const char*& cs)
  193. {
  194. bool retval=false;
  195. while(isspace(*cs))
  196. {
  197. retval=true;
  198. cs++;
  199. }
  200. return retval;
  201. }
  202. #include <regex>
  203. int regExprCompare(string sexpr,string scmp)
  204. {
  205. regex expression(sexpr);
  206. cmatch what;
  207. if(query_match(scmp.c_str(), scmp.c_str() + strlen(scmp.c_str()), what, expression))
  208. {
  209. //matched!
  210. return 0;
  211. }
  212. else
  213. return 1;
  214. }
  215. bool CFullSearchTrigger::compare(string str_msg,string str_key,map<string,string>& varmatches)
  216. {
  217. const char* msg=str_msg.c_str();
  218. const char* key=str_key.c_str();
  219. bool match=true;
  220. char varbuf[100];
  221. char cmpbuf[100];
  222. while (1)
  223. {
  224. if (!*msg) break;
  225. if (!*key) break;
  226. //get a variable.
  227. if (*key=='%')
  228. {
  229. int i=0;
  230. while(*key && *key!=' ')
  231. {
  232. varbuf[i++]=*(key++);
  233. }
  234. varbuf[i]=0;
  235. if (winnerVar=="")
  236. winnerVar=varbuf;
  237. killws(msg);
  238. if (*msg=='\"')
  239. {
  240. msg++;
  241. int i=0;
  242. while (*msg && *msg!='\"')
  243. {
  244. cmpbuf[i++]=*msg++;
  245. }
  246. cmpbuf[i]=0;
  247. msg++; //skip past last "
  248. }
  249. else
  250. {
  251. int i=0;
  252. while (*msg!=' ')
  253. {
  254. cmpbuf[i++]=*msg++;
  255. }
  256. cmpbuf[i]=0;
  257. }
  258. string matchexpr=extraProps[varbuf];
  259. if (matchexpr=="")
  260. {
  261. //if blank, match any quote delimited string or space delimited word
  262. varmatches.insert(pair<string,string>(varbuf,cmpbuf));
  263. }
  264. else if (matchexpr.at(0)!='!' && matchexpr.at(1)!='!')
  265. {
  266. //do a normal string compare
  267. if (stricmp(matchexpr.c_str(),cmpbuf)==0)
  268. varmatches.insert(pair<string,string>(varbuf,cmpbuf));
  269. else
  270. return false;
  271. }
  272. else
  273. {
  274. //in tfstats, reg expressions start with !! so skip past that
  275. const char* rexpr=matchexpr.c_str()+2;
  276. string test=rexpr;
  277. if (regExprCompare(rexpr,cmpbuf)==0)
  278. varmatches.insert(pair<string,string>(varbuf,cmpbuf));
  279. else
  280. return false;
  281. }
  282. }
  283. bool movedptr1 = killws(msg);
  284. bool movedptr2 = killws(key);
  285. if (!movedptr1 && !movedptr2)
  286. {
  287. if (!*msg) break;
  288. if (*msg!=*key)
  289. {
  290. match=false;
  291. break;
  292. }
  293. msg++;
  294. key++;
  295. }
  296. if (!*msg) break;
  297. }
  298. return match;
  299. }
  300. //------------------------------------------------------------------------------------------------------
  301. // Function: CFullSearchTrigger::matches
  302. // Purpose:
  303. // Input: le - the event we're testing
  304. // Output: Returns true if the given event triggers this trigger
  305. //------------------------------------------------------------------------------------------------------
  306. bool CFullSearchTrigger::matches(const CLogEvent* le)
  307. {
  308. //test against full text
  309. //clear out the state from the last match attempt
  310. map<string,string> varmatches;
  311. bool match=compare(le->getFullMessage(),keys[0],varmatches);
  312. #ifdef _CUSTOMDEBUG
  313. #ifdef _DEBUG
  314. if (match)
  315. {
  316. map<string,string>::iterator it=varmatches.begin();
  317. for (it;it!=varmatches.end();++it)
  318. {
  319. debug_printf("matched %s with %s\n",it->first.c_str(),it->second.c_str());
  320. }
  321. }
  322. #endif
  323. #endif
  324. return match;
  325. }
  326. #include "pid.h"
  327. PID CFullSearchTrigger::plrIDFromEvent(const CLogEvent* ple)
  328. {
  329. #ifdef WIN32
  330. if (winnerVar.compare(0,5,"%plr_")==0)
  331. #else
  332. if (winnerVar.at(0)=='%' &&
  333. winnerVar.at(1)=='p' &&
  334. winnerVar.at(2)=='l' &&
  335. winnerVar.at(3)=='r' &&
  336. winnerVar.at(4)=='_')
  337. #endif
  338. {
  339. map<string,string> varmatches;
  340. compare(ple->getFullMessage(),keys[0],varmatches);
  341. string name=varmatches[winnerVar];
  342. int svrID=Util::string2svrID(name);
  343. return pidMap[svrID];
  344. }
  345. else
  346. return -1;
  347. }
  348. //this class does
  349. string CFullSearchTrigger::getTrackString(const CLogEvent* ple)
  350. {
  351. map<string,string> varmatches;
  352. compare(ple->getFullMessage(),keys[0],varmatches);
  353. return varmatches[winnerVar];
  354. }