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.

460 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <direct.h>
  11. #include "tier1/strtools.h"
  12. #include <conio.h>
  13. #include "tier1/utlbuffer.h"
  14. #include "tier2/tier2.h"
  15. #include "filesystem.h"
  16. #include "imysqlwrapper.h"
  17. #include "../../game/server/dod/dod_gamestats.h"
  18. #include <time.h>
  19. static void Pause( void )
  20. {
  21. printf( "Hit a key to continue\n" );
  22. getch();
  23. }
  24. static void Usage()
  25. {
  26. fprintf( stderr, "Usage: gamestats_reader <hostname> <database> <username> <password> <table> <directory to parse> ( -verbose )\n" );
  27. Pause();
  28. exit( -1 );
  29. }
  30. #define SQL_CMD_BUFSIZE 16000
  31. char sqlCmd[SQL_CMD_BUFSIZE];
  32. bool g_bFirstCmd;
  33. bool g_bVerbose;
  34. IMySQL *mysql;
  35. char **g_argv;
  36. void StartMYSQLInsert( void )
  37. {
  38. g_bFirstCmd = true;
  39. sqlCmd[0] = '\0';
  40. Q_snprintf( sqlCmd, SQL_CMD_BUFSIZE, "INSERT INTO %s SET ", g_argv[5] );
  41. }
  42. void AddField( const char *field, const char *value )
  43. {
  44. char buf[128];
  45. if ( !g_bFirstCmd )
  46. {
  47. Q_strncat( sqlCmd, ", ", SQL_CMD_BUFSIZE, COPY_ALL_CHARACTERS );
  48. }
  49. Q_snprintf( buf, sizeof(buf), "%s=\"%s\"", field, value );
  50. Q_strncat( sqlCmd, buf, SQL_CMD_BUFSIZE, COPY_ALL_CHARACTERS );
  51. g_bFirstCmd = false;
  52. }
  53. void AddField( const char *field, const int value )
  54. {
  55. char buf[128];
  56. if ( !g_bFirstCmd )
  57. {
  58. Q_strncat( sqlCmd, ", ", SQL_CMD_BUFSIZE, COPY_ALL_CHARACTERS );
  59. }
  60. Q_snprintf( buf, sizeof(buf), "%s=%d", field, value );
  61. #ifdef _DEBUG
  62. if ( Q_strlen(buf) + Q_strlen(sqlCmd) > SQL_CMD_BUFSIZE )
  63. {
  64. Assert( !"increase buf size\n" );
  65. }
  66. #endif
  67. Q_strncat( sqlCmd, buf, SQL_CMD_BUFSIZE, COPY_ALL_CHARACTERS );
  68. g_bFirstCmd = false;
  69. }
  70. int CompleteMYSQLInsert( void )
  71. {
  72. // terminate command and execute it
  73. Q_strncat( sqlCmd, "\n", SQL_CMD_BUFSIZE, COPY_ALL_CHARACTERS );
  74. if ( g_bVerbose )
  75. {
  76. printf( "%s", sqlCmd );
  77. }
  78. int retcode = mysql->Execute( sqlCmd );
  79. if ( retcode != 0 )
  80. {
  81. const char *asdf = mysql->GetLastError();
  82. printf( "Error: %s\n", asdf );
  83. }
  84. return retcode;
  85. }
  86. static const char *pszTeamNames[] =
  87. {
  88. "allies",
  89. "axis"
  90. };
  91. static const char *pszClassNames[] =
  92. {
  93. "rifleman",
  94. "assault",
  95. "support",
  96. "sniper",
  97. "mg",
  98. "rocket"
  99. };
  100. int iDistanceStatWeapons[DOD_NUM_DISTANCE_STAT_WEAPONS] =
  101. {
  102. WEAPON_COLT,
  103. WEAPON_P38,
  104. WEAPON_C96,
  105. WEAPON_GARAND,
  106. WEAPON_GARAND_ZOOMED,
  107. WEAPON_M1CARBINE,
  108. WEAPON_K98,
  109. WEAPON_K98_ZOOMED,
  110. WEAPON_SPRING,
  111. WEAPON_SPRING_ZOOMED,
  112. WEAPON_K98_SCOPED,
  113. WEAPON_K98_SCOPED_ZOOMED,
  114. WEAPON_THOMPSON,
  115. WEAPON_MP40,
  116. WEAPON_MP44,
  117. WEAPON_MP44_SEMIAUTO,
  118. WEAPON_BAR,
  119. WEAPON_BAR_SEMIAUTO,
  120. WEAPON_30CAL,
  121. WEAPON_30CAL_UNDEPLOYED,
  122. WEAPON_MG42,
  123. WEAPON_MG42_UNDEPLOYED,
  124. };
  125. // Send hit/shots only for the following weapons
  126. int iNoDistStatWeapons[DOD_NUM_NODIST_STAT_WEAPONS] =
  127. {
  128. WEAPON_AMERKNIFE,
  129. WEAPON_SPADE,
  130. WEAPON_BAZOOKA,
  131. WEAPON_PSCHRECK,
  132. WEAPON_FRAG_US,
  133. WEAPON_FRAG_GER,
  134. WEAPON_FRAG_US_LIVE,
  135. WEAPON_FRAG_GER_LIVE,
  136. WEAPON_RIFLEGREN_US,
  137. WEAPON_RIFLEGREN_GER,
  138. WEAPON_RIFLEGREN_US_LIVE,
  139. WEAPON_RIFLEGREN_GER_LIVE,
  140. WEAPON_THOMPSON_PUNCH,
  141. WEAPON_MP40_PUNCH,
  142. };
  143. const char * s_WeaponAliasInfo[] =
  144. {
  145. "none", // WEAPON_NONE = 0,
  146. //Melee
  147. "amerknife", //WEAPON_AMERKNIFE,
  148. "spade", //WEAPON_SPADE,
  149. //Pistols
  150. "colt", //WEAPON_COLT,
  151. "p38", //WEAPON_P38,
  152. "c96", //WEAPON_C96
  153. //Rifles
  154. "garand", //WEAPON_GARAND,
  155. "m1carbine", //WEAPON_M1CARBINE,
  156. "k98", //WEAPON_K98,
  157. //Sniper Rifles
  158. "spring", //WEAPON_SPRING,
  159. "k98_scoped", //WEAPON_K98_SCOPED,
  160. //SMG
  161. "thompson", //WEAPON_THOMPSON,
  162. "mp40", //WEAPON_MP40,
  163. "mp44", //WEAPON_MP44,
  164. "bar", //WEAPON_BAR,
  165. //Machine guns
  166. "30cal", //WEAPON_30CAL,
  167. "mg42", //WEAPON_MG42,
  168. //Rocket weapons
  169. "bazooka", //WEAPON_BAZOOKA,
  170. "pschreck", //WEAPON_PSCHRECK,
  171. //Grenades
  172. "frag_us", //WEAPON_FRAG_US,
  173. "frag_ger", //WEAPON_FRAG_GER,
  174. "frag_us_live", //WEAPON_FRAG_US_LIVE
  175. "frag_ger_live", //WEAPON_FRAG_GER_LIVE
  176. "smoke_us", //WEAPON_SMOKE_US
  177. "smoke_ger", //WEAPON_SMOKE_GER
  178. "riflegren_us", //WEAPON_RIFLEGREN_US
  179. "riflegren_ger", //WEAPON_RIFLEGREN_GER
  180. "riflegren_us_live", //WEAPON_RIFLEGREN_US_LIVE
  181. "riflegren_ger_live", //WEAPON_RIFLEGREN_GER_LIVE
  182. // not actually separate weapons, but defines used in stats recording
  183. "thompson_punch", //WEAPON_THOMPSON_PUNCH
  184. "mp40_punch", //WEAPON_MP40_PUNCH
  185. "garand_zoomed", //WEAPON_GARAND_ZOOMED,
  186. "k98_zoomed", //WEAPON_K98_ZOOMED
  187. "spring_zoomed", //WEAPON_SPRING_ZOOMED
  188. "k98_scoped_zoomed", //WEAPON_K98_SCOPED_ZOOMED
  189. "30cal_undeployed", //WEAPON_30CAL_UNDEPLOYED,
  190. "mg42_undeployed", //WEAPON_MG42_UNDEPLOYED,
  191. "bar_semiauto", //WEAPON_BAR_SEMIAUTO,
  192. "mp44_semiauto", //WEAPON_MP44_SEMIAUTO,
  193. 0, // end of list marker
  194. };
  195. void ParseFile( const char *fileName )
  196. {
  197. FileHandle_t file = g_pFullFileSystem->Open( fileName, "rb" );
  198. if ( !file )
  199. {
  200. return;
  201. }
  202. dod_gamestats_t stats;
  203. g_pFullFileSystem->Read( &stats, sizeof( dod_gamestats_t ), file );
  204. if ( stats.header.iVersion != DOD_STATS_BLOB_VERSION || Q_stricmp( stats.header.szGameName, "dod" ) )
  205. {
  206. printf( "Error parsing file, bad header info: %s\n", fileName );
  207. return;
  208. }
  209. StartMYSQLInsert();
  210. AddField( "map", stats.header.szMapName );
  211. const time_t mapfiletime = g_pFullFileSystem->GetFileTime( fileName );
  212. struct tm *t = localtime( &mapfiletime );
  213. // YYYY-MM-DD HH:MM::SS
  214. char filetimebuf[64];
  215. Q_snprintf( filetimebuf, sizeof(filetimebuf), "%04d-%02d-%02d %02d:%02d:%02d",
  216. t->tm_year + 1900,
  217. t->tm_mon + 1,
  218. t->tm_mday,
  219. t->tm_hour,
  220. t->tm_min,
  221. t->tm_sec );
  222. AddField( "time", filetimebuf );
  223. AddField( "version", stats.header.iVersion );
  224. AddField( "ipaddr_0", stats.header.ipAddr[0] );
  225. AddField( "ipaddr_1", stats.header.ipAddr[1] );
  226. AddField( "ipaddr_2", stats.header.ipAddr[2] );
  227. AddField( "ipaddr_3", stats.header.ipAddr[3] );
  228. AddField( "port", stats.header.port );
  229. AddField( "minutes_map", stats.iMinutesPlayed );
  230. AddField( "wins_allies", stats.iNumAlliesWins );
  231. AddField( "wins_axis", stats.iNumAxisWins);
  232. AddField( "tickpoints_allies", stats.iAlliesTickPoints );
  233. AddField( "tickpoints_axis", stats.iAxisTickPoints );
  234. char buf[128];
  235. for ( int cls=0;cls<6;cls++ )
  236. {
  237. Q_snprintf( buf, sizeof(buf), "minutes_allies_%s", pszClassNames[cls] );
  238. AddField( buf, stats.iMinutesPlayedPerClass_Allies[cls] );
  239. Q_snprintf( buf, sizeof(buf), "kills_allies_%s", pszClassNames[cls] );
  240. AddField( buf, stats.iKillsPerClass_Allies[cls] );
  241. Q_snprintf( buf, sizeof(buf), "defenses_allies_%s", pszClassNames[cls] );
  242. AddField( buf, stats.iDefensesPerClass_Allies[cls] );
  243. Q_snprintf( buf, sizeof(buf), "caps_allies_%s", pszClassNames[cls] );
  244. AddField( buf, stats.iCapsPerClass_Allies[cls] );
  245. Q_snprintf( buf, sizeof(buf), "spawns_allies_%s", pszClassNames[cls] );
  246. AddField( buf, stats.iSpawnsPerClass_Allies[cls] );
  247. Q_snprintf( buf, sizeof(buf), "classlimit_allies_%s", pszClassNames[cls] );
  248. AddField( buf, stats.iClassLimits_Allies[cls] );
  249. Q_snprintf( buf, sizeof(buf), "minutes_axis_%s", pszClassNames[cls] );
  250. AddField( buf, stats.iMinutesPlayedPerClass_Axis[cls] );
  251. Q_snprintf( buf, sizeof(buf), "kills_axis_%s", pszClassNames[cls] );
  252. AddField( buf, stats.iKillsPerClass_Axis[cls] );
  253. Q_snprintf( buf, sizeof(buf), "defenses_axis_%s", pszClassNames[cls] );
  254. AddField( buf, stats.iDefensesPerClass_Axis[cls] );
  255. Q_snprintf( buf, sizeof(buf), "caps_axis_%s", pszClassNames[cls] );
  256. AddField( buf, stats.iCapsPerClass_Axis[cls] );
  257. Q_snprintf( buf, sizeof(buf), "spawns_axis_%s", pszClassNames[cls] );
  258. AddField( buf, stats.iSpawnsPerClass_Axis[cls] );
  259. Q_snprintf( buf, sizeof(buf), "classlimit_axis_%s", pszClassNames[cls] );
  260. AddField( buf, stats.iClassLimits_Axis[cls] );
  261. }
  262. int i;
  263. for ( i=0;i<DOD_NUM_DISTANCE_STAT_WEAPONS;i++ )
  264. {
  265. int iWeapon = iDistanceStatWeapons[i];
  266. const char *pszWeapon = s_WeaponAliasInfo[iWeapon];
  267. Q_snprintf( buf, sizeof(buf), "weapon_shots_%s", pszWeapon );
  268. AddField( buf, stats.weaponStatsDistance[i].iNumAttacks );
  269. Q_snprintf( buf, sizeof(buf), "weapon_hits_%s", pszWeapon );
  270. AddField( buf, stats.weaponStatsDistance[i].iNumHits );
  271. for ( int j=0;j<DOD_NUM_WEAPON_DISTANCE_BUCKETS;j++ )
  272. {
  273. Q_snprintf( buf, sizeof(buf), "weapon_distance_%s_%d", pszWeapon, j );
  274. AddField( buf, stats.weaponStatsDistance[i].iDistanceBuckets[j] );
  275. }
  276. }
  277. for ( i=0;i<DOD_NUM_NODIST_STAT_WEAPONS;i++ )
  278. {
  279. int iWeapon = iNoDistStatWeapons[i];
  280. const char *pszWeapon = s_WeaponAliasInfo[iWeapon];
  281. Q_snprintf( buf, sizeof(buf), "weapon_shots_%s", pszWeapon );
  282. AddField( buf, stats.weaponStats[i].iNumAttacks );
  283. Q_snprintf( buf, sizeof(buf), "weapon_hits_%s", pszWeapon );
  284. AddField( buf, stats.weaponStats[i].iNumHits );
  285. }
  286. CompleteMYSQLInsert();
  287. g_pFullFileSystem->Close( file );
  288. }
  289. int main( int argc, char **argv )
  290. {
  291. g_argv = argv;
  292. if( argc < 6 )
  293. {
  294. Usage();
  295. }
  296. if ( argc == 7 && !Q_stricmp( argv[6], "-verbose" ) )
  297. {
  298. g_bVerbose = true;
  299. }
  300. InitDefaultFileSystem();
  301. // Init MYSQL connection
  302. CSysModule *sql = Sys_LoadModule( "mysql_wrapper" );
  303. if ( sql )
  304. {
  305. CreateInterfaceFn factory = Sys_GetFactory( sql );
  306. if ( factory )
  307. {
  308. mysql = ( IMySQL * )factory( MYSQL_WRAPPER_VERSION_NAME, NULL );
  309. if ( mysql )
  310. {
  311. if ( mysql->InitMySQL( argv[ 2 ], argv[ 1 ], argv[ 3 ], argv[ 4 ] ) )
  312. {
  313. // insert rows
  314. const char *dir = argv[6];
  315. char searchString[MAX_PATH*2];
  316. Q_strncpy( searchString, dir, sizeof( searchString ) );
  317. Q_AppendSlash( searchString, sizeof( searchString ) );
  318. Q_strncat( searchString, "*.dat", sizeof( searchString ), COPY_ALL_CHARACTERS );
  319. int iNumFiles = 0;
  320. FileFindHandle_t findHandle = NULL;
  321. const char *filename = g_pFullFileSystem->FindFirst( searchString, &findHandle );
  322. while ( filename )
  323. {
  324. char fullFileName[MAX_PATH*2];
  325. Q_strncpy( fullFileName, dir, sizeof( fullFileName ) );
  326. Q_AppendSlash( fullFileName, sizeof( fullFileName ) );
  327. Q_strncat( fullFileName, filename, sizeof( fullFileName ), COPY_ALL_CHARACTERS );
  328. ParseFile( fullFileName );
  329. printf( "processing file: %s\n", fullFileName );
  330. iNumFiles++;
  331. filename = g_pFullFileSystem->FindNext(findHandle);
  332. }
  333. g_pFullFileSystem->FindClose(findHandle);
  334. printf( "Completed: %d files processed from directory \"%s\"\n", iNumFiles, dir );
  335. }
  336. else
  337. {
  338. printf( "InitMySQL failed ( %s )\n", mysql->GetLastError() );
  339. }
  340. mysql->Release();
  341. }
  342. else
  343. {
  344. printf( "Unable to connect via mysql_wrapper\n");
  345. }
  346. }
  347. else
  348. {
  349. printf( "Unable to get factory from mysql_wrapper.dll, not updating access mysql table!!!" );
  350. }
  351. Sys_UnloadModule( sql );
  352. }
  353. else
  354. {
  355. printf( "Unable to load mysql_wrapper.dll, not updating access mysql table!!!" );
  356. }
  357. return 0;
  358. }