summaryrefslogtreecommitdiff
path: root/utils/tfstats/tfstatsapplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/tfstats/tfstatsapplication.cpp')
-rw-r--r--utils/tfstats/tfstatsapplication.cpp467
1 files changed, 467 insertions, 0 deletions
diff --git a/utils/tfstats/tfstatsapplication.cpp b/utils/tfstats/tfstatsapplication.cpp
new file mode 100644
index 0000000..f7f441e
--- /dev/null
+++ b/utils/tfstats/tfstatsapplication.cpp
@@ -0,0 +1,467 @@
+//========= 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 the TFStatsApplication class.
+//
+// $Workfile: $
+// $Date: $
+//
+//------------------------------------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include "TFStatsApplication.h"
+#include "TFStatsReport.h"
+#include "LogEvent.h"
+#include "ScoreBoard.h"
+#include "WhoKilledWho.h"
+#include "memdbg.h"
+#include "awards.h"
+#include "MatchResults.h"
+#include "DialogueReadout.h"
+#include "cvars.h"
+#include "html.h"
+#include "TextFile.h"
+#include "CustomAward.h"
+#include "PlayerSpecifics.h"
+#include "util.h"
+#include "AllPlayersStats.h"
+#include <errno.h>
+
+
+
+CTFStatsApplication* g_pApp; //global!
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTFStatsApplication::printUsage
+// Purpose: Prints out how to use the program
+//------------------------------------------------------------------------------------------------------
+void CTFStatsApplication::printUsage()
+{
+
+ printf("TFStats version %li.%li\n",majorVer,minorVer);
+ printf("\nUSAGE:\n");
+#ifdef WIN32
+ printf("TFstatsRT.exe <log file name> <optional switches>\n");
+#else
+ printf("TFstats_l <log file name> <optional switches>\n");
+#endif
+ printf("the available switches are detailed in the documentation. (TFStats.htm): \n");
+ printf("---\n");
+ printf("After TFStats is done, several new HTML files will be in the current directory,\n");
+ printf("point your browser to the index.html in this directory and it will do the rest.\n");
+#ifdef WIN32
+ printf("(you should just be able to do \"start index.html\")\n");
+#endif
+ printf("TFStats uses Regex++:\nRegex++ � 1998-9 Dr John Maddock.\n");
+
+}
+
+#include "CustomAwardList.h"
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTFStatsApplication::DoAwards
+// Purpose: This reports all of the awards
+// Input: MatchResultsPage - the page on which to write the awards' HTML
+//------------------------------------------------------------------------------------------------------
+void CTFStatsApplication::DoAwards(CHTMLFile& MatchResultsPage)
+{
+ int chresult=os->chdir(g_pApp->outputDirectory.c_str());
+
+ MatchResultsPage.p();
+ MatchResultsPage.write("<img src=\"%s/awards.gif\">\n",g_pApp->supportHTTPPath.c_str());
+ MatchResultsPage.div("awards");
+
+ //do custom awards first, they're usually the important ones for the match
+ CCustomAwardList* pCust;
+ os->chdir(ruleDirectory.c_str());
+ pCust=CCustomAwardList::readCustomAwards(g_pMatchInfo->mapName());
+ os->chdir(outputDirectory.c_str());
+ if(pCust)
+ {
+
+ CCustomAwardIterator it;
+ for (it=pCust->begin();it!=pCust->end();++it)
+ {
+ (*it)->report(MatchResultsPage);
+ }
+
+ delete pCust;
+ MatchResultsPage.hr(450,true);
+ }
+ os->chdir(outputDirectory.c_str());
+
+ //do scout award here.
+ CSurvivalistAward csrva; csrva.report(MatchResultsPage);
+
+ //sniper award
+ CSharpshooterAward cssa; cssa.report(MatchResultsPage);
+
+ //soldier award
+ CRocketryAward cra; cra.report(MatchResultsPage);
+
+ //demoman awards
+ CGrenadierAward cga; cga.report(MatchResultsPage);
+ CDemolitionsAward cda; cda.report(MatchResultsPage);
+
+ //medic awards
+ CCureAward cca;cca.report(MatchResultsPage);
+ CBiologicalWarfareAward cbwa; cbwa.report(MatchResultsPage);
+
+ //HW award
+ CAssaultCannonAward caca;caca.report(MatchResultsPage);
+
+ //pyro award
+ CFlamethrowerAward cfa;cfa.report(MatchResultsPage);
+
+ //spy award
+ CKnifeAward cka;cka.report(MatchResultsPage);
+
+ //engineer awards
+ CBestSentryAward cbsa; cbsa.report(MatchResultsPage);
+ CSentryRebuildAward cba2;cba2.report(MatchResultsPage);
+
+
+ MatchResultsPage.hr(450,true);
+
+ //non class specific
+ CKamikazeAward ckami;ckami.report(MatchResultsPage);
+ CTalkativeAward cta;cta.report(MatchResultsPage);
+ CTeamKillAward ctka; ctka.report(MatchResultsPage);
+
+
+
+
+ MatchResultsPage.enddiv();
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTFStatsApplication::DoMatchResults
+// Purpose: This creates the MatchResults page of the report (the main page)
+//------------------------------------------------------------------------------------------------------
+void CTFStatsApplication::DoMatchResults()
+{
+ int chresult=os->chdir(g_pApp->outputDirectory.c_str());
+ CHTMLFile MatchResultsPage("MatchResults.html","results");
+ CMatchResults cmr;
+ cmr.report(MatchResultsPage);
+ DoAwards(MatchResultsPage);
+
+ CScoreboard cs;
+ cs.report(MatchResultsPage);
+
+
+ CWhoKilledWho cwkw; cwkw.report(MatchResultsPage);
+
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTFStatsApplication::parseCmdLineArg
+// Purpose: This parses variables and values out of passed in commandline args
+// Input: in - the full command line argument
+// var - the output buffer in which to place the name of the variable
+// val - the output buffer in which to place the value of the variable
+//------------------------------------------------------------------------------------------------------
+void CTFStatsApplication::parseCmdLineArg(const char* in, char* var, char* val)
+{
+ char* pEq=strchr(in,'=');
+ if (!pEq || pEq==in)
+ {
+ var[0]=val[0]=0;
+ }
+ else
+ {
+ *pEq=0;
+ strcpy(var,in);
+ strcpy(val,pEq+1);
+ Util::str2lowercase(var,var);
+ Util::str2lowercase(val,val);
+ *pEq='=';
+ }
+
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTFStatsApplication::ParseCommandLine
+// Purpose: this parses the commandline into the cmdLineSwitches map. Also
+// recognizes certain switches and sets variables and creates directories
+// accordingly to their values
+// Input: argc - count of arguments from commandline
+// argv[] - the arguments
+//------------------------------------------------------------------------------------------------------
+void CTFStatsApplication::ParseCommandLine(int argc,const char* argv[])
+{
+ char var[100];
+ char val[100];
+
+ //first find if we want to display startup info
+ bool displayStartupInfo=false;
+ for(int i=2;i<argc;i++)
+ {
+ parseCmdLineArg(argv[i],var,val);
+ if (!var[0])
+ fatalError("Malformed switch, required format is <variable>=<value> with no spaces");
+
+ cmdLineSwitches[var]=val;
+ if (stricmp(var,"displaystartupinfo")==0)
+ if (stricmp(val,"yes")==0)
+ {
+ displayStartupInfo=true;
+ break;
+ }
+ }
+
+
+
+ if (displayStartupInfo)
+ {
+ printf("%21s %-21s\n","Command line","Switches");
+ printf("-------------------------------------------\n");
+ }
+ for(i=2;i<argc;i++)
+ {
+ parseCmdLineArg(argv[i],var,val);
+ if (!var[0])
+ fatalError("Malformed switch, required format is <variable>=<value> with no spaces");
+
+ if (displayStartupInfo)
+ printf("%20s = %-20s\n",var,val);
+ cmdLineSwitches[var]=val;
+ }
+
+
+
+ outputDirectory=os->removeDirSlash(cmdLineSwitches["outputdir"]);
+ makeAndSaveDirectory(outputDirectory);
+
+ ruleDirectory=os->removeDirSlash(cmdLineSwitches["ruledir"]);
+ makeAndSaveDirectory(ruleDirectory);
+
+ if (cmdLineSwitches["eliminateoldplayers"]=="yes")
+ {
+ eliminateOldPlayers=true;
+ elimDays=atoi(cmdLineSwitches["oldplayercutoff"].c_str());
+ }
+ else
+ {
+ eliminateOldPlayers=false;
+ elimDays=0;
+ }
+
+
+ if (cmdLineSwitches["usesupportdir"]=="yes")
+ {
+ supportDirectory=os->removeDirSlash(cmdLineSwitches["supportdir"]);
+ supportHTTPPath=os->removeDirSlash(cmdLineSwitches["supporthttppath"]);
+ }
+ else
+ {
+ supportDirectory=g_pApp->outputDirectory+g_pApp->os->pathSeperator();
+ supportDirectory+="support";
+ supportHTTPPath="support";
+ }
+ makeAndSaveDirectory(supportDirectory);
+
+
+ if (cmdLineSwitches["persistplayerstats"]=="yes")
+ {
+ playerDirectory=os->removeDirSlash(cmdLineSwitches["playerdir"]);
+ playerHTTPPath=os->removeDirSlash(cmdLineSwitches["playerhttppath"]);
+ }
+ else
+ {
+ playerDirectory=g_pApp->outputDirectory+g_pApp->os->pathSeperator();
+ playerDirectory+="players";
+ playerHTTPPath="players";
+ }
+ makeAndSaveDirectory(playerDirectory);
+ makeDirectory(playerDirectory+"support");
+}
+
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTFStatsApplication::main
+// Purpose: The REAL main of the program
+// Input: argc - count of arguments from commandline
+// argv[] - the arguments
+//------------------------------------------------------------------------------------------------------
+void CTFStatsApplication::main(int argc,const char* argv[])
+{
+ if (argc<=1){printUsage();return;}
+ g_pApp=this;
+
+ //TODO: move this into OS interface
+ TFStats_setNewHandler();
+
+ inputDirectory=".";
+ makeAndSaveDirectory(inputDirectory);
+
+ //this call also sets up various directories to be used
+ ParseCommandLine(argc,argv);
+
+ Util::initFriendlyWeaponNameTable();
+
+ //LogFile is read in here.
+ //MUST do this before we chdir to the output directory
+ os->chdir(inputDirectory.c_str());
+ CEventList* plogfile=NULL;
+ plogfile=CEventList::readEventList(argv[1]);
+ if (!plogfile)
+ fatalError("No valid data found in logfile %s\n",argv[1]);
+
+
+ os->chdir(outputDirectory.c_str());
+ //make match information object
+ g_pMatchInfo= new CMatchInfo(plogfile);
+
+ CTFStatsReport matchreport;
+
+
+
+ matchreport.genImages();
+
+
+ matchreport.genJavaScript();
+ matchreport.genStyleSheet();
+
+ if (cmdLineSwitches["persistplayerstats"]=="yes")
+ matchreport.genAllPlayersStyleSheet();
+
+ matchreport.genIndex();
+
+ os->chdir(outputDirectory.c_str());
+ matchreport.genTopFrame();
+ matchreport.genNavFrame();
+
+
+ DoMatchResults();
+
+
+ CCVarList ccvl;
+ ccvl.makeHTMLPage("cvars.html","Server Settings");
+
+ CDialogueReadout cdr;
+ cdr.makeHTMLPage("dialogue.html","Dialogue");
+
+ CPlayerSpecifics cps;
+ cps.makeHTMLPage("players.html","Players");
+
+
+ if (cmdLineSwitches["persistplayerstats"]=="yes")
+ {
+ if(!g_pMatchInfo->isLanGame())
+ {
+ g_pApp->os->chdir(g_pApp->playerDirectory.c_str());
+ CAllPlayersStats caps;
+ caps.makeHTMLPage("allplayers.html","All Players");
+ }
+ else
+ {
+ g_pApp->warning("Lan Game detected, player stats will not be saved");
+ }
+ }
+ printf("TFStats completed successfully\n\n\n");
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTFStatsApplication::makeAndSaveDirectory
+// Purpose: Creates a directory and writes the full directory path back into the
+// passed in string. In effect, this turns a potentially relative path into an
+// absolute path, and ensures the directory exists.
+// Input: dir - the string that contains the pathname, and upon return will contain
+// the absolute pathname
+//------------------------------------------------------------------------------------------------------
+void CTFStatsApplication::makeAndSaveDirectory(string& dir)
+{
+ char startpath[500];
+ char fullpath[500];
+ os->getcwd(startpath,500);
+ if (!os->makeHier(dir))
+ {
+ fatalError("Failed to make directory \"%s\", aborting. (Reason: %s)",dir.c_str(),strerror(errno));
+ }
+ os->chdir(dir.c_str());
+ os->getcwd(fullpath,500);
+ dir=fullpath;
+ os->addDirSlash(dir);
+ os->chdir(startpath);
+}
+
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTFStatsApplication::makeDirectory
+// Purpose: Creates a directory.
+// Input: dir - the directory to create
+//------------------------------------------------------------------------------------------------------
+void CTFStatsApplication::makeDirectory(string& dir)
+{
+ char startpath[500];
+ os->getcwd(startpath,500);
+
+ if (!os->makeHier(dir))
+ {
+ fatalError("Failed to make directory \"%s\". (Reason: %s)",dir.c_str(),strerror(errno));
+ }
+ os->chdir(startpath);
+}
+
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTFStatsApplication::fatalError
+// Purpose: prints an error message and exits
+// Input: fmt - the format string
+// ... - optional arguments
+//------------------------------------------------------------------------------------------------------
+void CTFStatsApplication::fatalError(char* fmt,...)
+{
+ va_list v;
+ va_start(v,fmt);
+ fprintf(stderr,"Fatal Error: ");
+ vfprintf(stderr,fmt,v);
+ fprintf(stderr,"\n***Aborting. \n");
+ exit(-1);
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTFStatsApplication::warning
+// Purpose: prints a warning message and returns. (program doesn't exit)
+// Input: fmt - format string
+// ... - optional arguments
+//------------------------------------------------------------------------------------------------------
+void CTFStatsApplication::warning(char* fmt,...)
+{
+ va_list v;
+ va_start(v,fmt);
+ fprintf(stderr,"Warning: ");
+ vfprintf(stderr,fmt,v);
+ fprintf(stderr,"\n");
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTFStatsApplication::getCutoffSeconds
+// Purpose: Turns the number of cutoff days into seconds. Cutoff days are how
+// many days players can be absent from the server and still have their stats
+// reported in the all-player stats
+// Output: time_t the number of cutoff seconds
+//------------------------------------------------------------------------------------------------------
+time_t CTFStatsApplication::getCutoffSeconds()
+{
+ return 60*60*24*elimDays;
+} \ No newline at end of file