// log_test.c: Interface between MW4 Game-App and zStats logging library. // ---------------------------------------------------------------------- // J. Keimig // jkeimig@netgamesusa.com // 05 Jan 00 // Sample // 09 Oct 00 // Near ZBR for MW4 // #include #include #include #include "MW4Headers.hpp" #include "MW4Shell.hpp" #include "MWApplication.hpp" #include "MWMission.hpp" #include "MWPlayer.hpp" #include "mwmission.hpp" #include "bucket.hpp" #if !defined(NO_MR) #include "nglog.hpp" #include "nglog_mw4.hpp" #endif // !defined(NO_MR) #include "GameTypes.h" #include #include #if !defined(NO_LOG) // mdm - this is the key name for the NGWS status property const char NGWS_STATUS_KEY[] = "ngWS"; #define VA_BUFF 4 #define BUF_MAX 50 #define UPDATE_INTERVAL 12.0 // Minimum time interval between score updates. typedef int (*PFNGetngLogAPI)(nglog_import_t *, nglog_export_t *); char ngWS_status[32]; // External ngWS status (example for external public server info) nglog_library_t *nglog = NULL; // ngLog library object PROCESS_INFORMATION pi = {0}; // Single process info var to track ngWS status // Example of server configuration variables that can // be adjusted by the server operator. int z_style; int z_flush; int z_buffer; int z_id; int zS_exec; int zWS_enable; // Server setting if ngWS is to be enabled. char z_path[1024]; char z_logname[1024]; char zS_cfg[1024]; char zS_logdir[1024]; // Private local int game_started = 0; // For ordering... guarantees an entry will be placed first int game_finished = 0; // For filtering different end-game states int log_bufcnt = 0; // Number of buffered entries. char log_buf[BUF_MAX][1024]; // Buffering for ordering. double score_update = 0.0; // Periodic score updates. int va_index = 0; // Current va_buf pointer char va_buf[VA_BUFF][16384];// Handle nested calls for va // Watermark info #define H_OFFSET 7 #define H_LEN 10*3+8 unsigned char h_refs[] = { 251, 204, 207, 204, 219, 204, 199, /**/ 201, 192, 242, 244, 231, 135, 240, 151, 213, 203, 227, 244, 144, 231, 144, 146, 231, 202, 150, 228, 129, 151, 146, 151, 148, 144, 137, 196, 151, 245, 247, 232, 213, 231, 211, 206, 151, 233, /**/ 152, 155, 155, 155, 154, 6, 7, 199, 5, 251, 97, 0, 101, 41, 97, 0, 42, 41, 99, 7, 202, 181, 32, 73, 255, 199, 206, 254, 250, 137, 218, 204, 202, 219, 204, 221, 137, 218, 221, 219, 192, 199, 206, 152, 152, 243, 134, 28, 6, 111, 222, 198, 8, 54, 134 }; // // void MW4log_setStatusString( const char * status ): // --------------------------------------------------- // Set the ngWS status string. This is the value for the // ngWorldStats property that GUN/GameSpy will display. // void MW4log_setStatusString( const char * status ) { gosASSERT( strlen(status) < 32 ); strncpy(ngWS_status, status, 32); // this advertises the property to any Game List servers that are available. gos_NetSetAdvertItem( 0, NGWS_STATUS_KEY, status ); } // // void MW4log_init(void): // ----------------------- // Start up the logging interface, if needed. // void MW4log_init(void) { if(!MWApplication::GetInstance() || !MWApplication::GetInstance()->serverFlag || !MWApplication::GetInstance()->networkingFlag) { return; } if(nglog && z_style != STYLE_NGSTATS) { z_style = STYLE_APPEND; } // Load the logging library if(!nglog && !MW4log_load_zLogLib("ZlogLib.dll")) { // printf("Error loading ngLog library\n"); return; } log_bufcnt = 0; // Specify logging options. // MW4log_options_init(); // Start the log MW4log_start_logging(); return; } // // void MW4log_options_init(void): // ------------------------------- // Sets default "server" logging parameters. // void MW4log_options_init(void) { // External tweak variables (i.e. through server config) z_style = STYLE_NONE; z_flush = FLUSH_NOW; z_buffer = 10; z_id = 27910; zS_exec = 0; zWS_enable = 1; strcpy(z_path, "Stats"); strcpy(z_logname, "MW4_zlog.log"); strcpy(zS_cfg, "zStatsMW4.cfg"); strcpy(zS_logdir, "logs"); // Set external info based on initial settings if(zWS_enable) { MW4log_setStatusString("ENABLED"); } else { MW4log_setStatusString("DISABLED"); } // printf("*INITIAL* ngWS status: %s\n", ngWS_status); return; } // // int MW4log_load_zLogLib(char *libname): // ---------------------------------------- // Attempts to load and initialize logging library. // int MW4log_load_zLogLib(char *libname) { int i, len; char *tmp; char libpath[MAX_PATH*2], buf[MAX_PATH*3]; nglog_import_t imp; PFNGetngLogAPI GetngLogAPI = NULL; HANDLE ngloglibhandle = NULL; len = GetCurrentDirectory(MAX_PATH, libpath); tmp = libpath; while(*tmp) { *tmp ++= (char)tolower((int)*tmp); } sprintf(buf, "%s%s%s", libpath, MW4_BINARY_PATH, libname); // Try to load from the hardcoded path. If no-go, then try the local directory. ngloglibhandle = LoadLibrary(buf); if(!ngloglibhandle) { strcpy(libpath, _pgmptr); tmp = libpath; while(*tmp) { *tmp++ = (char)tolower((int)*tmp); } i = strlen(libpath)-1; while(libpath[i] != '\\') { i--; } libpath[i] = 0; sprintf(buf, "%s\\%s", libpath, libname); ngloglibhandle = LoadLibrary(buf); if(!ngloglibhandle) { printf("LibError: Couldn't load \"%s\"\n", libname); return(0); } } GetngLogAPI = (PFNGetngLogAPI) GetProcAddress((struct HINSTANCE__ *)ngloglibhandle, "GetngLogAPI"); if(GetngLogAPI == NULL) { FreeLibrary((struct HINSTANCE__ *)ngloglibhandle); // printf("LibError: Couldn't find GetngLogAPI in \"%s\"\n", libname); return(0); } else { nglog = (nglog_library_t *) calloc(1, sizeof(nglog_library_t)); nglog->fn = (nglog_export_t *) calloc(1, sizeof(nglog_export_t)); strncpy(nglog->path, libname, sizeof(nglog->path) - 1); nglog->path[MAX_PATH - 1] = 0; nglog->handle = ngloglibhandle; imp.MsgDump = MW4log_msgDump; imp.TimeDump = MW4log_timeDump; // Set all the dynamic bindings if(!(GetngLogAPI)(&imp, nglog->fn)) { // printf("LibError: Error in getting API\n"); return(0); } // printf("%s *INITIALIZED*\n", nglog->fn->LibVersion()); } return(1); } // // void MW4log_unload_zLogLib(void): // ---------------------------------- // Unloads and frees resources due to logging. // void MW4log_unload_zLogLib(void) { if(!nglog) { return; } FreeLibrary((struct HINSTANCE__ *)nglog->handle); free(nglog->fn); free(nglog); nglog = NULL; return; } // // void MW4log_start_logging(void): // -------------------------------- // Gets logging started with proper headers and logfile formats. // void MW4log_start_logging(void) { int i; const char *hostname, *gametype; char *mapname; char *info[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // 23 info lines + 1 terminator nglog_base base_info; if(!MWApplication::GetInstance()) { return; } NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams(); // Sanity check if(!params) { STOP(("MissionParams == NULL")); } // Initialize the log base_info.style = z_style; base_info.flush = z_flush; base_info.buffer = z_buffer; // base_info.worldstats = 1; // Hard-coded for beta zWS_enable = params->m_reportStats; base_info.worldstats = zWS_enable; base_info.id = z_id; // "path" should be a full path definition strncpy(base_info.path, z_path, sizeof(base_info.path) - 1); base_info.path[sizeof(base_info.path) - 1] = 0; strncpy(base_info.logname, z_logname, sizeof(base_info.logname) - 1); base_info.logname[sizeof(base_info.logname) - 1] = 0; // ngStats setup info base_info.ngS_exec = 0; // Call ngStats after every log close strncpy(base_info.ngS_cfg, zS_cfg, sizeof(base_info.ngS_cfg) - 1); base_info.ngS_cfg[sizeof(base_info.ngS_cfg) - 1] = 0; strncpy(base_info.ngS_logdir, zS_logdir, sizeof(base_info.ngS_logdir) - 1); base_info.ngS_logdir[sizeof(base_info.ngS_logdir) - 1] = 0; // ngStats and ngWorldStats name identification strcpy(base_info.ngS_name, "MechWarrior4"); strcpy(base_info.ngWS_name, "MW4"); // Hash input base_info.h_start = H_OFFSET; base_info.h_len = H_LEN; base_info.h_refs = h_refs; // Initialize required base header fields base_info.game_author = GAME_AUTHOR; base_info.game_name = GAME_NAME; base_info.game_url = GAME_AUTHOR_URL; base_info.game_version = VERSION; // base_info.game_version = GAME_VERSION; if(Network::GetInstance()) { hostname = Network::GetInstance()->GetGameName(); } else { hostname = NULL; } if(MWApplication::GetInstance()) { mapname = (char *) MWApplication::GetInstance()->m_currentMissionName; } else { mapname = NULL; } if(MW4Shell::Instance) { gametype = MW4Shell::Instance->GetRuleName(params->m_ruleType); } else { gametype = NULL; } // Custom info for log header // MSL 5.05 Add Option info[0] = strdup(va("server_address\t%s", MW4log_hostAddr())); info[1] = strdup(va("server_port\t%d", 1234567)); info[2] = strdup(va("timelimit\t%d", params->m_gameLength)); info[3] = strdup(va("fraglimit\t%d", params->m_killLimit)); info[4] = strdup(va("fraglimitNumber\t%d", params->m_killLimitNumber)); info[5] = strdup(va("respawnlimit\t%d", params->m_respawnLimit)); info[6] = strdup(va("respawnlimitNumber\t%d", params->m_respawnLimitNumber)); info[7] = strdup(va("splashdamage\t%d", params->m_splashOn)); info[8] = strdup(va("weaponjam\t%d", params->m_weaponjamOn)); info[9] = strdup(va("ammobayfire\t%d", params->m_ammobayfireOn)); // MSL 5.05 Advance Mode info[10] = strdup(va("advancemode\t%d", params->m_advancemodeOn)); // MSL 5.05 Armor Mode info[11] = strdup(va("armormode\t%d", params->m_armormodeOn)); info[12] = strdup(va("splashdamagePercentage\t%d", params->m_splashPercentage)); info[13] = strdup(va("unlimitedammo\t%d", params->m_unlimitedAmmo)); info[14] = strdup(va("mechheat\t%d", params->m_heatOn)); info[15] = strdup(va("autoaim\t%d", params->m_allowAutoAim)); info[16] = strdup(va("stockmechs\t%d", params->m_onlyStockMech)); info[17] = strdup(va("invulnerabledrop\t%d", params->m_invulnerableDrop)); info[18] = strdup(va("forcerespawn\t%d", params->m_forceRespawn)); info[19] = strdup(va("radarmode\t%d", params->m_radarMode)); info[20] = strdup(va("maxclients\t%d", params->m_maxPlayers)); info[21] = strdup(va("hostname\t%s", ((hostname) ? hostname : "UNKNOWN_HOST"))); info[22] = strdup(va("cpu\t%s", params->m_serverCPU)); info[23] = strdup(va("map\t%d\t%s", params->m_mapID, ((mapname) ? mapname : "UNKNOWN_MAP"))); info[24] = strdup(va("gametype\t%s", ((gametype) ? gametype : "UNKNOWN_GAMETYPE"))); info[25] = 0; // Make sure final string is null // We're all set, start up the log strncpy(z_logname, nglog->fn->logStart(&base_info, info), sizeof(z_logname) - 1); z_logname[sizeof(z_logname) - 1] = 0; // Clear out strdup allocations // MSL 5.05 Add Option for(i=0; i<25; i++) { if(info[i]) { free(info[i]); } } return; } // // void MW4log_ngWS_update(void): // ------------------------------ // Updates current ngWS status capability. // void MW4log_ngWS_update(void) { int stat; // ngWS was never invoked from the beginning if(pi.dwThreadId == -1111) { // printf("No exit_code, error during ngWS init\n"); MW4log_setStatusString("INACTIVE"); // ngWS logging *is* enabled.. check exit codes. } else { stat = nglog->fn->statusNGWS(&pi); switch(stat) { case EXIT_PROCERR: MW4log_setStatusString("INACTIVE"); break; case EXIT_NGWSERR: MW4log_setStatusString("INACTIVE"); break; case EXIT_RUNNING: break; // Maintain current state. case EXIT_OKAY: MW4log_setStatusString("ENABLED"); break; default: MW4log_setStatusString("ENABLED"); break; } } return; } // // void MW4log_msgDump(int msg_type, char *format, ...): // ----------------------------------------------------- // Handles messages passed from the ngLogLibrary // void MW4log_msgDump(int msg_type, char *format, ...) { char buf[4096]; va_list argptr; va_start(argptr, format); vsprintf(buf, format, argptr); va_end(argptr); // Print "info" to stdout. if(msg_type == MSG_INFO) { // nglog->fn->gameString((float)gos_GetElapsedTime(), va("(%s) INFO: %s", nglog->path, buf)); // fprintf(stdout, "(%s) INFO: %s", nglog->path, buf); // fflush(stdout); } else { // MSG_ERROR, MSG_CRITICAL // Print "errors" to stderr. // nglog->fn->gameString((float)gos_GetElapsedTime(), va("** (%s) ERROR: %s", nglog->path, buf)); // fprintf(stderr, "** (%s) ERROR: %s", nglog->path, buf); // fflush(stderr); } return; } // // char *MW4log_timeDump(void): // --------------------------- // Returns current gametime for MW4. // char *MW4log_timeDump(void) { MWMission *mission = (MWMission*)MWMission::GetInstance(); if(!mission) { return("0.0000"); } else { return(va("%.4f", mission->GetMissionTime())); } } // // char *va(char *format, ...): // ------------------------------- // Does a varargs printf into a rotating static buffer. // char *va(char *format, ...) { char *tmp; va_list argptr; tmp = va_buf[va_index]; va_start(argptr, format); vsprintf(tmp, format, argptr); va_end(argptr); va_index = (va_index + 1) % VA_BUFF; return(tmp); } // // char *MW4log_hostAddr(void): // ---------------------------- // Returns string of the local host's FIRST IP address in dotted-decimal // notation. // char *MW4log_hostAddr(void) { struct hostent *hptr; static char temp[128], lname[256]; unsigned char *p; if(gethostname(lname, sizeof(lname))) { sprintf(temp, "ERROR: no name"); return(temp); } if((hptr = gethostbyname(lname)) == NULL) { sprintf(temp, "ERROR: can't convert name\n"); return(temp); } p = (unsigned char *) hptr->h_addr_list[0]; sprintf(temp, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); return(temp); } // // void ngLog_playerIdentifier(unsigned char *name, char *passwd, int buf_len): // ---------------------------------------------------------------------------- // Spits back the player's unique MD5 identifier. // char *MW4log_playerIdentifier(unsigned char *buf, int buf_len) { int i; static char tmp[64], tmp2[64]; tmp[0] = 0; for(i=0; iserverFlag || !MWApplication::GetInstance()->networkingFlag) { return; } if(!nglog) { // Save contents of va, for safety strncpy(msg, str, sizeof(msg)-1); msg[sizeof(msg) - 1] = 0; MW4log_init(); if(!nglog) { return; } str = msg; } // nglog->fn->gameString((float)gos_GetElapsedTime(), va("rcvd:\t%s", str)); // Take care of ordering if(!game_started) { if(entry_type == MW4GAME_START) { nglog->fn->gameString(str); MW4log_writeBuf(); game_started = 1; game_finished = 0; score_update = UPDATE_INTERVAL; return; } else { if(log_bufcnt < BUF_MAX) { strncpy(log_buf[log_bufcnt], str, sizeof(log_buf[log_bufcnt]) - 1); log_buf[log_bufcnt][sizeof(log_buf[log_bufcnt]) - 1] = 0; log_bufcnt++; } return; } } // Now, make entries nglog->fn->gameString(str); return; } // // void MW4log_writeBuf(void): // --------------------------- // Drains buffered entries. // void MW4log_writeBuf(void) { int i; for(i=0; ifn->gameString(log_buf[i]); } log_bufcnt = 0; return; } // // void MW4log_gameEnd(int entry_type, char *str): // ----------------------------------------------- // GAME OVER MAN!!! // void MW4log_GameEnd(int entry_type, char *str) { static int zWS_called = 0; if(!MWApplication::GetInstance() || !MWApplication::GetInstance()->serverFlag || !MWApplication::GetInstance()->networkingFlag) { return; } if(!nglog || game_finished) { return; } // Drain any queued entries (shouldn't happen?) MW4log_writeBuf(); // Update zWS setting, if necessary. if(zWS_enable && zWS_called) { MW4log_ngWS_update(); } nglog->fn->gameEnd(str, &pi); game_started = 0; game_finished = 1; if(zWS_enable) { zWS_called = 1; } free(nglog->fn); nglog->fn = NULL; free(nglog); nglog = NULL; return; } // // void MW4log_playerConnect(char *str, int p_id): // ----------------------------------------------- // Player connect. // void MW4log_playerConnect(int p_id, char *p_name, char *p_info, float p_tonnage, unsigned char *buf, int buf_len) { char msg[1024]; if(!MWApplication::GetInstance() || !MWApplication::GetInstance()->serverFlag || !MWApplication::GetInstance()->networkingFlag) { return; } if(!nglog) { // Save contents of va, for safety strcpy(msg, p_info); MW4log_init(); if(!nglog) { return; } p_info = msg; } nglog->fn->plConnect(p_id, va("%s\t%s\t%.2f", p_name, p_info, p_tonnage), buf, buf_len); return; } // // void MW4log_writeAllStats(void): // -------------------------------- // Dumps all player stats. // void MW4log_writeAllStats(void) { int i; MWApplication *app = MWApplication::GetInstance(); if(!app) { return; } // Log player stats for(i=1; iservedConnectionData[i].clientConnected || !app->servedConnectionData[i].clientPlayer || !app->servedConnectionData[i].clientPlayer->vehicle) { continue; } MW4log_writePlayerStats(i, 0); } // Log lancemate (bot) stats for(i=0; ilancemateConnectionData[i].lancemateMech || !app->lancemateConnectionData[i].lancemateConnected) { continue; } MW4log_writeBotStats(i, 0); } // Log team scores /* if(MWApplication::GetInstance()->GetLocalNetParams()->m_teamAllowed) { MWMission *mission = Cast_Object(MWMission*, Mission::GetInstance()); stlport::vector team_buckets; if(!mission || !mission->m_BucketManager) { return; } for(int j=0; j<8; j++) { mission->m_BucketManager->FillTeamBuckets(i,team_buckets); for(stlport::vector::iterator k=team_buckets.begin(); k!=team_buckets.end(); k++) { if((*k)->Tracked() == true) { MW4log_generic(MW4P_DSTATS, va("Team_Score\t%d\t%d", i, (*k)->Value())); } } team_buckets.clear(); } } */ return; } // // void MW4log_checkCurrentStats(void): // ------------------------------------ // Logs players' updated stats, if needed. // void MW4log_checkCurrentStats(void) { int i; MWApplication *app = MWApplication::GetInstance(); MWMission *mission = (MWMission*)MWMission::GetInstance(); if(mission && app && app->GetLocalNetParams()) { int gt = app->GetLocalNetParams()->m_ruleType; if((gt != StockAttrition && gt != StockTeamAttrition) || !mission || !mission->GetMissionTime() || mission->GetMissionTime() <= score_update) { return; } score_update = mission->GetMissionTime() + UPDATE_INTERVAL; // Log player stats for(i=1; iservedConnectionData[i].clientConnected || !app->servedConnectionData[i].clientPlayer || !app->servedConnectionData[i].clientPlayer->vehicle || !app->servedConnectionData[i].stats_update) { continue; } MW4log_writePlayerStats(i, 1); app->servedConnectionData[i].stats_update = 0; } // Log lancemate (bot) stats for(i=0; ilancemateConnectionData[i].lancemateMech || !app->lancemateConnectionData[i].lancemateConnected || !app->lancemateConnectionData[i].stats_update) { continue; } MW4log_writeBotStats(i, 1); app->lancemateConnectionData[i].stats_update = 0; } } return; } // // void MW4log_writePlayerStats(int p_id, int stat_summary): // --------------------------------------------------------- // Dumps stats for a single player. // void MW4log_writePlayerStats(int p_id, int stat_summary) { int i, c_gvn, c_rcv; double d_gvn, d_rcv; char tmp[256], d_stats[30000]; MWApplication *app = MWApplication::GetInstance(); MWMission *mission; Check_Object (MWMission::GetInstance()); mission = Cast_Object (MWMission *,MWMission::GetInstance()); // Psycho-analysis is required if(!app || !mission) { return; } d_gvn = 0.0; d_rcv = 0.0; c_gvn = 0; c_rcv = 0; // Per-weapon summary d_stats[0] = 0; for(i=FirstWeaponID; iservedConnectionData[p_id].dmg_given[i] || app->servedConnectionData[p_id].dmg_rcvd[i] || app->servedConnectionData[p_id].wep_atts[i] || app->servedConnectionData[p_id].wep_hits[i]) { if(d_stats[0]) { strcat(d_stats, "\t"); } sprintf(tmp, "%d:%d:%d:%.2f:%.2f", i, app->servedConnectionData[p_id].wep_hits[i], app->servedConnectionData[p_id].wep_atts[i], app->servedConnectionData[p_id].dmg_given[i], app->servedConnectionData[p_id].dmg_rcvd[i]); if((strlen(tmp) + strlen(d_stats)) < (sizeof(d_stats) - 2)) { strcat(d_stats, tmp); } else { break; } } } d_stats[sizeof(d_stats) - 1] = 0; if(!stat_summary) { if(d_stats[0]) { MW4log_generic(MW4P_DSTATS, va("PW\t%d\t%s", p_id, d_stats)); } else { MW4log_generic(MW4P_DSTATS, va("PW\t%d\tNONE", p_id)); } } // Per-player interaction summary d_stats[0] = 0; for(i=0; iservedConnectionData[p_id].pdmg_given[i] || app->servedConnectionData[p_id].pdmg_rcvd[i] || app->servedConnectionData[p_id].comp_inf[i] || app->servedConnectionData[p_id].comp_rcv[i]) { if(d_stats[0]) { strcat(d_stats, "\t"); } sprintf(tmp, "%d:%.2f:%.2f:%d:%d", i, app->servedConnectionData[p_id].pdmg_given[i], app->servedConnectionData[p_id].pdmg_rcvd[i], app->servedConnectionData[p_id].comp_inf[i], app->servedConnectionData[p_id].comp_rcv[i]); d_gvn += app->servedConnectionData[p_id].pdmg_given[i]; d_rcv += app->servedConnectionData[p_id].pdmg_rcvd[i]; c_gvn += app->servedConnectionData[p_id].comp_inf[i]; c_rcv += app->servedConnectionData[p_id].comp_rcv[i]; if((strlen(tmp) + strlen(d_stats)) < (sizeof(d_stats) - 2)) { strcat(d_stats, tmp); } else { break; } } } d_stats[sizeof(d_stats) - 1] = 0; if(d_stats[0]) { MW4log_generic(MW4P_DSTATS, va("PD\t%d\t%s", p_id, d_stats)); } else { MW4log_generic(MW4P_DSTATS, va("PD\t%d\tNONE", p_id)); } if(stat_summary) { MW4log_generic(MW4P_DSTATS, va("PSS\t%d\t%.2f:%.2f:%d:%d", p_id, d_gvn, d_rcv, c_gvn, c_rcv)); } if (app->servedConnectionData[p_id].clientPlayer && app->servedConnectionData[p_id].clientPlayer->vehicle) { ReplicatorID rid = app->servedConnectionData[p_id].clientPlayer->vehicle->GetReplicatorID(); MW4log_generic(MW4P_DSTATS, va("PS\t%d\t%d\t%d\t%d\t%d", p_id, mission->m_BucketManager->GetCustomBucketValue(rid), app->servedConnectionData[i].effectivePing, 0.0f, app->servedConnectionData[i].packetLoss)); } return; } // // void MW4log_writeBotStats(int p_id, int stat_summary): // ------------------------------------------------------ // Dumps stats for a single bot. // void MW4log_writeBotStats(int p_id, int stat_summary) { int i, pid; double d_gvn, d_rcv; int c_gvn, c_rcv; char tmp[256], d_stats[30000]; MWMission *mission; Check_Object (MWMission::GetInstance()); mission = Cast_Object (MWMission *,MWMission::GetInstance()); d_gvn = 0.0; d_rcv = 0.0; c_gvn = 0; c_rcv = 0; MWApplication *app = MWApplication::GetInstance(); pid = p_id+Maximum_Players; // Per-weapon summary d_stats[0] = 0; for(i=FirstWeaponID; ilancemateConnectionData[p_id].dmg_given[i] || app->lancemateConnectionData[p_id].dmg_rcvd[i] || app->lancemateConnectionData[p_id].wep_atts[i] || app->lancemateConnectionData[p_id].wep_hits[i]) { if(d_stats[0]) { strcat(d_stats, "\t"); } sprintf(tmp, "%d:%d:%d:%.2f:%.2f", i, app->lancemateConnectionData[p_id].wep_hits[i], app->lancemateConnectionData[p_id].wep_atts[i], app->lancemateConnectionData[p_id].dmg_given[i], app->lancemateConnectionData[p_id].dmg_rcvd[i]); if((strlen(tmp) + strlen(d_stats)) < (sizeof(d_stats) - 2)) { strcat(d_stats, tmp); } else { break; } } } d_stats[sizeof(d_stats) - 1] = 0; if(!stat_summary) { if(d_stats[0]) { MW4log_generic(MW4P_DSTATS, va("PW\t%d\t%s", pid, d_stats)); } else { MW4log_generic(MW4P_DSTATS, va("PW\t%d\tNONE", pid)); } } // Per-player interaction summary d_stats[0] = 0; for(i=0; ilancemateConnectionData[p_id].pdmg_given[i] || app->lancemateConnectionData[p_id].pdmg_rcvd[i] || app->lancemateConnectionData[p_id].comp_inf[i] || app->lancemateConnectionData[p_id].comp_rcv[i]) { if(d_stats[0]) { strcat(d_stats, "\t"); } sprintf(tmp, "%d:%.2f:%.2f:%d:%d", i, app->lancemateConnectionData[p_id].pdmg_given[i], app->lancemateConnectionData[p_id].pdmg_rcvd[i], app->lancemateConnectionData[p_id].comp_inf[i], app->lancemateConnectionData[p_id].comp_rcv[i]); d_gvn += app->lancemateConnectionData[p_id].pdmg_given[i]; d_rcv += app->lancemateConnectionData[p_id].pdmg_rcvd[i]; c_gvn += app->lancemateConnectionData[p_id].comp_inf[i]; c_rcv += app->lancemateConnectionData[p_id].comp_rcv[i]; if((strlen(tmp) + strlen(d_stats)) < (sizeof(d_stats) - 2)) { strcat(d_stats, tmp); } else { break; } } } d_stats[sizeof(d_stats) - 1] = 0; if(d_stats[0]) { MW4log_generic(MW4P_DSTATS, va("PD\t%d\t%s", pid, d_stats)); } else { MW4log_generic(MW4P_DSTATS, va("PD\t%d\tNONE", pid)); } if(stat_summary) { MW4log_generic(MW4P_DSTATS, va("PSS\t%d\t%.2f:%.2f:%d:%d", pid, d_gvn, d_rcv, c_gvn, c_rcv)); } ReplicatorID rid = app->lancemateConnectionData[p_id].lancemateMech->GetReplicatorID(); MW4log_generic(MW4P_DSTATS, va("PS\t%d\t%d\t0\t0\t0", pid, mission->m_BucketManager->GetCustomBucketValue(rid))); return; } #endif // !defined(NO_LOG)