Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
1053 lines
27 KiB
C++
1053 lines
27 KiB
C++
// 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 <windows.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#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 <GameOS/Network.hpp>
|
|
#include <Buildnum/buildnum.h>
|
|
|
|
#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; i<buf_len; i++) {
|
|
sprintf(tmp2, "%02x", buf[i]);
|
|
strcat(tmp, tmp2);
|
|
}
|
|
|
|
return(tmp);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// void MW4log_generic(char *str):
|
|
// ------------------------------------------------
|
|
// Dummy log entry -- REMOVE ME!
|
|
//
|
|
void MW4log_generic(int entry_type, char *str)
|
|
{
|
|
char msg[4096];
|
|
|
|
|
|
if(!MWApplication::GetInstance() || !MWApplication::GetInstance()->serverFlag || !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; i<log_bufcnt; i++) {
|
|
nglog->fn->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; i<Maximum_Players; i++) {
|
|
if(!app->servedConnectionData[i].clientConnected ||
|
|
!app->servedConnectionData[i].clientPlayer ||
|
|
!app->servedConnectionData[i].clientPlayer->vehicle) {
|
|
continue;
|
|
}
|
|
|
|
MW4log_writePlayerStats(i, 0);
|
|
}
|
|
|
|
// Log lancemate (bot) stats
|
|
for(i=0; i<Maximum_Lancemates; i++) {
|
|
if(!app->lancemateConnectionData[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<CBucket*> 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<CBucket*>::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; i<Maximum_Players; i++) {
|
|
if(!app->servedConnectionData[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; i<Maximum_Lancemates; i++) {
|
|
if(!app->lancemateConnectionData[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; i<ServedConnectionData::NumWeaponsTracked; i++) {
|
|
if(app->servedConnectionData[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; i<Maximum_Players+Maximum_Lancemates; i++) {
|
|
if(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]) {
|
|
|
|
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; i<ServedConnectionData::NumWeaponsTracked; i++) {
|
|
if(app->lancemateConnectionData[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; i<Maximum_Players+Maximum_Lancemates; i++) {
|
|
if(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]) {
|
|
|
|
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)
|